AWSTemplateFormatVersion: "2010-09-09"
Description: RosettaInsight Mannual Stack (qs-1lzp3ja12)
Metadata: 
  AWS::CloudFormation::Interface: 
    ParameterGroups: 
      - 
        Label: 
          default: "Manual deployment parameters"
        Parameters: 
          - UserUid
          - ApiKey
    ParameterLabels:
      UserUid:
        default: "The RosettaHub User Uid"
      ApiKey:
        default: "The RosettaHub User Api Key"
        
Mappings:
  SetupVariables:
    Variables:
      RosettaHubAccountID: '072600145787'
  RegionMap:
    us-east-1:
      Bucket: com-rosettahub-public-code-region-us-east-1
    us-west-2:
      Bucket: com-rosettahub-public-code-region-us-west-2
    eu-west-1:
      Bucket: com-rosettahub-public-code
    ap-southeast-1:
      Bucket: com-rosettahub-public-code-region-ap-southeast-1
    
Parameters:
     UserUid:
      Description: The RosettaHub User Uid
      Type: String
     ApiKey:
      Description: The RosettaHub User Api Key
      Type: String 
      
      
Resources:
  RHKeysRole:
    Type: 'AWS::IAM::Role'
    Properties:
      RoleName: RHKeysRole
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Principal:
              AWS: 
              - Fn::Sub: 
                - 'arn:aws:iam::${RosettaHubAccountID}:root'
                - RosettaHubAccountID: !FindInMap [SetupVariables, Variables, RosettaHubAccountID]
            Action:
              - 'sts:AssumeRole'
      MaxSessionDuration: 43200  # Maximum session duration in seconds (12 hours)
      Path: /
      Policies:
        - PolicyName: 'RHKeysPolicy'
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: 'Allow'
                Action:
                  - 'ec2:AllocateAddress'
                  - 'ec2:AssignPrivateIpAddresses'
                  - 'ec2:ReleaseAddress'
                  - 'ec2:AssociateAddress'
                  - 'ec2:DisassociateAddress'
                  - 'ec2:DescribeAddresses'
                  - 'ec2:AssociateDhcpOptions'
                  - 'ec2:AssociateIamInstanceProfile'
                  - 'ec2:AssociateRouteTable'
                  - 'ec2:AttachInternetGateway'
                  - 'ec2:DescribeEgressOnlyInternetGateways'
                  - 'ec2:CreateEgressOnlyInternetGateway'
                  - 'ec2:DeleteEgressOnlyInternetGateway'
                  - 'ec2:AttachVolume'
                  - 'ec2:AuthorizeSecurityGroupEgress'
                  - 'ec2:AuthorizeSecurityGroupIngress'
                  - 'ec2:CancelSpotInstanceRequests'
                  - 'ec2:CreateDhcpOptions'
                  - 'ec2:CreateFleet'
                  - 'ec2:CreateInternetGateway'
                  - 'ec2:CreateLaunchTemplate'
                  - 'ec2:CreateLaunchTemplateVersion'
                  - 'ec2:CreateNatGateway'
                  - 'ec2:CreateRoute'
                  - 'ec2:CreateRouteTable'
                  - 'ec2:CreateSecurityGroup'
                  - 'ec2:CreateSubnet'
                  - 'ec2:CreateTags'
                  - 'ec2:CreateVolume'
                  - 'ec2:CreateVpc'
                  - 'ec2:CreateVpcEndpoint'
                  - 'ec2:CreateNetworkAcl'
                  - 'ec2:CreateVpcPeeringConnection'
                  - 'ec2:CreateNetworkInterface'
                  - 'ec2:DeleteDhcpOptions'
                  - 'ec2:DeleteFleets'
                  - 'ec2:DeleteInternetGateway'
                  - 'ec2:DeleteLaunchTemplate'
                  - 'ec2:DeleteLaunchTemplateVersions'
                  - 'ec2:DeleteNatGateway'
                  - 'ec2:DeleteNetworkAcl'
                  - 'ec2:DeleteRoute'
                  - 'ec2:DeleteRouteTable'
                  - 'ec2:DeleteSecurityGroup'
                  - 'ec2:DeleteSubnet'
                  - 'ec2:DeleteTags'
                  - 'ec2:DeleteVolume'
                  - 'ec2:DeleteVpc'
                  - 'ec2:DeleteVpcEndpoints'
                  - 'ec2:DeleteVpcPeeringConnection'
                  - 'ec2:DeleteNetworkInterface'
                  - 'ec2:DescribeNetworkAcls'
                  - 'ec2:DescribeAvailabilityZones'
                  - 'ec2:DescribeFleetHistory'
                  - 'ec2:DescribeFleetInstances'
                  - 'ec2:DescribeFleets'
                  - 'ec2:DescribeIamInstanceProfileAssociations'
                  - 'ec2:DescribeInstanceStatus'
                  - 'ec2:DescribeInstances'
                  - 'ec2:DescribeInternetGateways'
                  - 'ec2:DescribeLaunchTemplates'
                  - 'ec2:DescribeLaunchTemplateVersions'
                  - 'ec2:DescribeNatGateways'
                  - 'ec2:DescribePrefixLists'
                  - 'ec2:DescribeReservedInstancesOfferings'
                  - 'ec2:DescribeRouteTables'
                  - 'ec2:DescribeSecurityGroups'
                  - 'ec2:DescribeSpotInstanceRequests'
                  - 'ec2:DescribeSpotPriceHistory'
                  - 'ec2:DescribeSubnets'
                  - 'ec2:DescribeVolumes'
                  - 'ec2:DescribeVpcs'
                  - 'ec2:DetachInternetGateway'
                  - 'ec2:DisassociateIamInstanceProfile'
                  - 'ec2:DisassociateRouteTable'
                  - 'ec2:GetLaunchTemplateData'
                  - 'ec2:GetSpotPlacementScores'
                  - 'ec2:ModifyFleet'
                  - 'ec2:ModifyLaunchTemplate'
                  - 'ec2:ModifyVpcAttribute'
                  - 'ec2:ReplaceIamInstanceProfileAssociation'
                  - 'ec2:RequestSpotInstances'
                  - 'ec2:RevokeSecurityGroupEgress'
                  - 'ec2:RevokeSecurityGroupIngress'
                  - 'ec2:RunInstances'
                  - 'ec2:TerminateInstances'
                  - 'ec2:ImportKeyPair'
                  - 'ec2:DeleteKeyPair'
                  - 'ec2:DescribeKeyPairs'
                  - 'ec2:*Image'
                  - 'ec2:DescribeImages'
                  - 'ec2:*Snapshot'
                  - 'ec2:DescribeSnapshots'
                  - 'ec2:CreateSnapshots'
                  - 'ec2:StopInstances'
                  - 'ec2:StartInstances'
                  - 'ec2:RebootInstances'
                  - 'ec2:ModifySubnetAttribute'
                  - 'tag:TagResources'
                  - 'tag:UntagResources'
                Resource:
                  - '*'
              - Effect: 'Allow'
                Action:
                  - 'iam:CreateServiceLinkedRole'
                  - 'iam:PutRolePolicy'
                Resource: 'arn:aws:iam::*:role/aws-service-role/spot.amazonaws.com/AWSServiceRoleForEC2Spot'
                Condition:
                  StringLike:
                    'iam:AWSServiceName': 'spot.amazonaws.com'
              - Effect: 'Allow'
                Action:
                  - 'iam:PassRole'
                Resource: 'arn:aws:iam::*:role/RosettaHubSsmRole'
              - Effect: 'Allow'
                Action:
                  - 'iam:CreateRole'
                  - 'iam:TagRole'
                Resource: 'arn:aws:iam::*:role/RosettaHubSsmRole'

              # Permission to attach SSM policy (with condition)
              - Effect: 'Allow'
                Action: 'iam:AttachRolePolicy'
                Resource: 'arn:aws:iam::*:role/RosettaHubSsmRole'
                Condition:
                  ArnEquals:
                    'iam:PolicyArn': 'arn:aws:iam::aws:policy/service-role/AmazonEC2RoleforSSM'

              # Permissions for instance profile
              - Effect: 'Allow'
                Action:
                  - 'iam:CreateInstanceProfile'
                  - 'iam:AddRoleToInstanceProfile'
                  - 'iam:TagInstanceProfile'
                Resource:
                  - 'arn:aws:iam::*:instance-profile/RosettaHubSsmRole'
                  - 'arn:aws:iam::*:role/RosettaHubSsmRole'

              # Read permissions (required for validation)
              - Effect: 'Allow'
                Action:
                  - 'iam:GetRole'
                  - 'iam:GetPolicy'
                  - 'iam:GetInstanceProfile'
                Resource: '*'
  


      ManagedPolicyArns:
        - Fn::Sub:
          - 'arn:${Partition}:iam::aws:policy/AmazonS3FullAccess'
          - Partition: !Ref 'AWS::Partition'
        - Fn::Sub:
          - 'arn:${Partition}:iam::aws:policy/AmazonElasticFileSystemFullAccess'
          - Partition: !Ref 'AWS::Partition'
        - Fn::Sub:
          - 'arn:${Partition}:iam::aws:policy/AmazonEC2ContainerRegistryFullAccess'
          - Partition: !Ref 'AWS::Partition' 
        - Fn::Sub:
          - 'arn:${Partition}:iam::aws:policy/AmazonElasticContainerRegistryPublicFullAccess'
          - Partition: !Ref 'AWS::Partition'
        - Fn::Sub:
          - 'arn:${Partition}:iam::aws:policy/AWSKeyManagementServicePowerUser'
          - Partition: !Ref 'AWS::Partition' 
          
  MyLambdaFunction:
    Type: 'AWS::Lambda::Function'
    Properties:
      FunctionName: RHSetupFunction
      Handler: com.rosettahub.aws.lambda.RosettaHubKeysSetup
      Role: !GetAtt 'LambdaExecutionRole.Arn'
      Code:
        S3Bucket: !FindInMap [RegionMap, !Ref "AWS::Region", Bucket]
        S3Key: marketplace/2.0.0/RosettaFunctionAwsMarketplaceLambda.jar
      Runtime: java17
      Timeout: 120
      Environment:
        Variables:
          roleName: !Sub "${RHKeysRole}"
          lambdaBrokerUrl: "ssl://lambda-broker.rosettahub.com:61621"            
          JAVA_TOOL_OPTIONS: "-Djava.locale.providers=COMPAT,CLDR"
          secretNamePrefix: "marketplace-deployment!prod-fh5vq6jgietqy/rosettainsight"  
          RosettaHubAccountId : !FindInMap [SetupVariables, Variables, RosettaHubAccountID]
          UserUid: !Sub "${UserUid}"
          ApiKey: !Sub "${ApiKey}"
          JAVA_TOOL_OPTIONS: >-
            -Dorg.slf4j.simpleLogger.defaultLogLevel=info
            -Dorg.slf4j.simpleLogger.showDateTime=true
            -Dorg.slf4j.simpleLogger.dateTimeFormat="yyyy-MM-dd HH:mm:ss"
            -Dorg.slf4j.simpleLogger.showThreadName=true
            -Dorg.slf4j.simpleLogger.showLogName=true
            -Dorg.slf4j.simpleLogger.log.org.apache.activemq=error
            -Dorg.slf4j.simpleLogger.log.org.eclipse.jetty=error
            -Dorg.slf4j.simpleLogger.log.org.apache.cxf=error
            -Dorg.slf4j.simpleLogger.log.org.apache.spark=error
            -Dorg.slf4j.simpleLogger.log.org.sparkproject=error
          
    DependsOn: RHKeysRole
    
  LambdaExecutionRole:
    Type: 'AWS::IAM::Role'
    Properties:
      RoleName: RHSetupFunctionRole
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
        - Effect: Allow
          Principal:
            Service:
            - lambda.amazonaws.com
          Action:
          - 'sts:AssumeRole'
      Path: /
      Policies:
        - PolicyName: 'MyPolicy'
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: 'Allow'
                Action: 
                  - 'logs:CreateLogGroup'
                  - 'logs:CreateLogStream'
                  - 'logs:PutLogEvents'
                Resource: 
                  Fn::Sub:
                    - 'arn:${Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/RHSetupFunction:*'
                    - Partition: !Ref 'AWS::Partition'
              - Effect: 'Allow'
                Action:
                  - 'secretsmanager:ListSecrets'
                Resource: '*'
                
              - Effect: 'Allow'
                Action:
                  - 'iam:UpdateAssumeRolePolicy'
                Resource:
                  Fn::Sub:
                    - 'arn:${Partition}:iam::${AWS::AccountId}:role/${RHKeysRole}'
                    - Partition: !Ref 'AWS::Partition'

  InvokeLambda:
    Type: 'AWS::CloudFormation::CustomResource'
    DeletionPolicy : 'Retain'
    UpdateReplacePolicy: 'Retain'
    Properties:
      ServiceToken: !GetAtt 'MyLambdaFunction.Arn'
      
