---
AWSTemplateFormatVersion: '2010-09-09'
Description: >
  This template is for an account without a pre-existing SageMaker Studio Domain & SageMaker User Profile - it creates these.
  This template also includes the additional permissions which are required to run this tutorial

Parameters:
  UserProfileName:
    Type: String
    Description: The user profile name for the SageMaker workshop
    Default: 'studio-user'
  DomainName:
    Type: String
    Description: The domain name of the Sagemaker studio instance
    Default: 'StudioDomain'


Mappings:

  # add this to your Mappings -
  ARNs:
    us-east-1:
      arn: arn:aws:sagemaker:us-east-1:081325390199:image/jupyter-server-3
    us-east-1:
      arn: arn:aws:sagemaker:us-east-1:081325390199:image/jupyter-server-3
    us-east-2:
      arn: arn:aws:sagemaker:us-east-2:429704687514:image/jupyter-server-3
    us-west-1:
      arn: arn:aws:sagemaker:us-west-1:742091327244:image/jupyter-server-3
    us-west-2:
      arn: arn:aws:sagemaker:us-west-2:236514542706:image/jupyter-server-3
    af-south-1:
      arn: arn:aws:sagemaker:af-south-1:559312083959:image/jupyter-server-3
    ap-east-1:
      arn: arn:aws:sagemaker:ap-east-1:493642496378:image/jupyter-server-3
    ap-south-1:
      arn: arn:aws:sagemaker:ap-south-1:394103062818:image/jupyter-server-3
    ap-northeast-2:
      arn: arn:aws:sagemaker:ap-northeast-2:806072073708:image/jupyter-server-3
    ap-southeast-1:
      arn: arn:aws:sagemaker:ap-southeast-1:492261229750:image/jupyter-server-3
    ap-southeast-2:
      arn: arn:aws:sagemaker:ap-southeast-2:452832661640:image/jupyter-server-3
    ap-northeast-1:
      arn: arn:aws:sagemaker:ap-northeast-1:102112518831:image/jupyter-server-3
    ca-central-1:
      arn: arn:aws:sagemaker:ca-central-1:310906938811:image/jupyter-server-3
    eu-central-1:
      arn: arn:aws:sagemaker:eu-central-1:936697816551:image/jupyter-server-3
    eu-west-1:
      arn: arn:aws:sagemaker:eu-west-1:470317259841:image/jupyter-server-3
    eu-west-2:
      arn: arn:aws:sagemaker:eu-west-2:712779665605:image/jupyter-server-3
    eu-west-3:
      arn: arn:aws:sagemaker:eu-west-3:615547856133:image/jupyter-server-3
    eu-north-1:
      arn: arn:aws:sagemaker:eu-north-1:243637512696:image/jupyter-server-3
    eu-south-1:
      arn: arn:aws:sagemaker:eu-south-1:592751261982:image/jupyter-server-3
    sa-east-1:
      arn: arn:aws:sagemaker:sa-east-1:782484402741:image/jupyter-server-3

  RegionMap:
    us-east-1:
      datascience: "arn:aws:sagemaker:us-east-1:081325390199:image/datascience-1.0"
      datawrangler: "arn:aws:sagemaker:us-east-1:663277389841:image/sagemaker-data-wrangler-1.0"
    us-east-2:
      datascience: "arn:aws:sagemaker:us-east-2:429704687514:image/datascience-1.0"
      datawrangler: "arn:aws:sagemaker:us-east-2:415577184552:image/sagemaker-data-wrangler-1.0"
    us-west-1:
      datascience: "arn:aws:sagemaker:us-west-1:742091327244:image/datascience-1.0"
      datawrangler: "arn:aws:sagemaker:us-west-1:926135532090:image/sagemaker-data-wrangler-1.0"
    us-west-2:
      datascience: "arn:aws:sagemaker:us-west-2:236514542706:image/datascience-1.0"
      datawrangler: "arn:aws:sagemaker:us-west-2:174368400705:image/sagemaker-data-wrangler-1.0"
    af-south-1:
      datascience: "arn:aws:sagemaker:af-south-1:559312083959:image/datascience-1.0"
      datawrangler: "arn:aws:sagemaker:af-south-1:143210264188:image/sagemaker-data-wrangler-1.0"
    ap-east-1:
      datascience: "arn:aws:sagemaker:ap-east-1:493642496378:image/datascience-1.0"
      datawrangler: "arn:aws:sagemaker:ap-east-1:707077482487:image/sagemaker-data-wrangler-1.0"
    ap-south-1:
      datascience: "arn:aws:sagemaker:ap-south-1:394103062818:image/datascience-1.0"
      datawrangler: "arn:aws:sagemaker:ap-south-1:089933028263:image/sagemaker-data-wrangler-1.0"
    ap-northeast-2:
      datascience: "arn:aws:sagemaker:ap-northeast-2:806072073708:image/datascience-1.0"
      datawrangler: "arn:aws:sagemaker:ap-northeast-2:131546521161:image/sagemaker-data-wrangler-1.0"
    ap-southeast-1:
      datascience: "arn:aws:sagemaker:ap-southeast-1:492261229750:image/datascience-1.0"
      datawrangler: "arn:aws:sagemaker:ap-southeast-1:119527597002:image/sagemaker-data-wrangler-1.0"
    ap-southeast-2:
      datascience: "arn:aws:sagemaker:ap-southeast-2:452832661640:image/datascience-1.0"
      datawrangler: "arn:aws:sagemaker:ap-southeast-2:422173101802:image/sagemaker-data-wrangler-1.0"
    ap-northeast-1:
      datascience: "arn:aws:sagemaker:ap-northeast-1:102112518831:image/datascience-1.0"
      datawrangler: "arn:aws:sagemaker:ap-northeast-1:649008135260:image/sagemaker-data-wrangler-1.0"
    ca-central-1:
      datascience: "arn:aws:sagemaker:ca-central-1:310906938811:image/datascience-1.0"
      datawrangler: "arn:aws:sagemaker:ca-central-1:557239378090:image/sagemaker-data-wrangler-1.0"
    eu-central-1:
      datascience: "arn:aws:sagemaker:eu-central-1:936697816551:image/datascience-1.0"
      datawrangler: "arn:aws:sagemaker:eu-central-1:024640144536:image/sagemaker-data-wrangler-1.0"
    eu-west-1:
      datascience: "arn:aws:sagemaker:eu-west-1:470317259841:image/datascience-1.0"
      datawrangler: "arn:aws:sagemaker:eu-west-1:245179582081:image/sagemaker-data-wrangler-1.0"
    eu-west-2:
      datascience: "arn:aws:sagemaker:eu-west-2:712779665605:image/datascience-1.0"
      datawrangler: "arn:aws:sagemaker:eu-west-2:894491911112:image/sagemaker-data-wrangler-1.0"
    eu-west-3:
      datascience: "arn:aws:sagemaker:eu-west-3:615547856133:image/datascience-1.0"
      datawrangler: "arn:aws:sagemaker:eu-west-3:807237891255:image/sagemaker-data-wrangler-1.0"
    eu-north-1:
      datascience: "arn:aws:sagemaker:eu-north-1:243637512696:image/datascience-1.0"
      datawrangler: "arn:aws:sagemaker:eu-north-1:054986407534:image/sagemaker-data-wrangler-1.0"
    eu-south-1:
      datascience: "arn:aws:sagemaker:eu-south-1:488287956546:image/sagemaker-data-wrangler-1.0"
      datawrangler: "arn:aws:sagemaker:eu-south-1:592751261982:image/datascience-1.0"
    sa-east-1:
      datascience: "arn:aws:sagemaker:sa-east-1:782484402741:image/datascience-1.0"
      datawrangler: "arn:aws:sagemaker:sa-east-1:424196993095:image/sagemaker-data-wrangler-1.0"

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

  SageMakerExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      Policies:
        - PolicyName: s3-access
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              -
                Effect: Allow
                Action:
                  - s3:GetObject
                  - s3:PutObject
                  - s3:DeleteObject
                  - s3:ListBucket
                Resource: arn:aws:s3:::*
        - PolicyName: iam-access
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              -
                Effect: Allow
                Action:
                  - iam:GetRole
                  - iam:GetRolePolicy
                  - iam:PassRole
                Resource: '*'
        - PolicyName: kms-access
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              -
                Effect: Allow
                Action:
                  - kms:CreateKey
                  - kms:Get*
                  - kms:List*
                Resource: '*'
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          -
            Effect: Allow
            Principal:
              Service:
                - sagemaker.amazonaws.com
            Action:
              - sts:AssumeRole
          -
            Effect: Allow
            Principal:
              Service:
                - lambda.amazonaws.com
            Action:
              - sts:AssumeRole

      ManagedPolicyArns:
        - 'arn:aws:iam::aws:policy/AmazonSageMakerFullAccess'
        - 'arn:aws:iam::aws:policy/AmazonS3FullAccess'
        - 'arn:aws:iam::aws:policy/AWSCloudFormationFullAccess'
        - 'arn:aws:iam::aws:policy/AWSCodePipeline_FullAccess'
        - !Sub "arn:${AWS::Partition}:iam::aws:policy/AmazonSageMakerPipelinesIntegrations"

  LambdaExecutionPolicy:
    Type: AWS::IAM::ManagedPolicy
    Properties:
      Path: /
      PolicyDocument:
        Version: 2012-10-17
        Statement:
          - Sid: CloudWatchLogsPermissions
            Effect: Allow
            Action:
              - logs:CreateLogGroup
              - logs:CreateLogStream
              - logs:PutLogEvents
            Resource: !Sub "arn:${AWS::Partition}:logs:*:*:*"
          - Sid: SageMakerDomainPermission
            Effect: Allow
            Action:
              - sagemaker:ListDomains
              - sagemaker:CreateDomain
              - sagemaker:DescribeDomain
              - sagemaker:DeleteDomain
              - sagemaker:UpdateDomain
              - sagemaker:ListUserProfiles
              - sagemaker:CreateUserProfile
              - sagemaker:UpdateUserProfile
              - sagemaker:DeleteUserProfile
              - sagemaker:DescribeUserProfile
              - sagemaker:ListApps
              - sagemaker:CreateApp
              - sagemaker:DescribeApp
              - sagemaker:DeleteApp
              - sagemaker:UpdateApp
            Resource:
              - !Sub "arn:${AWS::Partition}:sagemaker:*:*:domain/*"
              - !Sub "arn:${AWS::Partition}:sagemaker:*:*:user-profile/*"
              - !Sub "arn:${AWS::Partition}:sagemaker:*:*:app/*"
          - Sid: SageMakerProjectsPermission
            Effect: Allow
            Action:
              - servicecatalog:AcceptPortfolioShare
              - sagemaker:EnableSagemakerServicecatalogPortfolio
              - sagemaker:DisableSagemakerServicecatalogPortfolio
            Resource: '*'
          - Sid: ServiceCatalogPermission
            Effect: Allow
            Action:
              - servicecatalog:*
            Resource: '*'
          - Sid: SageMakerExecPassRole
            Effect: Allow
            Action:
              - iam:PassRole
            Resource: !GetAtt  SageMakerExecutionRole.Arn
      Roles:
        - !Ref  LambdaExecutionRole
  # Adding a wait time after SageMakerExecutionRole creation
  # this is due to https://t.corp.amazon.com/P45031666
  DomainDeploymentDelay:
    Type: 'Custom::Delay'
    DependsOn: SageMakerExecutionRole
    Properties:
      ServiceToken: !GetAtt DelayLambda.Arn
      TimeToWait: 300

  DelayLambda:
    Type: 'AWS::Lambda::Function'
    Properties:
      Handler: "index.handler"
      Timeout: 660
      Role: !GetAtt LambdaExecutionRole.Arn
      Runtime: python3.10
      Code:
        ZipFile: |
          import json
          import cfnresponse
          import time
          def handler(event, context):
            time_to_wait = int(event['ResourceProperties']['TimeToWait'])
            print(f'Waiting for {time_to_wait} seconds')
            time.sleep(time_to_wait)
            print(f'Waiting finished')
            cfnresponse.send(event, context, cfnresponse.SUCCESS, {},'')

  DefaultVpcLambda:
    Type: AWS::Lambda::Function
    Properties:
      FunctionName: CFGetDefaultVpcIdTut
      Code:
        ZipFile: |
          import json
          import boto3
          import cfnresponse
          import logging
          import traceback

          ec2 = boto3.client('ec2')

          def lambda_handler(event, context):
            try:
              if 'RequestType' in event and event['RequestType'] == 'Create':
                  vpc_id = get_default_vpc_id()
                  subnets =  get_subnets_for_vpc(vpc_id)
                  cfnresponse.send(event, context, cfnresponse.SUCCESS, {'VpcId': vpc_id , "Subnets" : subnets}, '')
              else:
                  cfnresponse.send(event, context, cfnresponse.SUCCESS, {},'')
            except:
              logger.exception(f"CFGetDefaultVpcIdTut:failed :{traceback.format_exc()}")
              cfnresponse.send(event, context, cfnresponse.FAILED, {})

          def get_default_vpc_id():
              vpcs = ec2.describe_vpcs(Filters=[{'Name': 'is-default', 'Values': ['true']}])
              vpcs = vpcs['Vpcs']
              vpc_id = vpcs[0]['VpcId']
              return vpc_id


          def get_subnets_for_vpc(vpcId):
              response = ec2.describe_subnets(
                  Filters=[
                      {
                          'Name': 'vpc-id',
                          'Values': [vpcId]
                      }
                  ]
              )
              subnet_ids = []
              for subnet in response['Subnets']:
                  subnet_ids.append(subnet['SubnetId'])
              return subnet_ids
      Description: Return default VPC ID and Subnets
      Handler: index.lambda_handler
      MemorySize: 512
      Role: !GetAtt LambdaExecutionRole.Arn
      Runtime: python3.10
      Timeout: 5
  DefaultVpcFinder:
    Type: Custom::ResourceForFindingDefaultVpc
    Properties:
      ServiceToken: !GetAtt DefaultVpcLambda.Arn

  StudioDomain:
    Type: AWS::SageMaker::Domain
    DependsOn: DomainDeploymentDelay
    Properties:
      AppNetworkAccessType: PublicInternetOnly
      AuthMode: IAM
      DefaultUserSettings:
          ExecutionRole: !GetAtt SageMakerExecutionRole.Arn
          JupyterServerAppSettings:
                DefaultResourceSpec:
                    SageMakerImageArn:
                        Fn::FindInMap:
                              - ARNs
                              - !Ref AWS::Region
                              - arn
      DomainName: !Ref DomainName
      SubnetIds: !GetAtt DefaultVpcFinder.Subnets
      VpcId: !GetAtt DefaultVpcFinder.VpcId

  EnableProjectsLambda:
    Type: AWS::Lambda::Function
    DependsOn: StudioDomain
    Properties:
      FunctionName: CFEnableSagemakerProjectsTut
      Code:
        ZipFile: |
          # Function: CFEnableSagemakerProjects
          # Purpose:  Enables Sagemaker Projects
          import json
          import boto3
          import cfnresponse
          import logging
          import traceback


          client = boto3.client('sagemaker')
          sc_client = boto3.client('servicecatalog')

          def lambda_handler(event, context):
            try:
              response_status = cfnresponse.SUCCESS
              execution_role = event['ResourceProperties']['ExecutionRole']

              if 'RequestType' in event and event['RequestType'] == 'Create':
                  enable_projects(execution_role)
              cfnresponse.send(event, context, response_status, {}, '')
            except:
              logger.exception(f"CFEnableSagemakerProjectsTut:failed :{traceback.format_exc()}")
              cfnresponse.send(event, context, cfnresponse.FAILED, {})

          def enable_projects(studio_role_arn):
              # enable Project on account level (accepts portfolio share)
              response = client.enable_sagemaker_servicecatalog_portfolio()

              # associate studio role with portfolio
              response = sc_client.list_accepted_portfolio_shares()

              portfolio_id = ''
              for portfolio in response['PortfolioDetails']:
                  if portfolio['ProviderName'] == 'Amazon SageMaker':
                      portfolio_id = portfolio['Id']

              response = sc_client.associate_principal_with_portfolio(
                  PortfolioId=portfolio_id,
                  PrincipalARN=studio_role_arn,
                  PrincipalType='IAM'
              )
      Description: Enable Sagemaker Projects
      Handler: index.lambda_handler
      MemorySize: 512
      Role: !GetAtt LambdaExecutionRole.Arn
      Runtime: python3.10
      Timeout: 5

  EnableProjects:
    Type: Custom::ResourceForEnablingSageMakerProjects
    Properties:
      ServiceToken: !GetAtt EnableProjectsLambda.Arn
      ExecutionRole: !GetAtt SageMakerExecutionRole.Arn

  StudioUserProfile:
    Type: AWS::SageMaker::UserProfile
    Properties:
      DomainId: !GetAtt StudioDomain.DomainId
      UserProfileName: !Ref UserProfileName
      UserSettings:
        ExecutionRole: !GetAtt SageMakerExecutionRole.Arn


