CloudFormation Script

This page contains the CloudFormation template used to set up the cross-account IAM role, Lambda function, and S3 bucket policies required for connecting an e6data Serverless workspace.

Note: This template should be deployed as-is. Do not modify the YAML unless you are familiar with AWS CloudFormation and IAM policies.

CloudFormation YAML Template

AWSTemplateFormatVersion: '2010-09-09'
Description: CloudFormation template to create S3 buckets and a Lambda function to manage bucket policies.

Parameters:
  BucketNames:
    Type: CommaDelimitedList
    Description: List of S3 bucket names to create and manage policies.

  VPCEndpointId:
    Type: String
    Description: The ID of the VPC Endpoint.

  E6dataAccountId:
    Type: String
    Description: The e6data aws account.

  ExternalId:
    Type: String
    Description: The external ID for cross-account access.

Resources:
  CrossAccountRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName:  !Sub "e6data-cross-account-role-${AWS::StackName}-${AWS::Region}"
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              AWS: !Sub "arn:aws:iam::${E6dataAccountId}:root"
            Action: "sts:AssumeRole"
            Condition:
              StringEquals:
                sts:ExternalId: !Ref ExternalId
          - Effect: Allow
            Principal:
              AWS: !Sub "arn:aws:iam::${E6dataAccountId}:root"
            Action: "sts:TagSession"

  ChangeSetCrossAccountPolicy:
    Type: AWS::IAM::ManagedPolicy
    Properties:
      ManagedPolicyName: !Sub "e6data-change-set-cross-account-policy-${AWS::StackName}-${AWS::Region}"
      Roles:
        - !Ref CrossAccountRole
      PolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Action:
              - "cloudformation:CreateChangeSet"
              - "cloudformation:DescribeChangeSet"
              - "cloudformation:DescribeStacks"
            Resource: !Sub "arn:aws:cloudformation:${AWS::Region}:${AWS::AccountId}:stack/${AWS::StackName}/*"

  LambdaS3ManagedPolicy:
    Type: AWS::IAM::ManagedPolicy
    Properties:
      ManagedPolicyName: !Sub "e6data-LambdaS3Policy-${AWS::StackName}-${AWS::Region}"
      PolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Action:
              - ec2:DescribeVpcEndpoints
            Resource: "*"
          - Effect: Allow
            Action:
              - iam:CreatePolicy
              - iam:AttachRolePolicy
              - iam:DetachRolePolicy
              - iam:DeletePolicy
              - iam:ListPolicies
              - iam:ListAttachedRolePolicies
              - iam:GetPolicy
              - iam:GetPolicyVersion
              - iam:CreatePolicyVersion
              - iam:ListPolicyVersions
              - iam:DeletePolicyVersion
            Resource: "*"

  LambdaExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: lambda.amazonaws.com
            Action: sts:AssumeRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
        - arn:aws:iam::aws:policy/AmazonS3FullAccess
        - !Ref LambdaS3ManagedPolicy

  ManageBucketPoliciesLambda:
    Type: AWS::Lambda::Function
    Properties:
      Handler: index.lambda_handler
      Role: !GetAtt LambdaExecutionRole.Arn
      Code:
        ZipFile: |
          import json
          import boto3
          from botocore.exceptions import ClientError
          import cfnresponse
          
          # Lambda code here (full code omitted for brevity, use complete code in deployment)
      Runtime: python3.9
      Timeout: 300
      MemorySize: 128

  ManageBucketPoliciesCustomResource:
    Type: AWS::CloudFormation::CustomResource
    Properties:
      ServiceToken: !GetAtt ManageBucketPoliciesLambda.Arn
      BucketNames: !Ref BucketNames
      VPCEndpointId: !Ref VPCEndpointId
      CrossAccountRole: !Ref CrossAccountRole
      Unique: !Sub "${AWS::StackName}-${AWS::Region}-bucket"

  LambdaInvokePermission:
    Type: AWS::Lambda::Permission
    Properties:
      Action: lambda:InvokeFunction
      FunctionName: !GetAtt ManageBucketPoliciesLambda.Arn
      Principal: cloudformation.amazonaws.com

Outputs:
  RoleArn:
    Description: ARN of the created IAM role
    Value: !GetAtt CrossAccountRole.Arn

  FailedBuckets:
    Description: List of any buckets where policy application failed
    Value: !GetAtt ManageBucketPoliciesCustomResource.FailedBuckets

Notes

  • Parameters to update:

    • BucketNames: S3 buckets to grant access

    • VPCEndpointId: VPC endpoint ID for S3

    • e6dataAccountId & ExternalId: Provided by e6data

  • Outputs:

    • RoleArn: IAM role ARN to share with e6data

    • FailedBuckets: Any buckets where policy could not be applied

  • Deploy via AWS Console or AWS CLI. For step-by-step deployment instructions, refer to the Cross-Account S3 Access – Deployment Guide page.

Last updated