templates/databricks-multi-workspace-oem.template.yaml [782:997]:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  updateIAMSecurityGroupIds:
    Condition: CustomerManagedVPC 
    DependsOn: updateIAMRoleFunction
    Type: Custom::UpdateRoleAssumePolicy
    Properties:
      ServiceToken: !GetAtt 'updateIAMRoleFunction.Arn'
      role_name: !Ref IAMRole
      aws_region: !Ref AWSRegion
      accountId: !Ref AWS::AccountId
      security_group_ids: !Ref SecurityGroupIDs
      VPCID: !Ref VPCID

  # Customer managed Keys - Update Storage policy for S3 and EBS volumes 
  updateCustomManagedKeys:
    Condition: IsKMSKeyProvided
    DependsOn: updateKMSkeysFunction
    Type: Custom::updateCustomManagedKeys
    Properties:
      ServiceToken: !GetAtt 'updateKMSkeysFunction.Arn'
      key_id: !Ref KeyArn
      arn_credentials: !If [CreateDBManagedVPC, !GetAtt 'accessRoleDBManagedVPC.Arn', !GetAtt 'accessRoleCustomerManagedVPC.Arn']
      use_cases: !Ref KeyUseCases
      reuse_key_for_cluster_volumes: !Ref KeyReuseForClusterVolumes    

  # Databricks lambda for updating the Security Group Ids 
  databricksApiFunction:
    DependsOn: CopyZips
    Type: AWS::Lambda::Function
    Properties:
      Description: Databricks Account API
      Handler: rest_client.handler
      Runtime: python3.8
      Role: !GetAtt 'functionRole.Arn'
      Timeout: 900
      Code:
        S3Bucket: !Ref 'LambdaZipsBucket'
        S3Key: !Sub '${QSS3KeyPrefix}functions/packages/lambda.zip'   

  # Databricks lambda for updating the Security Group Ids 
  updateIAMRoleFunction:
    Condition: CustomerManagedVPC
    DependsOn: CopyZips
    Type: AWS::Lambda::Function
    Properties:
      Description: Update IAM Role policy document with the list of Security Group Ids
      Handler: update_custommanagedvpc_iam_role.handler
      Runtime: python3.8
      Role: !GetAtt 'functionRole.Arn'
      Timeout: 60
      Code:
        S3Bucket: !Ref 'LambdaZipsBucket'
        S3Key: !Sub '${QSS3KeyPrefix}functions/packages/lambda.zip'  
  
  # Databricks CMK lambda
  updateKMSkeysFunction:
    Condition: IsKMSKeyProvided
    DependsOn: CopyZips
    Type: AWS::Lambda::Function
    Properties:
      Description: Update CMK policy document for Storage
      Handler: update_custommanaged_cmk_policy.handler
      Runtime: python3.8
      Role: !GetAtt 'functionRole.Arn'
      Timeout: 60
      Code:
        S3Bucket: !Ref 'LambdaZipsBucket'
        S3Key: !Sub '${QSS3KeyPrefix}functions/packages/lambda.zip'

  # IAM Role for lambda function execution
  functionRole:
    Type: AWS::IAM::Role
    Metadata:
      cfn-lint:
        config:
          ignore_checks:
            - EIAMPolicyWildcardResource
          ignore_reasons:
            EIAMPolicyWildcardResource: "Need to manage databricks workspaces"
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: lambda.amazonaws.com
            Action: sts:AssumeRole
      ManagedPolicyArns:
        - !Sub arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole 
      Policies:
        - PolicyName: kmsUpdateRole
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action: 
                  - 'kms:GetKeyPolicy'
                  - 'kms:PutKeyPolicy'
                Resource: '*'   
        - PolicyName: iamUpdateRole
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action: 
                  - 'iam:PutRolePolicy'
                Resource: '*'  
      Tags:
        -
          Key: Name
          Value: !Sub '${TagValue}-IAMRole'  

  # Resources to stage lambda.zip file
  LambdaZipsBucket:
    Type: AWS::S3::Bucket
  CopyZips:
    Type: Custom::CopyZips
    Properties:
      ServiceToken: !GetAtt 'CopyZipsFunction.Arn'
      DestBucket: !Ref 'LambdaZipsBucket'
      SourceBucket: !Ref 'QSS3BucketName'
      Prefix: !Ref 'QSS3KeyPrefix'
      Objects:
        - functions/packages/lambda.zip
  CopyZipsRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: lambda.amazonaws.com
            Action: sts:AssumeRole
      ManagedPolicyArns:
        - !Sub arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
      Path: /
      Policies:
        - PolicyName: lambda-copier
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - s3:GetObject
                Resource:
                  - !Sub 'arn:${AWS::Partition}:s3:::${QSS3BucketName}/${QSS3KeyPrefix}*'
              - Effect: Allow
                Action:
                  - s3:PutObject
                  - s3:DeleteObject
                Resource:
                  - !Sub 'arn:${AWS::Partition}:s3:::${LambdaZipsBucket}/${QSS3KeyPrefix}*' 
      Tags:
        -
          Key: Name
          Value: !Sub '${TagValue}-IAMRole'            


  CopyZipsFunction:
    Type: AWS::Lambda::Function
    Properties:
      Description: Copies objects from a source S3 bucket to a destination
      Handler: index.handler
      Runtime: python3.8
      Role: !GetAtt 'CopyZipsRole.Arn'
      Timeout: 240
      Code:
        ZipFile: |
          import json
          import logging
          import threading
          import boto3
          import cfnresponse
          def copy_objects(source_bucket, dest_bucket, prefix, objects):
              s3 = boto3.client('s3')
              for o in objects:
                  key = prefix + o
                  copy_source = {
                      'Bucket': source_bucket,
                      'Key': key
                  }
                  print('copy_source: %s' % copy_source)
                  print('dest_bucket = %s'%dest_bucket)
                  print('key = %s' %key)
                  s3.copy_object(CopySource=copy_source, Bucket=dest_bucket,
                        Key=key)
          def delete_objects(bucket, prefix, objects):
              s3 = boto3.client('s3')
              objects = {'Objects': [{'Key': prefix + o} for o in objects]}
              s3.delete_objects(Bucket=bucket, Delete=objects)
          def timeout(event, context):
              logging.error('Execution is about to time out, sending failure response to CloudFormation')
              cfnresponse.send(event, context, cfnresponse.FAILED, {}, None)
          def handler(event, context):
              # make sure we send a failure to CloudFormation if the function
              # is going to timeout
              timer = threading.Timer((context.get_remaining_time_in_millis()
                        / 1000.00) - 0.5, timeout, args=[event, context])
              timer.start()
              print('Received event: %s' % json.dumps(event))
              status = cfnresponse.SUCCESS
              try:
                  source_bucket = event['ResourceProperties']['SourceBucket']
                  dest_bucket = event['ResourceProperties']['DestBucket']
                  prefix = event['ResourceProperties']['Prefix']
                  objects = event['ResourceProperties']['Objects']
                  if event['RequestType'] == 'Delete':
                      delete_objects(dest_bucket, prefix, objects)
                  else:
                      copy_objects(source_bucket, dest_bucket, prefix, objects)
              except Exception as e:
                  logging.error('Exception: %s' % e, exc_info=True)
                  status = cfnresponse.FAILED
              finally:
                  timer.cancel()
                  cfnresponse.send(event, context, status, {}, None)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -



