AWSTemplateFormatVersion: "2010-09-09"
Parameters:
  VpcCIDRBlock:
    Type: String
    Default: "10.0.0.0/16"
    Description: "CIDR block for the VPC"

  PublicSubnetCIDRBlock:
    Type: String
    Default: "10.0.0.0/24"
    Description: "CIDR block for the public subnet"

  PrivateSubnetCIDRBlock:
    Type: String
    Default: "10.0.1.0/24"
    Description: "CIDR block for the private subnet"

  AvailabiltyZone:
    Type: String
    Default: "us-east-1a"
    Description: "Availability Zone to Use"

  PrivateSubnetRS1CIDRBlock:
    Type: String
    Default: "10.0.2.0/24"
    Description: "CIDR block for the private subnet1. Used for Redshift"

  RedshiftAvailabiltyZone1:
    Type: String
    Default: "us-east-1a"
    Description: "Availability Zone to Use"

  PrivateSubnetRS2CIDRBlock:
    Type: String
    Default: "10.0.3.0/24"
    Description: "CIDR block for the private subnet2.Used for Redshift"

  RedshiftAvailabiltyZone2:
    Type: String
    Default: "us-east-1b"
    Description: "Availability Zone to Use"

  PrivateSubnetRS3CIDRBlock:
    Type: String
    Default: "10.0.4.0/24"
    Description: "CIDR block for the private subnet3.Used for Redshift"

  RedshiftAvailabiltyZone3:
    Type: String
    Default: "us-east-1c"
    Description: "Availability Zone to Use"

  S3BucketNameLakeFormationGoverned:
    Type: String
    Default: "tip-blog-s3-lf-temp"
    Description: "Provide a globally unique bucket Name.CloudFormation will create an S3 Bucket with this name which is governed by Lake Formation"

  S3BucketNameS3AccessGrants:
    Type: String
    Default: "tip-blog-s3-s3ag1-temp"
    Description: "Provide a globally unique bucket Name.CloudFormation will create an S3 Bucket with this name which is governed by S3 Access grants permissions"

  S3BucketNameAthenaResultsLocationS3AccessGrants:
    Type: String
    Default: "tip-blog-s3-athenarl-s3ag-temp"
    Description: "Provide a globally unique bucket Name.CloudFormation will create an S3 Bucket with this name to store Athena query results."

  S3BucketNameForEMRWorkspaceStorage:
    Type: String
    Default: "tip-blog-s3-emrtorage-workspace-temp"
    Description: "Provide a globally unique bucket Name.CloudFormation will create an S3 Bucket with this name to store EMR Studio workspace objects like Notebooks"

  IDCGroup1Id:
    Type: String
    Description: "Provide the Group ID from your IDC for group corresponding to Group1"

  IDCGroup2Id:
    Type: String
    Description: "Provide the Group ID from your IDC for group corresponding to Group2"

  IDCGroup3Id:
    Type: String
    Description: "Provide the Group ID from your IDC for group corresponding to Group3"

  IDCUser1Id:
    Type: String
    Description: "Provide the User ID from IDC for User1 belonging to Group1. We use this id to create S3 access grant to user id prefix for Athena Result location added security"

  RedshiftServerlessAdminUserName:
    Type: String
    Default: "admin"
    Description: "Username for Redshift administrator"

  RedshiftServerlessAdminPassword:
    Type: String
    NoEcho: true
    Description: "Redshift Database"

  RedshiftServerlessDatabase:
    Type: String
    Default: "dev"
    Description: "Redshift Database"

  DeployAthenaFlow:
    Type: String
    Default: "Yes"
    AllowedValues: ["Yes", "No"]
    Description: "Specify whether to deploy Athena components for interactive queries using Athena Query Editor"

  DeployEMRFlow:
    Type: String
    Default: "Yes"
    AllowedValues: ["Yes", "No"]
    Description: "Specify whether to deploy EMR components for interactive queries using EMR Notebook"

  DeployRedshiftQEV2Flow:
    Type: String
    Default: "Yes"
    AllowedValues: ["Yes", "No"]
    Description: "Specify whether to Redshift for interactive queries using Redshift Query Editor V2"

  CreateS3AGInstance:
    Type: String
    Default: "Yes"
    AllowedValues: ["Yes", "No"]
    Description: "Specify whether to create S3 Access grant instance. If you already have S3 Access Grant instance in the region. Mark this as No. S3 Access grants is used with EMR and Athena flows"

  IAMIDCInstanceArn:
    Type: String
    Description: "Instance ARN of AWS IAM Identity Center"

  SSlCertsS3BucketName:
    Type: String
    Default: "references-sg"
    Description: "An existing bucket name in your account where the SSL cert used with EMR security configuration are placed.Copy the SSL cert zip to this bucket before executing the stack"

  SSlCertsZip:
    Type: String
    Default: "my-certs.zip"
    Description: "Name of SSL cert zip, If you use the sample provided in the blog then my-certs.zip"

Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
      - Label:
          default: "VPC Configuration"
        Parameters:
          - VpcCIDRBlock
          - PublicSubnetCIDRBlock
          - PrivateSubnetCIDRBlock
          - AvailabiltyZone

      - Label:
          default: "Choose components to provision"
        Parameters:
          - DeployAthenaFlow
          - DeployEMRFlow
          - DeployRedshiftQEV2Flow
          - CreateS3AGInstance

      - Label:
          default: "Identity Center Configuration"
        Parameters:
          - IDCGroup1Id
          - IDCGroup2Id
          - IDCGroup3Id
          - IAMIDCInstanceArn
      
      - Label:
          default: "Data and EMR Studio workspace location buckets (Required if you choose to deploy EMR and/or Athena flows)"
        Parameters:
          - S3BucketNameLakeFormationGoverned
          - S3BucketNameForEMRWorkspaceStorage
 
      - Label:
          default: "EMR Configuration (Required if you choose to deploy EMR flow)"
        Parameters:
          - S3BucketNameS3AccessGrants
          - SSlCertsS3BucketName
          - SSlCertsZip


      - Label:
          default: "Athena Configuration (Required if you choose to deploy Athena flow)"
        Parameters:
          - IDCUser1Id
          - S3BucketNameAthenaResultsLocationS3AccessGrants

      - Label:
          default: "Redshift Configuration (Required if you choose to deploy Redshift flow)"
        Parameters:
          - RedshiftServerlessAdminUserName
          - RedshiftServerlessAdminPassword
          - RedshiftServerlessDatabase
          - PrivateSubnetRS1CIDRBlock
          - RedshiftAvailabiltyZone1
          - PrivateSubnetRS2CIDRBlock
          - RedshiftAvailabiltyZone2
          - PrivateSubnetRS3CIDRBlock
          - RedshiftAvailabiltyZone3

          

      

      