### S3 Bucket similar to the one created by the create domain action in the UI
  StudioBucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Join
        - "-"
        - - "sagemaker-studio"
          - !Select
            - 0
            - !Split
              - "-"
              - !Select
                - 2
                - !Split
                  - "/"
                  - !Ref "AWS::StackId"

### Check to make sure we need to create the Roles
  DefaultCatalogRoleLambda:
    Type: AWS::Lambda::Function
    Properties:
      FunctionName: CFGetCatalogRoles
      Code:
        ZipFile: |
          import json
          import boto3
          import cfnresponse
          import logging
          import traceback

          iam_client = boto3.client('iam')
          def lambda_handler(event, context):
            try:
              # TODO implement
              if 'RequestType' in event and event['RequestType'] == 'Create':
                  catalog_role = get_catalog_role()
                  catalog_use_role = get_catalog_use_role()
                  print(catalog_role, catalog_use_role)
                  dict_data = {'CatalogRole': catalog_role , "CatalogUseRole" : catalog_use_role}
                  cfnresponse.send(event, context, cfnresponse.SUCCESS, dict_data, '')
              else:
                  cfnresponse.send(event, context, cfnresponse.SUCCESS, {},'')
            except:
              logger.exception(f"CFGetCatalogRoles:failed :{traceback.format_exc()}")
              cfnresponse.send(event, context, cfnresponse.FAILED, {})

          def get_catalog_use_role():
              roles = iam_client.list_roles()
              Role_list = roles['Roles']
              for key in Role_list:
                  if key['RoleName'] and "AmazonSageMakerServiceCatalogProductsUseRole" in key['RoleName'] :
                      return key['RoleName'] + "1"
              return "AmazonSageMakerServiceCatalogProductsUseRole"

          def get_catalog_role():
              roles = iam_client.list_roles()
              Role_list = roles['Roles']
              for key in Role_list:
                  if key['RoleName'] and "AmazonSageMakerServiceCatalogProductsLaunchRole" in key['RoleName'] :
                      return key['RoleName'] + "1"
              return "AmazonSageMakerServiceCatalogProductsLaunchRole"

      Description: Returns a dict of Product launch role or nothing
      Handler: index.lambda_handler
      MemorySize: 512
      Role: !GetAtt LambdaExecutionRole.Arn
      Runtime: python3.10
      Timeout: 5
  DefaultCatalogRoleFinder:
    Type: Custom::ResourceForFindingCatalogRolesVpc
    Properties:
      ServiceToken: !GetAtt DefaultCatalogRoleLambda.Arn

