AWSTemplateFormatVersion: '2010-09-09'
Description: 'CloudFormation template to create an EC2 instance with Rclone installed'

Parameters:
  YourProductionS3Bucket:
    Type: String
    Description: Specify the name of your destination Amazon S3 Bucket
  LatestAmiId:
    Type: 'AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>'
    Default: '/aws/service/canonical/ubuntu/server/jammy/stable/current/arm64/hvm/ebs-gp2/ami-id'    
  InstanceType:
    Description: Select an instance type compatible with the Ubuntu based AMI Architecure and offered in the Region's Availability Zone. Refer to Blog instructions for more details.
    Type: String
    Default: m7g.medium
  KeyName:
    Description: Select an existing EC2 KeyPair to enable SSH access to the instance.
    Type: AWS::EC2::KeyPair::KeyName
  DropboxClientId:
    Description: Client ID for Rclone Dropbox remote configuration.
    Type: String
    NoEcho: true
  DropboxClientSecret:
    Description: Client Secret for Rclone Dropbox remote configuration.
    Type: String
    NoEcho: true
  SelfIP:
    Description: Your IP address for SSH access. Must be a valid IP CIDR range of the form x.x.x.x/x.
    Type: String
    Default: ''
  VpcId:
    Description: Select the VPC in which to create the EC2 instance.
    Type: AWS::EC2::VPC::Id
  SubnetId:
    Description: Select the Subnet in which to create the EC2 instance.
    Type: AWS::EC2::Subnet::Id
    

Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
      - Label:
          default: "EC2 Configuration"
        Parameters:
          - VpcId
          - SubnetId
          - InstanceType
          - LatestAmiId
          - KeyName
          - SelfIP
      - Label:
          default: "Rclone Dropbox Remote Configuration"
        Parameters:
          - DropboxClientId
          - DropboxClientSecret
      - Label:
          default: "Your Destination Amazon S3 Bucket"
        Parameters:
          - YourProductionS3Bucket
      
    ParameterLabels:
      InstanceType:
        default: "EC2 instance type"
      KeyName:
        default: "EC2 key pair"
      SelfIP:
        default: "Your IP Address"
      VpcId:
        default: "VPC"
      SubnetId:
        default: "Subnet"
      DropboxClientId:
        default: "Client ID"
      DropboxClientSecret:
        default: "Client Secret"

Conditions:
  HasSelfIP: !Not [!Equals [!Ref 'SelfIP', '']]

Resources:

  myInstanceProfile:
    Type: 'AWS::IAM::InstanceProfile'
    Properties:
      Path: /
      Roles:
        - !Ref myEC2Role


  myEC2Role:
    Type: 'AWS::IAM::Role'
    Properties:
      ManagedPolicyArns:
        - 'arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore'
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service: ec2.amazonaws.com
            Action: 'sts:AssumeRole'      
      Policies:    
        - PolicyName: AllowReadWritePolicy
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - "s3:ListBucket*"
                  - "s3:ListAllMyBuckets"
                  - "s3:DeleteObject"
                  - "s3:GetObject"
                  - "s3:PutObject"
                  - "s3:PutObjectAcl"                  
                Resource:
                  - !Sub arn:${AWS::Partition}:s3:::${YourProductionS3Bucket}/*      
                  - !Sub arn:${AWS::Partition}:s3:::${YourProductionS3Bucket}     
              - Effect: Allow
                Action:
                  - "s3:ListAllMyBuckets"              
                Resource:
                  - !Sub arn:${AWS::Partition}:s3:::*            

  AccessKeySecret:
    Type: AWS::SecretsManager::Secret
    Properties:
      Name: !Sub 'rclone-secrets-${AWS::StackName}'
      SecretString: !Sub '{"DropboxClientId":"${DropboxClientId}", "DropboxClientSecret":"${DropboxClientSecret}"}'



  EC2Instance:
    Type: AWS::EC2::Instance
    Properties:
      InstanceType: !Ref 'InstanceType'
      IamInstanceProfile: !Ref myInstanceProfile
      SecurityGroupIds: [!Ref 'InstanceSecurityGroup']
      KeyName: !Ref 'KeyName'
      ImageId: !Ref LatestAmiId
      SubnetId: !Ref 'SubnetId'
      Tags:
        - Key: Name
          Value: Rclone Instance - Dropbox to S3
      UserData:
        Fn::Base64: !Sub |
          #!/bin/bash
          sudo apt update
          sudo apt install -y rclone
          sleep 10

          mkdir -p /home/ubuntu/.config/rclone
          cat > /home/ubuntu/.config/rclone/rclone.conf <<EOF
          
          [s3-remote]
          type = s3
          provider = AWS
          env_auth = true
          region = ${AWS::Region}
          
          [dropbox-remote]
          type = dropbox
          client_id = ${DropboxClientId}
          client_secret = ${DropboxClientSecret}
          scope = dropbox

          EOF
          chown -R ubuntu:ubuntu /home/ubuntu/.config/rclone
          sleep 10

      BlockDeviceMappings:
        - DeviceName: /dev/sda1
          Ebs:
            VolumeType: gp3
            VolumeSize: 25

  InstanceSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Allow all traffic from self IP and AWS IP range
      VpcId: !Ref 'VpcId'
      SecurityGroupIngress:
        - !If
          - HasSelfIP
          - Description: Inbound Rule from Self IP
            IpProtocol: tcp
            FromPort: 22
            ToPort: 22
            CidrIp: !Ref 'SelfIP'
          - !Ref 'AWS::NoValue'
      SecurityGroupEgress:
        - Description: Allow all outbound traffic
          IpProtocol: -1
          FromPort: -1
          ToPort: -1
          CidrIp: '0.0.0.0/0'

Outputs:
  InstanceId:
    Description: InstanceId of the newly created EC2 instance
    Value: !Ref 'EC2Instance'
  PublicIPv4Address:
    Description: Public IPv4 address of the newly created EC2 instance
    Value: !GetAtt 'EC2Instance.PublicIp'
  AccessKeySecretArn:
    Description: ARN of the Secrets Manager secret containing the access key ID, secret access key, Dropbox Client ID, and Client Secret
    Value: !Ref 'AccessKeySecret'