Resources:
  TIPVPC:
    Type: "AWS::EC2::VPC"
    Properties:
      CidrBlock: !Ref VpcCIDRBlock
      EnableDnsSupport: true
      EnableDnsHostnames: true
      Tags:
        - Key: Name
          Value: "TIP-Blog-VPC"
        - Key: for-use-with-amazon-emr-managed-policies
          Value: true

  TIPVPCNoIngressSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: "no-ingress-sg"
      GroupDescription: "Security group with no ingress rule"
      VpcId: !Ref TIPVPC
      SecurityGroupEgress:
      - IpProtocol: "-1"
        FromPort: -1
        ToPort: -1
        CidrIp: "0.0.0.0/0"

  PublicSubnet:
    Type: "AWS::EC2::Subnet"
    Properties:
      VpcId: !Ref TIPVPC
      CidrBlock: !Ref PublicSubnetCIDRBlock
      AvailabilityZone: !Ref AvailabiltyZone 
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: "PublicSubnet"
        - Key: for-use-with-amazon-emr-managed-policies
          Value: true

  PrivateSubnet:
    Type: "AWS::EC2::Subnet"
    Properties:
      VpcId: !Ref TIPVPC
      CidrBlock: !Ref PrivateSubnetCIDRBlock
      AvailabilityZone: !Ref AvailabiltyZone 
      Tags:
        - Key: Name
          Value: "tip-blog-privatesubnet"
        - Key: for-use-with-amazon-emr-managed-policies
          Value: true

  PrivateSubnet1:
    Type: "AWS::EC2::Subnet"
    Condition: DeployRedshiftCondition 
    Properties:
      VpcId: !Ref TIPVPC
      CidrBlock: !Ref PrivateSubnetRS1CIDRBlock
      AvailabilityZone: !Ref RedshiftAvailabiltyZone1 
      Tags:
        - Key: Name
          Value: "tip-blog-privatesubnet"
        - Key: for-use-with-amazon-emr-managed-policies
          Value: true

  PrivateSubnet2:
    Type: "AWS::EC2::Subnet"
    Condition: DeployRedshiftCondition 
    Properties:
      VpcId: !Ref TIPVPC
      CidrBlock: !Ref PrivateSubnetRS2CIDRBlock
      AvailabilityZone: !Ref RedshiftAvailabiltyZone2 
      Tags:
        - Key: Name
          Value: "tip-blog-privatesubnet"
        - Key: for-use-with-amazon-emr-managed-policies
          Value: true

  PrivateSubnet3:
    Type: "AWS::EC2::Subnet"
    Condition: DeployRedshiftCondition 
    Properties:
      VpcId: !Ref TIPVPC
      CidrBlock: !Ref PrivateSubnetRS3CIDRBlock
      AvailabilityZone: !Ref RedshiftAvailabiltyZone3 
      Tags:
        - Key: Name
          Value: "tip-blog-privatesubnet"
        - Key: for-use-with-amazon-emr-managed-policies
          Value: true


  InternetGateway:
    Type: "AWS::EC2::InternetGateway"
    Properties:
      Tags:
        - Key: Name
          Value: "tip-blog-InternetGateway"

  AttachGateway:
    Type: "AWS::EC2::VPCGatewayAttachment"
    Properties:
      VpcId: !Ref TIPVPC
      InternetGatewayId: !Ref InternetGateway

  NatGateway:
    Type: "AWS::EC2::NatGateway"
    Properties:
      AllocationId: !GetAtt ElasticIP.AllocationId
      SubnetId: !Ref PublicSubnet

  ElasticIP:
    Type: "AWS::EC2::EIP"

  PublicRouteTable:
    Type: "AWS::EC2::RouteTable"
    Properties:
      VpcId: !Ref TIPVPC
      Tags:
        - Key: Name
          Value: "PublicRouteTable"

  PublicRoute:
    Type: "AWS::EC2::Route"
    Properties:
      RouteTableId: !Ref PublicRouteTable
      DestinationCidrBlock: "0.0.0.0/0"
      GatewayId: !Ref InternetGateway

  PublicSubnetRouteTableAssociation:
    Type: "AWS::EC2::SubnetRouteTableAssociation"
    Properties:
      SubnetId: !Ref PublicSubnet
      RouteTableId: !Ref PublicRouteTable

  PrivateRouteTable:
    Type: "AWS::EC2::RouteTable"
    Properties:
      VpcId: !Ref TIPVPC
      Tags:
        - Key: Name
          Value: "PrivateRouteTable"

  PrivateRoute:
    Type: "AWS::EC2::Route"
    DependsOn: NatGateway
    Properties:
      RouteTableId: !Ref PrivateRouteTable
      DestinationCidrBlock: "0.0.0.0/0"
      NatGatewayId: !Ref NatGateway

  SubnetRouteTableAssociation:
    Type: "AWS::EC2::SubnetRouteTableAssociation"
    Properties:
      SubnetId: !Ref PrivateSubnet
      RouteTableId: !Ref PrivateRouteTable

  S3BucketNameLFG:
    Type: "AWS::S3::Bucket"
    Condition: DeployStudioCondition
    Properties:
      BucketName: !Ref S3BucketNameLakeFormationGoverned
  
  S3BucketNameS3AG:
    Type: "AWS::S3::Bucket"
    Condition: DeployEMRCondition
    Properties:
      BucketName: !Ref S3BucketNameS3AccessGrants

  S3BucketNameAthenaResults:
    Type: "AWS::S3::Bucket"
    Condition: DeployStudioCondition
    Properties:
      BucketName: !Ref S3BucketNameAthenaResultsLocationS3AccessGrants

  S3BucketNameEMRStudioWorkspaceStorage:
    Type: "AWS::S3::Bucket"
    Condition: DeployStudioCondition
    Properties:
      BucketName: !Ref S3BucketNameForEMRWorkspaceStorage

  LambdaExecutionRole:
    Type: AWS::IAM::Role
    Condition: DeployStudioCondition
    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
      Policies:
        - PolicyName: CopyObjectPolicy
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - s3:ListBucket
                  - s3:GetBucketLocation
                Resource:
                  - !Sub "arn:aws:s3:::${S3BucketNameLakeFormationGoverned}"
                  - !Sub "arn:aws:s3:::${S3BucketNameS3AccessGrants}"
                  - !Sub "arn:aws:s3:::${S3BucketNameAthenaResultsLocationS3AccessGrants}"
                  - !Sub "arn:aws:s3:::${S3BucketNameForEMRWorkspaceStorage}"
              - Effect: Allow
                Action:
                  - s3:GetObject
                  - s3:PutObject
                  - s3:DeleteObject
                  - s3:ListObjects
                  - s3:PutObjectAcl
                  - s3:GetObjectAcl
                Resource:
                  - !Sub "arn:aws:s3:::${S3BucketNameLakeFormationGoverned}/*"
                  - !Sub "arn:aws:s3:::${S3BucketNameS3AccessGrants}/*"
                  - !Sub "arn:aws:s3:::${S3BucketNameAthenaResultsLocationS3AccessGrants}/*"
                  - !Sub "arn:aws:s3:::${S3BucketNameForEMRWorkspaceStorage}/*"
              - Effect: Allow
                Action:
                  - s3:GetObject
                Resource:
                  - "arn:aws:s3:::aws-blogs-artifacts-public/*"

  CopyLambdaFunction:
    Type: AWS::Lambda::Function
    DependsOn: LambdaExecutionRole
    Condition: DeployStudioCondition
    Properties:
      Code: 
        ZipFile: |
          import boto3
          import os
          import cfnresponse
          response_data = {}
          s3 = boto3.client('s3')

          def bucket_exists(bucket_name):
            try:
                s3.head_bucket(Bucket=bucket_name)
                return True
            except Exception as e:
                # Log the exception or return False if the bucket doesn't exist
                print(f"Bucket {bucket_name} does not exist or is not accessible: {str(e)}")
                return False

          def lambda_handler(event, context):
            source_bucket = 'aws-blogs-artifacts-public'
            lf_destination_bucket = os.environ['S3BucketNameLFG']
            s3ag_destination_bucket = os.environ['S3BucketNameS3AG']
            s3_athena_bucket = os.environ['S3BucketNameAthena']
            s3_workspace_bucket = os.environ['S3BucketNameWorkStorage']
            the_event = event['RequestType']

            try:
              print("Starting to copy.")
              if the_event in ('Create', 'Update'):
                

                object_key = 'artifacts/BDB-3528/data/customer/cust_feedback_v0.csv'
                copy_params = {
                    'Bucket': lf_destination_bucket,
                    'CopySource': {'Bucket': source_bucket, 'Key': object_key},
                    'Key': 'data/cust_feedback_v0.csv'
                }
                s3.copy_object(**copy_params)
                print(f"Successfully copied {object_key} from {source_bucket} to {lf_destination_bucket}.")

                object_key = 'artifacts/BDB-3528/data/customer-v1/cust_feedback_v1.csv'
                copy_params = {
                    'Bucket': s3ag_destination_bucket,
                    'CopySource': {'Bucket': source_bucket, 'Key': object_key},
                    'Key': 'input/cust_feedback_v1.csv'
                }
                if s3ag_destination_bucket.strip() !='' and bucket_exists (s3ag_destination_bucket):
                  s3.copy_object(**copy_params)
                  print(f"Successfully copied {object_key} from {source_bucket} to {s3ag_destination_bucket}.")

                
              elif the_event == 'Delete':
                print("Deleting S3 content...")
                b_operator = boto3.resource('s3')
                if s3ag_destination_bucket.strip() !='' and bucket_exists (s3ag_destination_bucket) :
                  print("Deleting - ",str(s3ag_destination_bucket))
                  b_operator.Bucket(str(s3ag_destination_bucket)).objects.all().delete()
                  print("Execution succesfull!")
                if lf_destination_bucket.strip() !='' and bucket_exists (lf_destination_bucket):
                  print("Deleting - ",str(lf_destination_bucket))
                  b_operator.Bucket(str(lf_destination_bucket)).objects.all().delete()
                  print("Execution succesfull!")
                if s3_athena_bucket.strip() !='' and bucket_exists (s3_athena_bucket) :
                  print("Deleting - ",str(s3_athena_bucket))
                  b_operator.Bucket(str(s3_athena_bucket)).objects.all().delete()
                  print("Execution succesfull!")
                if s3_workspace_bucket.strip() !='' and bucket_exists (s3_workspace_bucket) :
                  print("Deleting - ",str(s3_workspace_bucket))
                  import time
                  time.sleep(240) ## Sleep to allow terminating EMR cluster logs updates 
                  b_operator.Bucket(str(s3_workspace_bucket)).objects.all().delete()
                  print("Execution succesfull!")

              
              cfnresponse.send(event, context, cfnresponse.SUCCESS, response_data)
            except Exception as e:
              print("Execution failed...")
              print(str(e))
              response_data['Data'] = str(e)
              cfnresponse.send(event, context, cfnresponse.FAILED, response_data)
              

      Handler: index.lambda_handler
      Runtime: python3.8
      Timeout: 600
      Role: !GetAtt LambdaExecutionRole.Arn
      Environment:
        Variables:
          S3BucketNameLFG: !Ref S3BucketNameLakeFormationGoverned
          S3BucketNameS3AG: !Ref S3BucketNameS3AccessGrants
          S3BucketNameAthena: !Ref S3BucketNameAthenaResultsLocationS3AccessGrants
          S3BucketNameWorkStorage: !Ref S3BucketNameForEMRWorkspaceStorage
          
  s3CustomResource:
    Type: Custom::S3CustomResource
    Condition: DeployStudioCondition
    DependsOn: LambdaExecutionRole
    Version: "1.0"
    Properties:
      ServiceToken: !GetAtt CopyLambdaFunction.Arn

  cleanupBucketOnDelete:
     Type: Custom::cleanupbucket1
     Condition: DeployStudioCondition
     DependsOn: 
      - CopyLambdaFunction
      - S3BucketNameLFG
      - S3BucketNameEMRStudioWorkspaceStorage
     Properties:
       ServiceToken: !GetAtt CopyLambdaFunction.Arn

  cleanupBucketOnDelete2:
     Type: Custom::cleanupbucket2
     Condition: DeployEMRCondition
     DependsOn: 
      - CopyLambdaFunction
      - S3BucketNameS3AG
     Properties:
       ServiceToken: !GetAtt CopyLambdaFunction.Arn

  cleanupBucketOnDelete3:
     Type: Custom::cleanupbucket3
     Condition: DeployAthenaCondition
     DependsOn: 
      - CopyLambdaFunction
      - S3BucketNameAthenaResults
     Properties:
       ServiceToken: !GetAtt CopyLambdaFunction.Arn

      
  # Create Engine and Workspace Security groups
  # https://docs.aws.amazon.com/emr/latest/ManagementGuide/emr-studio-security-groups.html
  

  # Handle cyclic dependency with engine and workspace sg
  EngineSGIngressFromWorkspaceSG:
    Type: 'AWS::EC2::SecurityGroupIngress'
    Properties:
      FromPort: 18888
      ToPort: 18888
      GroupId: !GetAtt EMRStudioEngineSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt EMRStudioWorkspaceSecurityGroup.GroupId
      IpProtocol: 'tcp'


  EMRStudioWorkspaceSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: "EMR Studio Workspace Security Group"
      VpcId: !Ref TIPVPC
      SecurityGroupEgress:
      - IpProtocol: tcp
        FromPort: 443
        ToPort: 443
        CidrIp: 0.0.0.0/0
      - IpProtocol: tcp
        FromPort: 18888
        ToPort: 18888
        DestinationSecurityGroupId:
          Fn::GetAtt:
          - EMRStudioEngineSecurityGroup
          - GroupId
      Tags:
      - Key: Name
        Value: EMRTIP-Workspace-SG
      - Key: for-use-with-amazon-emr-managed-policies
        Value: 'true'

  EMRStudioEngineSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: "EMR Studio Engine Security Group"
      VpcId: !Ref TIPVPC
      SecurityGroupEgress:
      - IpProtocol: "-1"
        FromPort: -1
        ToPort: -1
        CidrIp: "0.0.0.0/0"
      Tags:
        - Key: Name
          Value: EMRTIP-Engine-SG
        - Key: for-use-with-amazon-emr-managed-policies
          Value: 'true'

  # Redshift and QS firewall - Handle cyclic dependency with engine and workspace sg
  RedshiftIngressFromQS:
    Type: 'AWS::EC2::SecurityGroupIngress'
    Properties:
      FromPort: 0
      ToPort: 65535
      GroupId: !GetAtt QSSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt RedshiftSecurityGroup.GroupId
      IpProtocol: 'tcp'

  QSIngressFromRS:
    Type: 'AWS::EC2::SecurityGroupIngress'
    Properties:
      FromPort: 0
      ToPort: 65535
      GroupId: !GetAtt RedshiftSecurityGroup.GroupId
      SourceSecurityGroupId: !GetAtt QSSecurityGroup.GroupId
      IpProtocol: 'tcp'


  RedshiftSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: "Redshift serverless namespace Security Group"
      VpcId: !Ref TIPVPC
      SecurityGroupEgress:
      - IpProtocol: tcp
        FromPort: 0
        ToPort: 65535
        CidrIp: 0.0.0.0/0

  QSSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: "QS Security Group"
      VpcId: !Ref TIPVPC
      SecurityGroupEgress:
      - IpProtocol: tcp
        FromPort: 0
        ToPort: 65535
        CidrIp: 0.0.0.0/0

  ## Cloud9 is deprecated. Pleas use cloud shell from AWS management console to execute the commands.

  # C9IDE:
  #   Type: 'AWS::Cloud9::EnvironmentEC2'
  #   Properties:
  #     Name: YourCloud9EnvironmentName
  #     Description: 'YourCloud9Environment for running CLI commands '
  #     InstanceType: t2.micro  # Adjust as needed
  #     AutomaticStopTimeMinutes: 30  # Adjust as needed
  #     ConnectionType: CONNECT_SSH  # Or CONNECT_SSM for Systems Manager
  #     SubnetId: !Ref PublicSubnet
  #     ImageId: amazonlinux-2023-x86_64  # Specify your EC2 AMI ID
  
  
  EMRStudioServiceRole:
    Type: AWS::IAM::Role
    Condition: DeployStudioCondition
    Properties: 
      RoleName: !Sub 'AmazonEMRStudio_ServiceRole_tipblog_${AWS::AccountId}'
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - elasticmapreduce.amazonaws.com
            Action:
              - 'sts:AssumeRole'
      Path: '/'
      Policies:
        - PolicyName: TIPBlogStudioWrkspaceAccessPolicy
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
            - Effect: Allow
              Action: ['s3:GetObject','s3:ListBucket','s3:PutObject']
              Resource: 
                - !Sub 'arn:aws:s3:::${S3BucketNameForEMRWorkspaceStorage}/*'
                - !Sub 'arn:aws:s3:::${S3BucketNameForEMRWorkspaceStorage}'
        - PolicyName: AllowEC2ReadOnlyActions
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - "ec2:DescribeSecurityGroups"
                  - "ec2:DescribeNetworkInterfaces"
                  - "ec2:DescribeTags"
                  - "ec2:DescribeInstances"
                  - "ec2:DescribeSubnets"
                  - "ec2:DescribeVpcs"
                Resource:
                  - "*"
        - PolicyName: EMRSparkAI-Studio-Service-Policy
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
            - Sid: AllowEMRReadOnlyActions
              Effect: Allow
              Action:
              - elasticmapreduce:ListInstances
              - elasticmapreduce:DescribeCluster
              - elasticmapreduce:ListSteps
              Resource: "*"
            - Sid: AllowEC2ENIActionsWithEMRTags
              Effect: Allow
              Action:
              - ec2:CreateNetworkInterfacePermission
              - ec2:DeleteNetworkInterface
              Resource:
              - arn:aws:ec2:*:*:network-interface/*
              Condition:
                StringEquals:
                  aws:ResourceTag/for-use-with-amazon-emr-managed-policies: 'true'
            - Sid: AllowEC2ENIAttributeAction
              Effect: Allow
              Action:
              - ec2:ModifyNetworkInterfaceAttribute
              Resource:
              - arn:aws:ec2:*:*:instance/*
              - arn:aws:ec2:*:*:network-interface/*
              - arn:aws:ec2:*:*:security-group/*
            - Sid: AllowEC2SecurityGroupActionsWithEMRTags
              Effect: Allow
              Action:
              - ec2:AuthorizeSecurityGroupEgress
              - ec2:AuthorizeSecurityGroupIngress
              - ec2:RevokeSecurityGroupEgress
              - ec2:RevokeSecurityGroupIngress
              - ec2:DeleteNetworkInterfacePermission
              Resource: "*"
              Condition:
                StringEquals:
                  aws:ResourceTag/for-use-with-amazon-emr-managed-policies: 'true'
            - Sid: AllowDefaultEC2SecurityGroupsCreationWithEMRTags
              Effect: Allow
              Action:
              - ec2:CreateSecurityGroup
              Resource:
              - arn:aws:ec2:*:*:security-group/*
              Condition:
                StringEquals:
                  aws:RequestTag/for-use-with-amazon-emr-managed-policies: 'true'
            - Sid: AllowDefaultEC2SecurityGroupsCreationInVPCWithEMRTags
              Effect: Allow
              Action:
              - ec2:CreateSecurityGroup
              Resource:
              - arn:aws:ec2:*:*:vpc/*
              Condition:
                StringEquals:
                  aws:ResourceTag/for-use-with-amazon-emr-managed-policies: 'true'
            - Sid: AllowAddingEMRTagsDuringDefaultSecurityGroupCreation
              Effect: Allow
              Action:
              - ec2:CreateTags
              Resource: arn:aws:ec2:*:*:security-group/*
              Condition:
                StringEquals:
                  aws:RequestTag/for-use-with-amazon-emr-managed-policies: 'true'
                  ec2:CreateAction: CreateSecurityGroup
            - Sid: AllowEC2ENICreationWithEMRTags
              Effect: Allow
              Action:
              - ec2:CreateNetworkInterface
              Resource:
              - arn:aws:ec2:*:*:network-interface/*
              Condition:
                StringEquals:
                  aws:RequestTag/for-use-with-amazon-emr-managed-policies: 'true'
            - Sid: AllowEC2ENICreationInSubnetAndSecurityGroupWithEMRTags
              Effect: Allow
              Action:
              - ec2:CreateNetworkInterface
              Resource:
              - arn:aws:ec2:*:*:subnet/*
              - arn:aws:ec2:*:*:security-group/*
              Condition:
                StringEquals:
                  aws:ResourceTag/for-use-with-amazon-emr-managed-policies: 'true'
            - Sid: AllowAddingTagsDuringEC2ENICreation
              Effect: Allow
              Action:
              - ec2:CreateTags
              Resource: arn:aws:ec2:*:*:network-interface/*
              Condition:
                StringEquals:
                  ec2:CreateAction: CreateNetworkInterface
            - Sid: AllowEC2ReadOnlyActions
              Effect: Allow
              Action:
              - ec2:DescribeSecurityGroups
              - ec2:DescribeNetworkInterfaces
              - ec2:DescribeTags
              - ec2:DescribeInstances
              - ec2:DescribeSubnets
              - ec2:DescribeVpcs
              Resource: "*"
            - Sid: AllowSecretsManagerReadOnlyActionsWithEMRTags
              Effect: Allow
              Action:
              - secretsmanager:GetSecretValue
              Resource: arn:aws:secretsmanager:*:*:secret:*
              Condition:
                StringEquals:
                  aws:ResourceTag/for-use-with-amazon-emr-managed-policies: 'true'
            - Effect: Allow
              Action:
              - s3:PutObject
              - s3:GetObject
              - s3:GetEncryptionConfiguration
              - s3:ListBucket
              - s3:DeleteObject
              Resource: arn:aws:s3:::*

  TIPUserRole:
    Type: AWS::IAM::Role
    Condition: DeployStudioCondition
    Properties: 
      RoleName: !Sub 'UserRole_tipblog_${AWS::AccountId}'
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - elasticmapreduce.amazonaws.com
                - access-grants.s3.amazonaws.com
                - athena.amazonaws.com
              AWS:
                 !If
                    - DeployEMRCondition
                    - !GetAtt EMREC2InstanceRole.Arn
                    - !Ref 'AWS::NoValue'
            Action:
              - 'sts:AssumeRole'
              - 'sts:SetContext'
              - 'sts:SetSourceIdentity'
      Path: '/'
      Policies:
        - PolicyName: TIPBlog-rs-iam-pass-role
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
            - Effect: Allow
              Action: ['iam:PassRole']
              Resource: !GetAtt EMRStudioServiceRole.Arn
        - PolicyName: AthenaWGAccess
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
            - Effect: Allow
              Action: ['athena:GetDataCatalog','athena:GetPreparedStatement','athena:CreatePreparedStatement','athena:DeletePreparedStatement','athena:UpdatePreparedStatement','athena:ListPreparedStatements','athena:GetWorkGroup','athena:ListWorkGroups','athena:StartQueryExecution','athena:GetQueryExecution','athena:GetQueryResults']
              Resource: 
                - '*'

        - PolicyName: TIPBlog-IDC-TrustedIdFed-Policy
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
            - Effect: Allow
              Action: ['sso-oauth:CreateTokenWithIAM']
              Resource: 
                - '*'
            - Effect: Allow
              Action: ['glue:CreateDatabase','glue:DeleteDatabase','glue:GetDatabase','glue:GetDatabases','glue:UpdateDatabase','glue:CreateTable','glue:DeleteTable','glue:BatchDeleteTable','glue:UpdateTable','glue:GetTable','glue:GetTables','glue:BatchCreatePartition','glue:CreatePartition','glue:DeletePartition','glue:BatchDeletePartition','glue:UpdatePartition','glue:GetPartition','glue:GetPartitions','glue:BatchGetPartition','lakeformation:GetDataAccess']
              Resource: 
                - '*'
            
            - Effect: Allow
              Action: ['s3:GetDataAccess','s3:GetAccessGrantsInstanceForPrefix']
              Resource: 
                - '*'
            
            - Effect: Allow
              Action: ['elasticmapreduce:ListInstances','elasticmapreduce:ListSteps','elasticmapreduce:DescribeCluster','elasticmapreduce:ListStudios','elasticmapreduce:ListEditors','elasticmapreduce:DescribeEditor','elasticmapreduce:AttachEditor','elasticmapreduce:CreateEditor','elasticmapreduce:DeleteEditor','elasticmapreduce:DetachEditor','elasticmapreduce:OpenEditorInConsole','elasticmapreduce:StartEditor','elasticmapreduce:StopEditor','elasticmapreduce:UpdateEditor','elasticmapreduce:ListClusters','elasticmapreduce:GetClusterSessionCredentials']
              Resource: 
                - '*'

            - Effect: Allow
              Action: ['s3:PutObject','s3:GetObject','s3:GetEncryptionConfiguration','s3:ListBucket','s3:DeleteObject']
              Resource: 
                - !Sub 'arn:aws:s3:::${S3BucketNameS3AccessGrants}*'
                - !Sub 'arn:aws:s3:::${S3BucketNameAthenaResultsLocationS3AccessGrants}/*'

  TIPRoleRedshift:
    Type: AWS::IAM::Role
    Condition: DeployRedshiftCondition
    Properties: 
      RoleName: !Sub 'UserRole_tipblog_redshift_${AWS::AccountId}'
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - redshift.amazonaws.com
                - redshift-serverless.amazonaws.com
            Action:
              - 'sts:AssumeRole'
              - 'sts:SetContext'
              - 'sts:SetSourceIdentity'
      Path: '/'
      Policies:      
        - PolicyName: redshift-idc-policy-1
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
            - Effect: Allow
              Action: ['redshift:DescribeQev2IdcApplications']
              Resource: 
                - '*'
            - Effect: Allow
              Action: ['sso:DescribeApplication','sso:DescribeInstance']
              Resource: 
                - '*'

        - PolicyName: TIPBlog-rs-glue-policy
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
            - Effect: Allow
              Action: ['glue:CreateDatabase','glue:DeleteDatabase','glue:GetDatabase','glue:GetDatabases','glue:UpdateDatabase','glue:CreateTable','glue:DeleteTable','glue:BatchDeleteTable','glue:UpdateTable','glue:GetTable','glue:GetTables','glue:BatchCreatePartition','glue:CreatePartition','glue:DeletePartition','glue:BatchDeletePartition','glue:UpdatePartition','glue:GetPartition','glue:GetPartitions','glue:BatchGetPartition']
              Resource: 
                - '*'

  TIPRoleQuickSight:
    Type: AWS::IAM::Role
    Condition: DeployRedshiftCondition
    Properties: 
      RoleName: !Sub 'UserRole_tipblog_quicksight_${AWS::AccountId}'
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - quicksight.amazonaws.com
            Action:
              - 'sts:AssumeRole'
              - 'sts:SetContext'
              - 'sts:SetSourceIdentity'
      Path: '/'
      Policies:
        - PolicyName: TIPBlog-rs-role
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
            - Effect: Allow
              Action: ['redshift:Describe*','ec2:CreateNetworkInterface','ec2:ModifyNetworkInterfaceAttribute','ec2:DeleteNetworkInterface','ec2:DescribeSubnets','ec2:DescribeSecurityGroups']
              Resource: 
                - '*'

  RedshiftQEPolicyPermissionSet:
    Type: AWS::IAM::ManagedPolicy
    Condition: DeployRedshiftCondition
    Properties:
      PolicyDocument: 
        Version: '2012-10-17'
        Statement:
        - Effect: Allow
          Action: ['redshift:DescribeQev2IdcApplications','redshift-serverless:ListWorkgroups','redshift-serverless:GetWorkgroup']
          Resource: 
            - '*'
        - Effect: Allow
          Action: ['sso:DescribeApplication','sso:DescribeInstance']
          Resource: 
            - '*'
      ManagedPolicyName: redshift-idc-policy-tip
      Path: "/"
     

  # RedshiftQEPermissionSet:
  #   Type: AWS::SSO:s:PermissionSet
  #   Condition: DeployRedshiftCondition
  #   DependsOn: RedshiftQEPolicyPermissionSet
  #   Properties:
  #     ManagedPolicies: ["AmazonRedshiftQueryEditorV2ReadSharing","redshift-idc-policy-tip"]
  #     InstanceArn: !Ref IAMIDCInstanceArn
  #     Name: tip-blog-qe-v2-permission-set

  
  # RedshiftQEUserAssignemnt:
  #   Type: AWS::SSO::Assignment
  #   Condition: DeployRedshiftCondition
  #   DependsOn: RedshiftQEPermissionSet
  #   Properties:
  #     InstanceArn: !Ref IAMIDCInstanceArn
  #     PermissionSetArn: !GetAtt RedshiftQEPermissionSet.Arn
  #     PrincipalId: !Ref IDCGroup3Id
  #     PrincipalType: GROUP
  #     TargetId: !Sub ${AWS::AccountId}
  #     TargetType: AWS_ACCOUNT

  EMRStudio:
    Type: AWS::EMR::Studio
    Condition: DeployStudioCondition
    Properties:
      Name: tip-blog-studio
      AuthMode: SSO
      IdcInstanceArn: !Ref IAMIDCInstanceArn
      IdcUserAssignment: OPTIONAL
      TrustedIdentityPropagationEnabled: true
      DefaultS3Location: !Sub "s3://${S3BucketNameForEMRWorkspaceStorage}/workspace"
      UserRole: !GetAtt TIPUserRole.Arn
      ServiceRole: !GetAtt EMRStudioServiceRole.Arn
      WorkspaceSecurityGroupId: !Ref EMRStudioWorkspaceSecurityGroup
      EngineSecurityGroupId: !Ref EMRStudioEngineSecurityGroup    
      SubnetIds:
        - !Ref PrivateSubnet
      VpcId: !Ref TIPVPC


  ##GLue Database
  GlueDatabase:
    Type: 'AWS::Glue::Database'
    Condition: DeployStudioCondition
    Properties:
      DatabaseInput:
        Name: 'oktank_tipblog_temp'
      CatalogId: !Sub ${AWS::AccountId}
  ## Customer Table 
  GlueTableCustomer:
    Type: 'AWS::Glue::Table'
    Condition: DeployStudioCondition
    DependsOn: GlueDatabase
    Properties:
      CatalogId: !Sub ${AWS::AccountId}
      DatabaseName: 'oktank_tipblog_temp'
      TableInput:
        Name: 'customer'
        TableType: EXTERNAL_TABLE
        Parameters: {
          "EXTERNAL": "TRUE",
          'skip.header.line.count': '1'
        } 
        StorageDescriptor:
          Columns:
            - Name: data_key
              Type: bigint
            - Name: data_load_date
              Type: string
            - Name: data_location
              Type: string
            - Name: customer_email
              Type: string
            - Name: customer_name
              Type: string
            - Name: comment1
              Type: string
            - Name: comment2
              Type: string
            # Add more columns as needed
          Location: !Sub 's3://${S3BucketNameLakeFormationGoverned}/data/'
          InputFormat: 'org.apache.hadoop.mapred.TextInputFormat'
          OutputFormat: 'org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat'
          SerdeInfo:
            SerializationLibrary: 'org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe'
            Parameters:
              'field.delim': ',' 

  
  ## LF Data Location Policy
  LFServiceRole:
    Type: AWS::IAM::Role
    Condition: DeployStudioCondition
    Properties: 
      RoleName: !Sub 'LFRole_tipblog_${AWS::AccountId}'
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - lakeformation.amazonaws.com
              # AWS:
              #   - !Sub "arn:aws:iam::${AWS::AccountId}:role/EMR_EC2_DefaultRole" --Check if this is needed
            Action:
              - 'sts:AssumeRole'
      Path: '/'
      Policies:
        - PolicyName: lf-s3-access
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
            - Effect: Allow
              Action: ['s3:PutObject','s3:GetObject','s3:DeleteObject','s3:ListBucket']
              Resource: 
                - !Sub 'arn:aws:s3:::${S3BucketNameLakeFormationGoverned}/*'
                - !Sub 'arn:aws:s3:::${S3BucketNameLakeFormationGoverned}'
  
  ## Register Data Location in LF
  RegisterDataLocation:
    Type: AWS::LakeFormation::Resource
    Condition: DeployStudioCondition
    DependsOn: LFServiceRole
    Properties:
      ResourceArn: !Sub arn:aws:s3:::${S3BucketNameLakeFormationGoverned}/data/
      RoleArn: !GetAtt LFServiceRole.Arn 
      UseServiceLinkedRole: false
      WithFederation: false

  ## Enable Application Integration 
  LFApplicationIntegration:
    Type: AWS::LakeFormation::DataLakeSettings
    Properties:
      AllowFullTableExternalDataAccess: true

  EMRSecConfig:
    Type: "AWS::EMR::SecurityConfiguration"
    Condition: DeployEMRCondition
    DependsOn: EMRStudio
    Properties:
      Name: "TIP-EMRSecurityConfig"
      SecurityConfiguration: {
        "AuthenticationConfiguration":{
          "IdentityCenterConfiguration":{
            "EnableIdentityCenter":true,
            "IdentityCenterApplicationAssigmentRequired":false,
            "IdentityCenterInstanceARN": !Ref IAMIDCInstanceArn,
            "IAMRoleForEMRIdentityCenterApplicationARN": !GetAtt TIPUserRole.Arn
            }
        },
        "AuthorizationConfiguration": {
          "LakeFormationConfiguration": {
            "EnableLakeFormation": true
          }
        },
        "EncryptionConfiguration": {
          "EnableInTransitEncryption": true,
          "EnableAtRestEncryption": false,
          "InTransitEncryptionConfiguration": {
            "TLSCertificateConfiguration": {
              "CertificateProviderType": "PEM",
              "S3Object": !Sub "s3://${SSlCertsS3BucketName}/${SSlCertsZip}"
            }
          }
        }
    }

  # EMR on EC2 Resources
  # - EMR Cluster
  # - Instance/Service roles with read/write access to artifacts bucket
  SparkCluster:
    Type: AWS::EMR::Cluster
    Condition: DeployEMRCondition    
    Properties:
      Name: EMRWithTIP
      ReleaseLabel: emr-7.0.0
      JobFlowRole: !Ref EMREC2InstanceRole
      ServiceRole: !GetAtt EMREC2ServiceRole.Arn
      SecurityConfiguration: !Ref EMRSecConfig
      Configurations:
           - Classification: emrfs-site
             ConfigurationProperties:
              fs.s3.s3AccessGrants.enabled: true
              fs.s3.s3AccessGrants.fallbackToIAM: false
      Applications:
        - Name: Livy
        - Name: Spark
        - Name: Hadoop
        - Name: JupyterEnterpriseGateway
      LogUri: !Sub s3://${S3BucketNameForEMRWorkspaceStorage}/logs/emr-ec2/
      AutoTerminationPolicy:
          IdleTimeout: 7200
      Instances:
        Ec2SubnetIds:
          - Ref: PrivateSubnet
        MasterInstanceGroup:
          InstanceCount: 1
          InstanceType: m5.2xlarge
          Market: ON_DEMAND
          Name: cfnMaster
        CoreInstanceGroup:
          InstanceCount: 1
          InstanceType: m5.2xlarge
          Market: ON_DEMAND
          Name: cfnCore
      Tags:
        - Key: for-use-with-amazon-emr-managed-policies
          Value: "true"
    DependsOn:
      - EMREC2InstanceProfile
      - EMRSecConfig
      - SubnetRouteTableAssociation
    UpdateReplacePolicy: Delete
    DeletionPolicy: Delete
  
  # The service role used by EMR
  EMREC2ServiceRole:
    Type: AWS::IAM::Role
    Condition: DeployEMRCondition
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Action: sts:AssumeRole
            Effect: Allow
            Principal:
              Service: elasticmapreduce.amazonaws.com
        Version: "2012-10-17"
      ManagedPolicyArns:
        - !Sub "arn:${AWS::Partition}:iam::aws:policy/service-role/AmazonEMRServicePolicy_v2"
      Policies:
        - PolicyName: ServiceRoleDefaultPolicy
          PolicyDocument:
            Statement:
                - Action: iam:PassRole
                  Condition:
                    StringEquals:
                      iam:PassedToService: ec2.amazonaws.com
                  Effect: Allow
                  Resource: !GetAtt EMREC2InstanceRole.Arn
            Version: "2012-10-17"

  # The instance role assumed by EMR EC2 instances
  # When using runtime roles, permissions are limited
  # - Access to write EMR logs
  # - Allow SSM
  EMREC2InstanceRole:
    Type: AWS::IAM::Role
    Condition: DeployEMRCondition
    Properties:
      AssumeRolePolicyDocument:
        Statement:
          - Action: sts:AssumeRole
            Effect: Allow
            Principal:
              Service: ec2.amazonaws.com
        Version: "2012-10-17"
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
      Policies:
        - PolicyName: WriteS3Logs
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Effect: Allow
                Action:
                  - "s3:PutObject"
                  - "s3:GetObject"
                  - "s3:DeleteObject"
                Resource:
                  - !Sub 'arn:aws:s3:::${S3BucketNameForEMRWorkspaceStorage}/logs/emr-ec2/*'
        - PolicyName: GetSSCerts
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Effect: Allow
                Action:
                  - "s3:GetObject"
                Resource:
                  - !Sub 'arn:aws:s3:::${SSlCertsS3BucketName}/*'
                  
  EMREC2InstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Condition: DeployEMRCondition
    Properties:
      InstanceProfileName:
        Ref: EMREC2InstanceRole
      Roles:
        - Ref: EMREC2InstanceRole

  S3AGInstance:
    Type: AWS::S3::AccessGrantsInstance
    Condition: CreateS3AGInstanceCondiiton
    Properties: 
      IdentityCenterArn: !Ref IAMIDCInstanceArn

  # Register location - Bucket from where EMR reads  
  S3AGLocationEMR:
    Type: AWS::S3::AccessGrantsLocation
    Condition: DeployEMRCondition
    Properties: 
      IamRoleArn: !GetAtt TIPUserRole.Arn
      LocationScope: !Sub s3://${S3BucketNameS3AccessGrants}/

  # Register location - Athena Results Location Bucket
  S3AGLocationAthenaQR:
    Type: AWS::S3::AccessGrantsLocation
    Condition: DeployAthenaCondition
    Properties: 
      IamRoleArn: !GetAtt TIPUserRole.Arn
      LocationScope: !Sub s3://${S3BucketNameAthenaResultsLocationS3AccessGrants}/

  # Access Grant - Athena Results Location Bucket
  S3AGLocationAthenaQRGrants:
    Type: AWS::S3::AccessGrant
    Condition: DeployAthenaCondition
    DependsOn: S3AGLocationAthenaQR
    Properties: 
      AccessGrantsLocationConfiguration:
        S3SubPrefix: !Sub ${IDCUser1Id}/*
      AccessGrantsLocationId: !GetAtt S3AGLocationAthenaQR.AccessGrantsLocationId
      Grantee: 
        GranteeIdentifier: !Ref IDCGroup1Id
        GranteeType: DIRECTORY_GROUP
      Permission: READWRITE

  #Access Grant - EMR S3AG Bucket for Input Data
  S3AGLocationEMRBucketGrantsInput:
    Type: AWS::S3::AccessGrant
    Condition: DeployEMRCondition
    DependsOn: S3AGLocationEMR
    Properties: 
      AccessGrantsLocationConfiguration:
        S3SubPrefix: "input*" 
      AccessGrantsLocationId: !GetAtt S3AGLocationEMR.AccessGrantsLocationId
      Grantee: 
        GranteeIdentifier: !Ref IDCGroup2Id
        GranteeType: DIRECTORY_GROUP
      Permission: READ


  #Access Grant - EMR S3AG Bucket for Output Data
  S3AGLocationEMRBucketGrantsOutput:
    Type: AWS::S3::AccessGrant
    Condition: DeployEMRCondition
    DependsOn: S3AGLocationEMR
    Properties: 
      AccessGrantsLocationConfiguration:
        S3SubPrefix: "output/*"
      AccessGrantsLocationId: !GetAtt S3AGLocationEMR.AccessGrantsLocationId
      Grantee: 
        GranteeIdentifier: !Ref IDCGroup2Id
        GranteeType: DIRECTORY_GROUP
      Permission: READWRITE

  ## RS Namespace
  RedshiftSrverlessNS:
    Type: AWS::RedshiftServerless::Namespace
    Condition: DeployRedshiftCondition
    Properties:
      AdminUsername: !Ref RedshiftServerlessAdminUserName
      AdminUserPassword: !Ref RedshiftServerlessAdminPassword
      DbName: !Ref RedshiftServerlessDatabase
      DefaultIamRoleArn: !GetAtt TIPRoleRedshift.Arn
      IamRoles: [!GetAtt TIPRoleRedshift.Arn]
      NamespaceName: !Sub redshift-idc-ns-tipblog-${AWS::AccountId}

  RedshiftSrverlessWG:
    Type: AWS::RedshiftServerless::Workgroup
    Condition: DeployRedshiftCondition
    DependsOn: RedshiftSrverlessNS
    Properties:
      NamespaceName: !Sub redshift-idc-ns-tipblog-${AWS::AccountId}
      PubliclyAccessible: false
      WorkgroupName: !Sub redshift-idc-wg-tipblog
      SecurityGroupIds: [!Ref RedshiftSecurityGroup]
      SubnetIds: [!Ref PrivateSubnet1, !Ref PrivateSubnet2, !Ref PrivateSubnet3]


Conditions:
  DeployAthenaCondition: !Equals [!Ref DeployAthenaFlow, "Yes"]
  DeployEMRCondition: !Equals [!Ref DeployEMRFlow, "Yes"]
  DeployRedshiftCondition: !Equals [!Ref DeployRedshiftQEV2Flow, "Yes"]
  DeployStudioCondition: !Or [!Equals [!Ref DeployAthenaFlow, "Yes"], !Equals [!Ref DeployEMRFlow,"Yes"]]
  CreateS3AGInstanceCondiiton: !Equals [!Ref CreateS3AGInstance, "Yes"]

Outputs:

  Cloud9URL:
    Description: Cloud9 Environment
    Value: Cloud9 is deprecated. Pleas use cloud shell from AWS management console to execute the commands.
      # Fn::Join:
      # - ''
      # - - !Sub https://${AWS::Region}.console.aws.amazon.com/cloud9/ide/
      #   - !Ref 'C9IDE'


  EMRStudioURL:
    Condition: DeployStudioCondition
    Description: EMR Studio Environment
    Value: !GetAtt EMRStudio.Url

  AthenaResultLocation:
    Condition: DeployAthenaCondition
    Description: Result Location for Amazon Athena
    Value: !Sub s3://${S3BucketNameAthenaResultsLocationS3AccessGrants}/

  S3AccessGrantInputpath:
    Condition: DeployAthenaCondition
    Description: Input data governed byS3 Acces Grants
    Value: !Sub s3://${S3BucketNameS3AccessGrants}/input/*

  IDCInstanceARN:
    Description: IDC instance ARN
    Value: !Ref IAMIDCInstanceArn

  TIPStudioRoleArn:
    Condition: DeployStudioCondition
    Description: Trusted IDentity Propagation Execution Role with EMR Studio
    Value: !GetAtt TIPUserRole.Arn

  TIPRedshiftRoleArn:
    Condition: DeployRedshiftCondition
    Description: Trusted IDentity Propagation Execution Role with Redshift
    Value: !GetAtt TIPRoleRedshift.Arn

  CatalogId:
    Description: Glue Default Catalog Id. AWS Account Number
    Value: !Sub ${AWS::AccountId}

  RedshiftNamespace:
    Condition: DeployRedshiftCondition
    Description: Created Redshift namespace
    Value: !GetAtt RedshiftSrverlessNS.Namespace.NamespaceName

  VPCId:
    Description: VPC Id Created
    Value: !Ref TIPVPC

  QSSecurityGroup:
    Condition: DeployRedshiftCondition
    Description: QuickSight Security Grou
    Value: !Ref QSSecurityGroup

  RoleQuickSight:
    Condition: DeployRedshiftCondition
    Description: QuickSight IAM Role to be used for creating VPC connection
    Value: !Ref TIPRoleQuickSight

  RedshiftSrverlessWorkgroup:
    Condition: DeployRedshiftCondition
    Description: Redshift Workgroup
    Value: !GetAtt RedshiftSrverlessWG.Workgroup.Endpoint.Address