### Roles for Sagemaker projects
  AmazonSageMakerServiceCatalogProductsLaunchRole:
    Type: "AWS::IAM::Role"
    Properties:
      RoleName: !GetAtt DefaultCatalogRoleFinder.CatalogRole
      Description: "SageMaker role created from the SageMaker AWS Management Console. This role has the permissions required to launch the Amazon SageMaker portfolio of products from AWS ServiceCatalog."
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: "Allow"
            Principal:
              Service: "servicecatalog.amazonaws.com"
            Action: "sts:AssumeRole"
      Path: "/service-role/"
      MaxSessionDuration: 3600
      Policies:
        - PolicyName: AmazonSageMakerAdmin-ServiceCatalogProductsServiceRolePolicy
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - 'apigateway:GET'
                  - 'apigateway:POST'
                  - 'apigateway:PUT'
                  - 'apigateway:PATCH'
                  - 'apigateway:DELETE'
                Resource: '*'
                Condition:
                  StringLike:
                    'aws:ResourceTag/sagemaker:launch-source': '*'
              - Effect: Allow
                Action:
                  - 'apigateway:POST'
                Resource: '*'
                Condition:
                  'ForAnyValue:StringLike':
                    'aws:TagKeys':
                      - 'sagemaker:launch-source'
              - Effect: Allow
                Action:
                  - 'apigateway:PATCH'
                Resource:
                  - 'arn:aws:apigateway:*::/account'
              - Effect: Allow
                Action:
                  - 'cloudformation:CreateStack'
                  - 'cloudformation:UpdateStack'
                  - 'cloudformation:DeleteStack'
                Resource: 'arn:aws:cloudformation:*:*:stack/SC-*'
                Condition:
                  ArnLikeIfExists:
                    'cloudformation:RoleArn':
                      - 'arn:aws:sts::*:assumed-role/AmazonSageMakerServiceCatalog*'
              - Effect: Allow
                Action:
                  - 'cloudformation:DescribeStackEvents'
                  - 'cloudformation:DescribeStacks'
                Resource: 'arn:aws:cloudformation:*:*:stack/SC-*'
              - Effect: Allow
                Action:
                  - 'cloudformation:GetTemplateSummary'
                  - 'cloudformation:ValidateTemplate'
                Resource: '*'
              - Effect: Allow
                Action:
                  - 'codebuild:CreateProject'
                  - 'codebuild:DeleteProject'
                  - 'codebuild:UpdateProject'
                Resource:
                  - 'arn:aws:codebuild:*:*:project/sagemaker-*'
              - Effect: Allow
                Action:
                  - 'codecommit:CreateCommit'
                  - 'codecommit:CreateRepository'
                  - 'codecommit:DeleteRepository'
                  - 'codecommit:GetRepository'
                  - 'codecommit:TagResource'
                Resource:
                  - 'arn:aws:codecommit:*:*:sagemaker-*'
              - Effect: Allow
                Action:
                  - 'codecommit:ListRepositories'
                Resource: '*'
              - Effect: Allow
                Action:
                  - 'codepipeline:CreatePipeline'
                  - 'codepipeline:DeletePipeline'
                  - 'codepipeline:GetPipeline'
                  - 'codepipeline:GetPipelineState'
                  - 'codepipeline:StartPipelineExecution'
                  - 'codepipeline:TagResource'
                  - 'codepipeline:UpdatePipeline'
                Resource:
                  - 'arn:aws:codepipeline:*:*:sagemaker-*'
              - Effect: Allow
                Action:
                  - 'cognito-idp:CreateUserPool'
                Resource: '*'
                Condition:
                  'ForAnyValue:StringLike':
                    'aws:TagKeys':
                      - 'sagemaker:launch-source'
              - Effect: Allow
                Action:
                  - 'cognito-idp:CreateGroup'
                  - 'cognito-idp:CreateUserPoolDomain'
                  - 'cognito-idp:CreateUserPoolClient'
                  - 'cognito-idp:DeleteGroup'
                  - 'cognito-idp:DeleteUserPool'
                  - 'cognito-idp:DeleteUserPoolClient'
                  - 'cognito-idp:DeleteUserPoolDomain'
                  - 'cognito-idp:DescribeUserPool'
                  - 'cognito-idp:DescribeUserPoolClient'
                  - 'cognito-idp:UpdateUserPool'
                  - 'cognito-idp:UpdateUserPoolClient'
                Resource: '*'
                Condition:
                  StringLike:
                    'aws:ResourceTag/sagemaker:launch-source': '*'
              - Action:
                  - 'ecr:CreateRepository'
                  - 'ecr:DeleteRepository'
                Resource:
                  - 'arn:aws:ecr:*:*:repository/sagemaker-*'
                Effect: Allow
              - Effect: Allow
                Action:
                  - 'events:DescribeRule'
                  - 'events:DeleteRule'
                  - 'events:DisableRule'
                  - 'events:EnableRule'
                  - 'events:PutRule'
                  - 'events:PutTargets'
                  - 'events:RemoveTargets'
                Resource:
                  - 'arn:aws:events:*:*:rule/sagemaker-*'
              - Effect: Allow
                Action:
                  - 'firehose:CreateDeliveryStream'
                  - 'firehose:DeleteDeliveryStream'
                  - 'firehose:DescribeDeliveryStream'
                  - 'firehose:StartDeliveryStreamEncryption'
                  - 'firehose:StopDeliveryStreamEncryption'
                  - 'firehose:UpdateDestination'
                Resource: 'arn:aws:firehose:*:*:deliverystream/sagemaker-*'
              - Action:
                  - 'glue:CreateDatabase'
                  - 'glue:DeleteDatabase'
                Resource:
                  - 'arn:aws:glue:*:*:catalog'
                  - 'arn:aws:glue:*:*:database/sagemaker-*'
                  - 'arn:aws:glue:*:*:table/sagemaker-*'
                  - 'arn:aws:glue:*:*:userDefinedFunction/sagemaker-*'
                Effect: Allow
              - Action:
                  - 'glue:CreateClassifier'
                  - 'glue:DeleteClassifier'
                  - 'glue:DeleteCrawler'
                  - 'glue:DeleteJob'
                  - 'glue:DeleteTrigger'
                  - 'glue:DeleteWorkflow'
                  - 'glue:StopCrawler'
                Resource:
                  - '*'
                Effect: Allow
              - Action:
                  - 'glue:CreateWorkflow'
                Resource:
                  - 'arn:aws:glue:*:*:workflow/sagemaker-*'
                Effect: Allow
              - Action:
                  - 'glue:CreateJob'
                Resource:
                  - 'arn:aws:glue:*:*:job/sagemaker-*'
                Effect: Allow
              - Action:
                  - 'glue:CreateCrawler'
                  - 'glue:GetCrawler'
                Resource:
                  - 'arn:aws:glue:*:*:crawler/sagemaker-*'
                Effect: Allow
              - Action:
                  - 'glue:CreateTrigger'
                  - 'glue:GetTrigger'
                Resource:
                  - 'arn:aws:glue:*:*:trigger/sagemaker-*'
                Effect: Allow
              - Effect: Allow
                Action:
                  - 'iam:PassRole'
                Resource:
                  - 'arn:aws:iam::*:role/service-role/AmazonSageMakerServiceCatalog*'
              - Effect: Allow
                Action:
                  - 'lambda:AddPermission'
                  - 'lambda:CreateFunction'
                  - 'lambda:DeleteFunction'
                  - 'lambda:GetFunction'
                  - 'lambda:GetFunctionConfiguration'
                  - 'lambda:InvokeFunction'
                  - 'lambda:RemovePermission'
                Resource:
                  - 'arn:aws:lambda:*:*:function:sagemaker-*'
              - Effect: Allow
                Action:
                  - 'logs:CreateLogGroup'
                  - 'logs:CreateLogStream'
                  - 'logs:DeleteLogGroup'
                  - 'logs:DeleteLogStream'
                  - 'logs:DescribeLogGroups'
                  - 'logs:DescribeLogStreams'
                  - 'logs:PutRetentionPolicy'
                Resource:
                  - 'arn:aws:logs:*:*:log-group:/aws/apigateway/AccessLogs/*'
                  - 'arn:aws:logs:*:*:log-group::log-stream:*'
              - Effect: Allow
                Action: 's3:GetObject'
                Resource: '*'
                Condition:
                  StringEquals:
                    's3:ExistingObjectTag/servicecatalog:provisioning': 'true'
              - Effect: Allow
                Action: 's3:GetObject'
                Resource:
                  - 'arn:aws:s3:::sagemaker-*'
              - Effect: Allow
                Action:
                  - 's3:CreateBucket'
                  - 's3:DeleteBucket'
                  - 's3:DeleteBucketPolicy'
                  - 's3:GetBucketPolicy'
                  - 's3:PutBucketAcl'
                  - 's3:PutBucketNotification'
                  - 's3:PutBucketPolicy'
                  - 's3:PutBucketPublicAccessBlock'
                  - 's3:PutBucketLogging'
                  - 's3:PutEncryptionConfiguration'
                Resource: 'arn:aws:s3:::sagemaker-*'
              - Action:
                  - 'sagemaker:CreateEndpoint'
                  - 'sagemaker:CreateEndpointConfig'
                  - 'sagemaker:CreateModel'
                  - 'sagemaker:CreateWorkteam'
                  - 'sagemaker:DeleteEndpoint'
                  - 'sagemaker:DeleteEndpointConfig'
                  - 'sagemaker:DeleteModel'
                  - 'sagemaker:DeleteWorkteam'
                  - 'sagemaker:DescribeModel'
                  - 'sagemaker:DescribeEndpointConfig'
                  - 'sagemaker:DescribeEndpoint'
                  - 'sagemaker:DescribeWorkteam'
                Resource:
                  - 'arn:aws:sagemaker:*:*:*'
                Effect: Allow
              - Action:
                  - 'states:CreateStateMachine'
                  - 'states:DeleteStateMachine'
                  - 'states:UpdateStateMachine'
                Resource:
                  - 'arn:aws:states:*:*:stateMachine:sagemaker-*'
                Effect: Allow


  AmazonSageMakerServiceCatalogProductsUseRole:
    Type: "AWS::IAM::Role"
    Properties:
      RoleName: !GetAtt DefaultCatalogRoleFinder.CatalogUseRole
      Description: "SageMaker role created from the SageMaker AWS Management Console. This role has the permissions required to use the Amazon SageMaker portfolio of products from AWS ServiceCatalog."
      Path: "/service-role/"
      MaxSessionDuration: 3600
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: "Allow"
            Principal:
              Service:
                - "cloudformation.amazonaws.com"
                - "apigateway.amazonaws.com"
                - "lambda.amazonaws.com"
                - "codebuild.amazonaws.com"
                - "sagemaker.amazonaws.com"
                - "glue.amazonaws.com"
                - "events.amazonaws.com"
                - "states.amazonaws.com"
                - "codepipeline.amazonaws.com"
                - "firehose.amazonaws.com"
            Action: "sts:AssumeRole"
      Policies:
        - PolicyName: AmazonSageMakerServiceCatalogProductsUseRole-20210122T152377
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              -
                Action:
                  - cloudformation:CreateChangeSet
                  - cloudformation:CreateStack
                  - cloudformation:DescribeChangeSet
                  - cloudformation:DeleteChangeSet
                  - cloudformation:DeleteStack
                  - cloudformation:DescribeStacks
                  - cloudformation:ExecuteChangeSet
                  - cloudformation:SetStackPolicy
                  - cloudformation:UpdateStack
                Resource: arn:aws:cloudformation:*:*:stack/sagemaker-*
                Effect: Allow
              -
                Action:
                  - cloudwatch:PutMetricData
                Resource: "*"
                Effect: Allow
              -
                Action:
                  - codebuild:BatchGetBuilds
                  - codebuild:StartBuild
                Resource:
                  - arn:aws:codebuild:*:*:project/sagemaker-*
                  - arn:aws:codebuild:*:*:build/sagemaker-*
                Effect: Allow
              -
                Action:
                  - codecommit:CancelUploadArchive
                  - codecommit:GetBranch
                  - codecommit:GetCommit
                  - codecommit:GetUploadArchiveStatus
                  - codecommit:UploadArchive
                Resource: arn:aws:codecommit:*:*:sagemaker-*
                Effect: Allow
              -
                Action:
                  - codepipeline:StartPipelineExecution
                Resource: arn:aws:codepipeline:*:*:sagemaker-*
                Effect: Allow
              -
                Action:
                  - ec2:DescribeRouteTables
                Resource: "*"
                Effect: Allow
              -
                Action:
                  - ecr:BatchCheckLayerAvailability
                  - ecr:BatchGetImage
                  - ecr:Describe*
                  - ecr:GetAuthorizationToken
                  - ecr:GetDownloadUrlForLayer
                Resource: "*"
                Effect: Allow
              -
                Effect: Allow
                Action:
                  - ecr:BatchDeleteImage
                  - ecr:CompleteLayerUpload
                  - ecr:CreateRepository
                  - ecr:DeleteRepository
                  - ecr:InitiateLayerUpload
                  - ecr:PutImage
                  - ecr:UploadLayerPart
                Resource:
                  - arn:aws:ecr:*:*:repository/sagemaker-*
              -
                Action:
                  - events:DeleteRule
                  - events:DescribeRule
                  - events:PutRule
                  - events:PutTargets
                  - events:RemoveTargets
                Resource:
                  - arn:aws:events:*:*:rule/sagemaker-*
                Effect: Allow
              -
                Action:
                  - firehose:PutRecord
                  - firehose:PutRecordBatch
                Resource: arn:aws:firehose:*:*:deliverystream/sagemaker-*
                Effect: Allow
              -
                Action:
                  - glue:BatchCreatePartition
                  - glue:BatchDeletePartition
                  - glue:BatchDeleteTable
                  - glue:BatchDeleteTableVersion
                  - glue:BatchGetPartition
                  - glue:CreateDatabase
                  - glue:CreatePartition
                  - glue:CreateTable
                  - glue:DeletePartition
                  - glue:DeleteTable
                  - glue:DeleteTableVersion
                  - glue:GetDatabase
                  - glue:GetPartition
                  - glue:GetPartitions
                  - glue:GetTable
                  - glue:GetTables
                  - glue:GetTableVersion
                  - glue:GetTableVersions
                  - glue:SearchTables
                  - glue:UpdatePartition
                  - glue:UpdateTable
                Resource:
                  - arn:aws:glue:*:*:catalog
                  - arn:aws:glue:*:*:database/default
                  - arn:aws:glue:*:*:database/global_temp
                  - arn:aws:glue:*:*:database/sagemaker-*
                  - arn:aws:glue:*:*:table/sagemaker-*
                  - arn:aws:glue:*:*:tableVersion/sagemaker-*
                Effect: Allow
              -
                Action:
                  - iam:PassRole
                Resource:
                  - arn:aws:iam::*:role/service-role/AmazonSageMakerServiceCatalogProductsUse*
                Effect: Allow
              -
                Effect: Allow
                Action:
                  - lambda:InvokeFunction
                Resource:
                  - arn:aws:lambda:*:*:function:sagemaker-*
              -
                Action:
                  - logs:CreateLogDelivery
                  - logs:CreateLogGroup
                  - logs:CreateLogStream
                  - logs:DeleteLogDelivery
                  - logs:Describe*
                  - logs:GetLogDelivery
                  - logs:GetLogEvents
                  - logs:ListLogDeliveries
                  - logs:PutLogEvents
                  - logs:PutResourcePolicy
                  - logs:UpdateLogDelivery
                Resource: "*"
                Effect: Allow
              -
                Effect: Allow
                Action:
                  - s3:CreateBucket
                  - s3:DeleteBucket
                  - s3:GetBucketAcl
                  - s3:GetBucketCors
                  - s3:GetBucketLocation
                  - s3:ListAllMyBuckets
                  - s3:ListBucket
                  - s3:ListBucketMultipartUploads
                  - s3:PutBucketCors
                Resource:
                  - arn:aws:s3:::aws-glue-*
                  - arn:aws:s3:::sagemaker-*
              -
                Effect: Allow
                Action:
                  - s3:AbortMultipartUpload
                  - s3:DeleteObject
                  - s3:GetObject
                  - s3:GetObjectVersion
                  - s3:PutObject
                Resource:
                  - arn:aws:s3:::aws-glue-*
                  - arn:aws:s3:::sagemaker-*
              -
                Effect: Allow
                Action:
                  - sagemaker:*
                NotResource:
                  - arn:aws:sagemaker:*:*:domain/*
                  - arn:aws:sagemaker:*:*:user-profile/*
                  - arn:aws:sagemaker:*:*:app/*
                  - arn:aws:sagemaker:*:*:flow-definition/*
              -
                Action:
                  - states:DescribeExecution
                  - states:DescribeStateMachine
                  - states:DescribeStateMachineForExecution
                  - states:GetExecutionHistory
                  - states:ListExecutions
                  - states:ListTagsForResource
                  - states:StartExecution
                  - states:StopExecution
                  - states:TagResource
                  - states:UntagResource
                  - states:UpdateStateMachine
                Resource:
                  - arn:aws:states:*:*:stateMachine:sagemaker-*
                  - arn:aws:states:*:*:execution:sagemaker-*:*
                Effect: Allow
              -
                Action:
                  - states:ListStateMachines
                Resource: "*"
                Effect: Allow


  JupyterApp:
    Type: AWS::SageMaker::App
    DependsOn: StudioUserProfile
    Properties:
      AppName: default
      AppType: JupyterServer
      DomainId: !GetAtt StudioDomain.DomainId
      UserProfileName: !Ref UserProfileName

  DataScienceApp:
    Type: AWS::SageMaker::App
    DependsOn: StudioUserProfile
    Properties:
      AppName: instance-event-engine-datascience-ml-t3-medium
      AppType: KernelGateway
      DomainId: !GetAtt StudioDomain.DomainId
      ResourceSpec:
        InstanceType:  ml.t3.medium
        SageMakerImageArn: !FindInMap
          - RegionMap
          - !Ref 'AWS::Region'
          - datascience
      UserProfileName: !Ref UserProfileName

  DataWranglerApp:
    Type: AWS::SageMaker::App
    DependsOn: StudioUserProfile
    Properties:
      AppName: instance-event-engine-datawrangler-ml-m5-4xlarge
      AppType: KernelGateway
      DomainId: !GetAtt StudioDomain.DomainId
      ResourceSpec:
        InstanceType:  ml.m5.4xlarge
        SageMakerImageArn: !FindInMap
          - RegionMap
          - !Ref 'AWS::Region'
          - datawrangler
      UserProfileName: !Ref UserProfileName