templates/databricks-multi-workspace-test.template.yaml [752:967]:
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  updateIAMSecurityGroupIds:
    Condition: CustomerManagedVPC 
    DependsOn: updateIAMRoleFunction
    Type: Custom::UpdateRoleAssumePolicy
    Properties:
      ServiceToken: !GetAtt 'updateIAMRoleFunction.Arn'
      role_name: !Ref IAMRole
      aws_region: !Ref AWSRegion
      accountId: !Ref AWS::AccountId
      security_group_ids: !Ref SecurityGroupIDs
      VPCID: !Ref VPCID

  # Customer managed Keys - Update Storage policy for S3 and EBS volumes 
  updateCustomManagedKeys:
    Condition: IsKMSKeyProvided
    DependsOn: updateKMSkeysFunction
    Type: Custom::updateCustomManagedKeys
    Properties:
      ServiceToken: !GetAtt 'updateKMSkeysFunction.Arn'
      key_id: !Ref KeyArn
      arn_credentials: !If [CreateDBManagedVPC, !GetAtt 'accessRoleDBManagedVPC.Arn', !GetAtt 'accessRoleCustomerManagedVPC.Arn']
      use_cases: !Ref KeyUseCases
      reuse_key_for_cluster_volumes: !Ref KeyReuseForClusterVolumes

  # Databricks main Lambda for all E2 objects and workspace creation
  databricksApiFunction:
    DependsOn: CopyZips
    Type: AWS::Lambda::Function
    Properties:
      Description: Databricks Account API
      Handler: rest_client.handler
      Runtime: python3.8
      Role: !GetAtt 'functionRole.Arn'
      Timeout: 900
      Code:
        S3Bucket: !Ref 'LambdaZipsBucket'
        S3Key: !Sub '${QSS3KeyPrefix}functions/packages/lambda.zip'   
  
  # Databricks lambda for updating the Security Group Ids 
  updateIAMRoleFunction:
    Condition: CustomerManagedVPC
    DependsOn: CopyZips
    Type: AWS::Lambda::Function
    Properties:
      Description: Update IAM Role policy document with the list of Security Group Ids
      Handler: update_custommanagedvpc_iam_role.handler
      Runtime: python3.8
      Role: !GetAtt 'functionRole.Arn'
      Timeout: 60
      Code:
        S3Bucket: !Ref 'LambdaZipsBucket'
        S3Key: !Sub '${QSS3KeyPrefix}functions/packages/lambda.zip'  

  # Databricks CMK lambda
  updateKMSkeysFunction:
    Condition: IsKMSKeyProvided
    DependsOn: CopyZips
    Type: AWS::Lambda::Function
    Properties:
      Description: Update CMK policy document for Storage
      Handler: update_custommanaged_cmk_policy.handler
      Runtime: python3.8
      Role: !GetAtt 'functionRole.Arn'
      Timeout: 60
      Code:
        S3Bucket: !Ref 'LambdaZipsBucket'
        S3Key: !Sub '${QSS3KeyPrefix}functions/packages/lambda.zip'

  # IAM Role for lambda function execution
  functionRole:
    Type: AWS::IAM::Role
    Metadata:
      cfn-lint:
        config:
          ignore_checks:
            - EIAMPolicyWildcardResource
          ignore_reasons:
            EIAMPolicyWildcardResource: "Need to manage databricks workspaces"
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: lambda.amazonaws.com
            Action: sts:AssumeRole
      ManagedPolicyArns:
        - !Sub arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole 
      Policies:
        - PolicyName: kmsUpdateRole
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action: 
                  - 'kms:GetKeyPolicy'
                  - 'kms:PutKeyPolicy'
                Resource: '*'   
        - PolicyName: iamUpdateRole
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action: 
                  - 'iam:PutRolePolicy'
                Resource: '*'  
      Tags:
        -
          Key: Name
          Value: !Sub '${TagValue}-IAMRole'  

  # Resources to stage lambda.zip file
  LambdaZipsBucket:
    Type: AWS::S3::Bucket
  CopyZips:
    Type: Custom::CopyZips
    Properties:
      ServiceToken: !GetAtt 'CopyZipsFunction.Arn'
      DestBucket: !Ref 'LambdaZipsBucket'
      SourceBucket: !Ref 'QSS3BucketName'
      Prefix: !Ref 'QSS3KeyPrefix'
      Objects:
        - functions/packages/lambda.zip
  CopyZipsRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: lambda.amazonaws.com
            Action: sts:AssumeRole
      ManagedPolicyArns:
        - !Sub arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
      Path: /
      Policies:
        - PolicyName: lambda-copier
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - s3:GetObject
                Resource:
                  - !Sub 'arn:${AWS::Partition}:s3:::${QSS3BucketName}/${QSS3KeyPrefix}*'
              - Effect: Allow
                Action:
                  - s3:PutObject
                  - s3:DeleteObject
                Resource:
                  - !Sub 'arn:${AWS::Partition}:s3:::${LambdaZipsBucket}/${QSS3KeyPrefix}*' 
      Tags:
        -
          Key: Name
          Value: !Sub '${TagValue}-IAMRole'            


  CopyZipsFunction:
    Type: AWS::Lambda::Function
    Properties:
      Description: Copies objects from a source S3 bucket to a destination
      Handler: index.handler
      Runtime: python3.8
      Role: !GetAtt 'CopyZipsRole.Arn'
      Timeout: 240
      Code:
        ZipFile: |
          import json
          import logging
          import threading
          import boto3
          import cfnresponse
          def copy_objects(source_bucket, dest_bucket, prefix, objects):
              s3 = boto3.client('s3')
              for o in objects:
                  key = prefix + o
                  copy_source = {
                      'Bucket': source_bucket,
                      'Key': key
                  }
                  print('copy_source: %s' % copy_source)
                  print('dest_bucket = %s'%dest_bucket)
                  print('key = %s' %key)
                  s3.copy_object(CopySource=copy_source, Bucket=dest_bucket,
                        Key=key)
          def delete_objects(bucket, prefix, objects):
              s3 = boto3.client('s3')
              objects = {'Objects': [{'Key': prefix + o} for o in objects]}
              s3.delete_objects(Bucket=bucket, Delete=objects)
          def timeout(event, context):
              logging.error('Execution is about to time out, sending failure response to CloudFormation')
              cfnresponse.send(event, context, cfnresponse.FAILED, {}, None)
          def handler(event, context):
              # make sure we send a failure to CloudFormation if the function
              # is going to timeout
              timer = threading.Timer((context.get_remaining_time_in_millis()
                        / 1000.00) - 0.5, timeout, args=[event, context])
              timer.start()
              print('Received event: %s' % json.dumps(event))
              status = cfnresponse.SUCCESS
              try:
                  source_bucket = event['ResourceProperties']['SourceBucket']
                  dest_bucket = event['ResourceProperties']['DestBucket']
                  prefix = event['ResourceProperties']['Prefix']
                  objects = event['ResourceProperties']['Objects']
                  if event['RequestType'] == 'Delete':
                      delete_objects(dest_bucket, prefix, objects)
                  else:
                      copy_objects(source_bucket, dest_bucket, prefix, objects)
              except Exception as e:
                  logging.error('Exception: %s' % e, exc_info=True)
                  status = cfnresponse.FAILED
              finally:
                  timer.cancel()
                  cfnresponse.send(event, context, status, {}, None)
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -



