AWSTemplateFormatVersion: '2010-09-09'
Description: CloudFormation template for AWS resources - Glue, Athena, IAM roles, and users

Parameters:
  ArtifactsS3BucketName:
    Type: String
    Description: Name of the S3 bucket which will be created by CloudFormation. This bucket  will be used for storing the dummy data,Glue scripts and Athena Results under respective folders.  
 
  UserCategory1Password:
    Type: String
    NoEcho: true
    Description: Password to be used by User1 for AWS console login and execute queries on Athena. Minimum of 8 characters
  UserCategory2Password:
    Type: String
    NoEcho: true
    Description: Password to be used by User2 for AWS console login and execute queries on Athena. Minimum of 8 characters
  UserCategory3Password:
    Type: String
    NoEcho: true
    Description: Password to be used by User3 for AWS console login and execute queries on Athena. Minimum of 8 characters

Resources:

  # Artifacts Bucket Creation and copy artifacts
  ArtifactsS3BucketNameResource:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Ref ArtifactsS3BucketName

  LambdaExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: lambda.amazonaws.com
            Action: sts:AssumeRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
      Policies:
        - PolicyName: CopyObjectPolicy
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - s3:ListBucket
                  - s3:GetBucketLocation
                Resource:
                  - !Sub "arn:aws:s3:::${ArtifactsS3BucketName}"
              - Effect: Allow
                Action:
                  - s3:GetObject
                  - s3:PutObject
                  - s3:DeleteObject
                  - s3:ListObjects
                  - s3:PutObjectAcl
                  - s3:GetObjectAcl
                Resource:
                  - !Sub "arn:aws:s3:::${ArtifactsS3BucketName}/*"
              - Effect: Allow
                Action:
                  - s3:GetObject
                Resource:
                  - "arn:aws:s3:::aws-blogs-artifacts-public/*"

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

          def lambda_handler(event, context):
            source_bucket = 'aws-blogs-artifacts-public'
            destination_bucket = os.environ['ArtifactsS3BucketName']
            the_event = event['RequestType']

            try:
              print("Starting to copy.")
              if the_event in ('Create', 'Update'):
                object_key = 'artifacts/BDB-3528/scripts/Data_Quality_PII_Checker.py'
                copy_params = {
                    'Bucket': destination_bucket,
                    'CopySource': {'Bucket': source_bucket, 'Key': object_key},
                    'Key': "scripts/Data_Quality_PII_Checker.py"
                }
                s3.copy_object(**copy_params)
                print(f"Successfully copied {object_key} from {source_bucket} to {destination_bucket}.")

                object_key = 'artifacts/BDB-3528/scripts/LF-Tag-Handler.py'
                copy_params = {
                    'Bucket': destination_bucket,
                    'CopySource': {'Bucket': source_bucket, 'Key': object_key},
                    'Key': "scripts/LF-Tag-Handler.py"
                }
                s3.copy_object(**copy_params)
                print(f"Successfully copied {object_key} from {source_bucket} to {destination_bucket}.")

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

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

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

                object_key = 'artifacts/BDB-3528/data/customer-v1/cust_feedback_v1_fixed.csv'
                copy_params = {
                    'Bucket': destination_bucket,
                    'CopySource': {'Bucket': source_bucket, 'Key': object_key},
                    'Key': 'data-v1/cust_feedback_v1_fixed.csv'
                }
                s3.copy_object(**copy_params)
                print(f"Successfully copied {object_key} from {source_bucket} to {destination_bucket}.")
              elif the_event == 'Delete':
                print("Deleting S3 content...")
                b_operator = boto3.resource('s3')
                b_operator.Bucket(str(destination_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: 120
      Role: !GetAtt LambdaExecutionRole.Arn
      Environment:
        Variables:
          ArtifactsS3BucketName: !Ref ArtifactsS3BucketName
          
  s3CustomResource:
    Type: Custom::S3CustomResource
    DependsOn: LambdaExecutionRole
    Version: "1.0"
    Properties:
      ServiceToken: !GetAtt CopyLambdaFunction.Arn

  cleanupBucketOnDelete:
     Type: Custom::cleanupbucket
     DependsOn: 
      - CopyLambdaFunction
      - ArtifactsS3BucketNameResource
     Properties:
       ServiceToken: !GetAtt CopyLambdaFunction.Arn


  # Glue Service DQ Role
  GlueServiceDQRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: [glue.amazonaws.com]
            Action: ['sts:AssumeRole']
      Path: '/'
      Policies:
        - PolicyName: GlueServiceDQPolicy
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action: [ 'glue:PublishDataQuality']
                Resource: 
                  - !Sub 'arn:aws:glue:*:${AWS::AccountId}:dataQualityRuleset/DataQuality_BasicChecks'
                  - !Sub 'arn:aws:glue:*:${AWS::AccountId}:dataQualityRuleset/DataQuality_PIIColumns'
              - Effect: Allow
                Action: [ 'glue:GetDatabase', 'glue:GetTables', 'glue:GetTable','glue:GetPartitions', 'glue:GetPartition']
                Resource:
                  - !Sub 'arn:aws:glue:*:${AWS::AccountId}:catalog'
                  - !Sub 'arn:aws:glue:*:${AWS::AccountId}:database/oktank_autogov_temp'
                  - !Sub 'arn:aws:glue:*:${AWS::AccountId}:table/oktank_autogov_temp/*'
              - Effect: Allow
                Action: [ 'lakeformation:GetDataAccess','glue:BatchGetCustomEntityTypes','glue:GetCustomEntityType']
                Resource: '*'
              - Effect: Allow
                Action: ['s3:GetObject','s3:PutObject','s3:ListBucket']
                Resource: 
                  - !Sub 'arn:aws:s3:::${ArtifactsS3BucketName}/*'
                  - !Sub 'arn:aws:s3:::${ArtifactsS3BucketName}'
              - Effect: Allow
                Action: ['logs:CreateLogGroup','logs:CreateLogStream','logs:PutLogEvents'] 
                Resource: 'arn:aws:logs:*:*:*'
              - Effect: Allow
                Action: ['cloudwatch:PutMetricData'] 
                Resource: '*'


  # Glue Service LF Tagger Role
  GlueServiceLFTaggerRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: [glue.amazonaws.com]
            Action: ['sts:AssumeRole']
      Path: '/'
      Policies:
        - PolicyName: GlueServiceLFTaggerPolicy
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action: [ 'glue:GetDataQualityResult']
                Resource: 
                  - !Sub 'arn:aws:glue:*:${AWS::AccountId}:dataQualityRuleset/DataQuality_BasicChecks'
                  - !Sub 'arn:aws:glue:*:${AWS::AccountId}:dataQualityRuleset/DataQuality_PIIColumns'
              - Effect: Allow
                Action: [ 'glue:GetDatabase','glue:GetTable']
                Resource:
                  - !Sub 'arn:aws:glue:*:${AWS::AccountId}:catalog'
                  - !Sub 'arn:aws:glue:*:${AWS::AccountId}:database/oktank_autogov_temp'
                  - !Sub 'arn:aws:glue:*:${AWS::AccountId}:table/oktank_autogov_temp/*'
              - Effect: Allow
                Action: [ 'lakeformation:DescribeResource','lakeformation:GetResourceLFTags','lakeformation:AddLFTagsToResource','lakeformation:RemoveLFTagsFromResource','glue:ListDataQualityResults']
                Resource: '*'
              - Effect: Allow
                Action: ['s3:GetObject','s3:ListBucket']
                Resource: 
                  - !Sub 'arn:aws:s3:::${ArtifactsS3BucketName}/*'
                  - !Sub 'arn:aws:s3:::${ArtifactsS3BucketName}'
              - Effect: Allow
                Action: ['logs:CreateLogGroup','logs:CreateLogStream','logs:PutLogEvents'] 
                Resource: 'arn:aws:logs:*:*:*'

  # Role for State machine to trigger glue jobs
  StepFunctionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: [states.amazonaws.com]
            Action: ['sts:AssumeRole']
      Path: '/'
      Policies:
        - PolicyName: GlueServicePolicy
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action: [ 'glue:StartJobRun','glue:GetJobRuns', 'glue:GetJobRun']
                Resource:
                  - !Sub 'arn:aws:glue:*:${AWS::AccountId}:job/Data-Quality-PII-Checker_Job'
                  - !Sub 'arn:aws:glue:*:${AWS::AccountId}:job/LF-Tag-Handler_Job'
  
  # Users
  
                
  DLUser1:
    Type: AWS::IAM::User
    Properties:
      LoginProfile:
        Password: !Ref UserCategory1Password
        PasswordResetRequired: False
      Policies:
        - PolicyName: DLUser1LFDataAccess
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action: ['lakeformation:GetDataAccess']
                Resource: '*'

        - PolicyName: StateMachineAccess
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action: ['states:ListStateMachines','states:ListActivities','states:ListExecutions','states:DescribeStateMachineForExecution','states:GetExecutionHistory','states:DescribeExecution']
                Resource: '*'
              - Effect: Allow
                Action: ['states:DescribeActivity','states:DescribeStateMachine','states:StopExecution','states:StartSyncExecution','states:DescribeStateMachineForExecution','states:DescribeExecution','states:GetExecutionHistory','states:StartExecution','states:GetActivityTask']
                Resource: !Sub 'arn:aws:states:*:${AWS::AccountId}:stateMachine:AutoGovMachine'  
                  
        - PolicyName: DLUser1GluePolicy
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action: ['glue:GetTable','glue:GetTables','glue:GetDatabase','glue:GetDatabases']
                Resource: 
                  - !Sub 'arn:aws:glue:*:${AWS::AccountId}:catalog'
                  - !Sub 'arn:aws:glue:*:${AWS::AccountId}:database/oktank_autogov_temp'
                  - !Sub 'arn:aws:glue:*:${AWS::AccountId}:table/oktank_autogov_temp/*'

        - PolicyName: DLUser1Policy
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action: ['athena:GetWorkGroup','athena:StartQueryExecution','athena:GetQueryExecution','athena:GetQueryResults']
                Resource: !Sub 'arn:aws:athena:*:${AWS::AccountId}:workgroup/auto_gov_blog_workgroup_temporary_user1'
              - Effect: Allow
                Action: ['athena:ListWorkGroups']
                Resource: '*'
        - PolicyName: AthenaResultLocationPolicy
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - s3:GetBucketLocation
                  - s3:ListBucket
                Resource: !Sub 'arn:aws:s3:::${ArtifactsS3BucketName}'
              - Effect: Allow
                Action:
                  - s3:GetObject
                  - s3:PutObject
                Resource: !Sub 'arn:aws:s3:::${ArtifactsS3BucketName}/athena-results/user1/*'

  DLUser2:
    Type: AWS::IAM::User
    Properties:
      LoginProfile:
        Password: !Ref UserCategory2Password
        PasswordResetRequired: False
      Policies:
        - PolicyName: DLUser2LFDataAccess
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action: ['lakeformation:GetDataAccess']
                Resource: '*'
        - PolicyName: StateMachineAccess
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action: ['states:ListStateMachines','states:ListActivities','states:ListExecutions','states:DescribeStateMachineForExecution','states:GetExecutionHistory','states:DescribeExecution']
                Resource: '*'
              - Effect: Allow
                Action: ['states:DescribeActivity','states:DescribeStateMachine','states:StopExecution','states:StartSyncExecution','states:DescribeStateMachineForExecution','states:DescribeExecution','states:GetExecutionHistory','states:StartExecution','states:GetActivityTask']
                Resource: !Sub 'arn:aws:states:*:${AWS::AccountId}:stateMachine:AutoGovMachine'   
        - PolicyName: DLUser2GluePolicy
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action: ['glue:GetTable','glue:GetTables','glue:GetDatabase','glue:GetDatabases']
                Resource: 
                  - !Sub 'arn:aws:glue:*:${AWS::AccountId}:catalog'
                  - !Sub 'arn:aws:glue:*:${AWS::AccountId}:database/oktank_autogov_temp'
                  - !Sub 'arn:aws:glue:*:${AWS::AccountId}:table/oktank_autogov_temp/*'
        - PolicyName: DLUser2Policy
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action: ['athena:GetWorkGroup','athena:StartQueryExecution','athena:GetQueryExecution','athena:GetQueryResults']
                Resource: !Sub 'arn:aws:athena:*:${AWS::AccountId}:workgroup/auto_gov_blog_workgroup_temporary_user2'
              - Effect: Allow
                Action: ['athena:ListWorkGroups']
                Resource: '*'
        - PolicyName: AthenaResultLocationPolicy
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - s3:GetBucketLocation
                  - s3:ListBucket
                Resource: !Sub 'arn:aws:s3:::${ArtifactsS3BucketName}'
              - Effect: Allow
                Action:
                  - s3:GetObject
                  - s3:PutObject
                Resource: !Sub 'arn:aws:s3:::${ArtifactsS3BucketName}/athena-results/user2/*'

  DLUser3:
    Type: AWS::IAM::User
    Properties:
      LoginProfile:
        Password: !Ref UserCategory3Password
        PasswordResetRequired: False
      Policies:
        - PolicyName: DLUser3LFDataAccess
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action: ['lakeformation:GetDataAccess']
                Resource: '*'
        - PolicyName: StateMachineAccess
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action: ['states:ListStateMachines','states:ListActivities','states:ListExecutions','states:DescribeStateMachineForExecution','states:GetExecutionHistory','states:DescribeExecution']
                Resource: '*'
              - Effect: Allow
                Action: ['states:DescribeActivity','states:DescribeStateMachine','states:StopExecution','states:StartSyncExecution','states:DescribeStateMachineForExecution','states:DescribeExecution','states:GetExecutionHistory','states:StartExecution','states:GetActivityTask']
                Resource: !Sub 'arn:aws:states:*:${AWS::AccountId}:stateMachine:AutoGovMachine'   
        - PolicyName: DLUser3GluePolicy
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action: ['glue:GetTable','glue:GetTables','glue:GetDatabase','glue:GetDatabases']
                Resource: 
                  - !Sub 'arn:aws:glue:*:${AWS::AccountId}:catalog'
                  - !Sub 'arn:aws:glue:*:${AWS::AccountId}:database/oktank_autogov_temp'
                  - !Sub 'arn:aws:glue:*:${AWS::AccountId}:table/oktank_autogov_temp/*'
        - PolicyName: DLUser3Policy
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action: ['athena:GetWorkGroup','athena:StartQueryExecution','athena:GetQueryExecution','athena:GetQueryResults']
                Resource: !Sub 'arn:aws:athena:*:${AWS::AccountId}:workgroup/auto_gov_blog_workgroup_temporary_user3'
              - Effect: Allow
                Action: ['athena:ListWorkGroups']
                Resource: '*'
          
        - PolicyName: AthenaResultLocationPolicy
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - s3:GetBucketLocation
                  - s3:ListBucket
                Resource: !Sub 'arn:aws:s3:::${ArtifactsS3BucketName}'
              - Effect: Allow
                Action:
                  - s3:GetObject
                  - s3:PutObject
                Resource: !Sub 'arn:aws:s3:::${ArtifactsS3BucketName}/athena-results/user3/*'

  ## Athena Workgroup
  AthenaWorkgroup1:
    Type: 'AWS::Athena::WorkGroup'
    Properties:
      Name: 'auto_gov_blog_workgroup_temporary_user1'
      Description: 'Athena Workgroup'
      State: ENABLED
      RecursiveDeleteOption: true
      WorkGroupConfiguration:
        ResultConfiguration:
          OutputLocation: !Sub 's3://${ArtifactsS3BucketName}/athena-results/user1' 

  ## Athena Workgroup
  AthenaWorkgroup2:
    Type: 'AWS::Athena::WorkGroup'
    Properties:
      Name: 'auto_gov_blog_workgroup_temporary_user2'
      Description: 'Athena Workgroup'
      State: ENABLED
      RecursiveDeleteOption: true
      WorkGroupConfiguration:
        ResultConfiguration:
          OutputLocation: !Sub 's3://${ArtifactsS3BucketName}/athena-results/user2'

  ## Athena Workgroup
  AthenaWorkgroup3:
    Type: 'AWS::Athena::WorkGroup'
    Properties:
      Name: 'auto_gov_blog_workgroup_temporary_user3'
      Description: 'Athena Workgroup'
      State: ENABLED
      RecursiveDeleteOption: true
      WorkGroupConfiguration:
        ResultConfiguration:
          OutputLocation: !Sub 's3://${ArtifactsS3BucketName}/athena-results/user3'
  
  
  
  ##GLue Database
  GlueDatabase:
    Type: 'AWS::Glue::Database'
    Properties:
      DatabaseInput:
        Name: 'oktank_autogov_temp'
      CatalogId: !Sub ${AWS::AccountId}
  ## Customer Table 
  GlueTableCustomer:
    Type: 'AWS::Glue::Table'
    DependsOn: GlueDatabase
    Properties:
      CatalogId: !Sub ${AWS::AccountId}
      DatabaseName: 'oktank_autogov_temp'
      TableInput:
        Name: 'customer'
        Description: 'Your table description (optional)'
        Parameters:
          '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://${ArtifactsS3BucketName}/data/customer/'
          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': ',' 

  ##Base table which is used for Referential check as part of basic DQ rules.
  GlueTableBase:
    Type: 'AWS::Glue::Table'
    DependsOn: GlueDatabase
    Properties:
      CatalogId: !Sub ${AWS::AccountId}
      DatabaseName: 'oktank_autogov_temp'
      TableInput:
        Name: 'base'
        Description: 'Your table description (optional)'
        Parameters:
          'skip.header.line.count': '1' 
        StorageDescriptor:
          Columns:
            - Name: data_key
              Type: bigint
            - Name: data_load_date
              Type: string
            - Name: data_location
              Type: string
            # Add more columns as needed
          Location: !Sub 's3://${ArtifactsS3BucketName}/data/base'
          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': ',' 
  
  
  # Glue Jobs
  GlueJob1:
    Type: AWS::Glue::Job
    Properties:
      Name: Data-Quality-PII-Checker_Job
      Role: !GetAtt GlueServiceDQRole.Arn
      Command:
        Name: glueetl
        ScriptLocation: !Sub 's3://${ArtifactsS3BucketName}/scripts/Data_Quality_PII_Checker.py'
      DefaultArguments:
        '--job-bookmark-option': 'job-bookmark-disable'
        '--additional-python-modules': 'boto3==1.28.3'
      GlueVersion: 3.0
        
  GlueJob2:
    Type: AWS::Glue::Job
    Properties:
      Name: LF-Tag-Handler_Job
      Role: !GetAtt GlueServiceLFTaggerRole.Arn
      Command:
        Name: pythonshell
        PythonVersion: 3.9
        ScriptLocation: !Sub 's3://${ArtifactsS3BucketName}/scripts/LF-Tag-Handler.py'
      DefaultArguments:
        '--job-bookmark-option': 'job-bookmark-disable'
        '--additional-python-modules': 'boto3==1.28.3'
    

  AutoGovMachine:
    Type: AWS::StepFunctions::StateMachine
    Properties:
      StateMachineName: AutoGovMachine
      DefinitionString:
        Fn::Sub: |
          {
            "Comment": "State Machine for automated governance",
            "StartAt": "CheckDataQuality",
            "States": {
              "CheckDataQuality": {
                "Type": "Task",
                "Resource": "arn:aws:states:::glue:startJobRun.sync",
                "Parameters": {
                  "JobName": "Data-Quality-PII-Checker_Job",
                  "Arguments": {
                    "--bucket_name.$": "$.BucketName"
                  }
                },
                "Next": "ApplyTags"
              },
              "ApplyTags": {
                "Type": "Task",
                "Resource": "arn:aws:states:::glue:startJobRun.sync",
                "Parameters": {
                  "JobName": "LF-Tag-Handler_Job",
                  "Arguments": {
                    "--job-id.$": "$.Id",
                    "--job-name.$": "$.JobName",
                    "--bucket_name.$": "$.Arguments.--bucket_name"
                  }
                },
                "End": true
              }
            }
          }
      RoleArn: !GetAtt StepFunctionRole.Arn

  ## Register Data Location
  RegisterDataLocation:
    Type: AWS::LakeFormation::Resource
    Properties:
      ResourceArn: !Sub arn:aws:s3:::${ArtifactsS3BucketName}/data/
      RoleArn: !Sub arn:aws:iam::${AWS::AccountId}:role/aws-service-role/lakeformation.amazonaws.com/AWSServiceRoleForLakeFormationDataAccess
      UseServiceLinkedRole: true
      WithFederation: false

  ## Creating Tags
  DQTag:
    Type: AWS::LakeFormation::Tag
    Properties:
      TagKey: "dq_tag"
      TagValues:
        - "DQ90"
        - "DQ100"
        - "DQL_LT_50"
        - "DQ50_80"
        - "DQ80_90"
  
  TBLTag:
    Type: AWS::LakeFormation::Tag
    Properties:
      TagKey: "tbl_class"
      TagValues:
        - "public"
        - "sensitive"

  ColTag:
    Type: AWS::LakeFormation::Tag
    Properties:
      TagKey: "col_class"
      TagValues:
        - "sensitive"
        - "public"            
            



## Granting Permission to GlueDQJobRole to read all tables under oktank_autogov_temp database
  GlueDQJobPermission:
    Type: AWS::LakeFormation::PrincipalPermissions
    Properties:
      Principal:
        DataLakePrincipalIdentifier: !GetAtt GlueServiceDQRole.Arn
      Resource:
        Table:
          CatalogId: !Sub ${AWS::AccountId}
          DatabaseName: "oktank_autogov_temp"
          TableWildcard: { }
      Permissions:
        - "SELECT"
      PermissionsWithGrantOption:
        - "SELECT"
                  
## Granting Permission to LFTaggerRole to apply the tags on the tables
 
  LFTagTablesPermission:
    Type: AWS::LakeFormation::PrincipalPermissions
    Properties:
      Principal:
        DataLakePrincipalIdentifier: !GetAtt GlueServiceLFTaggerRole.Arn
      Resource:
        Table:
          CatalogId: !Sub ${AWS::AccountId}
          DatabaseName: "oktank_autogov_temp"
          TableWildcard: { }
      Permissions:
        - "DESCRIBE"
        - "ALTER"
        - "DROP"
        - "INSERT"
        - "SELECT"
        - "DELETE"
      PermissionsWithGrantOption:
        - "DESCRIBE"
        - "ALTER"
        - "DROP"
        - "INSERT"
        - "SELECT"
        - "DELETE"

  COLCLASSLFTagPermission:
    Type: AWS::LakeFormation::PrincipalPermissions
    Properties:
      Principal:
        DataLakePrincipalIdentifier: !GetAtt GlueServiceLFTaggerRole.Arn
      Resource:
        LFTag:
          CatalogId: !Sub ${AWS::AccountId}
          TagKey: "col_class"
          TagValues:
            - "sensitive"
            - "public"
      Permissions:
        - "ASSOCIATE"
        - "DESCRIBE"
      PermissionsWithGrantOption:
        - "ASSOCIATE"  
        - "DESCRIBE"

  TBLCLASSLFTagPermission:
    Type: AWS::LakeFormation::PrincipalPermissions
    Properties:
      Principal:
        DataLakePrincipalIdentifier: !GetAtt GlueServiceLFTaggerRole.Arn
      Resource:
        LFTag:
          CatalogId: !Sub ${AWS::AccountId}
          TagKey: "tbl_class"
          TagValues:
            - "sensitive"
            - "public"
      Permissions:
        - "ASSOCIATE"
        - "DESCRIBE"
      PermissionsWithGrantOption:
        - "ASSOCIATE" 
        - "DESCRIBE" 

  DQCLASSLFTagPermission:
    Type: AWS::LakeFormation::PrincipalPermissions
    Properties:
      Principal:
        DataLakePrincipalIdentifier: !GetAtt GlueServiceLFTaggerRole.Arn
      Resource:
        LFTag:
          CatalogId: !Sub ${AWS::AccountId}
          TagKey: "dq_tag"
          TagValues:
            - "DQ90"
            - "DQ100"
            - "DQL_LT_50"
            - "DQ50_80"
            - "DQ80_90"
      Permissions:
        - "ASSOCIATE"
        - "DESCRIBE"
      PermissionsWithGrantOption:
        - "ASSOCIATE"
        - "DESCRIBE"    

Outputs:
  
  UserCategory1:
    Value: !Ref DLUser1
    Description: Data Lake user corresponding to category 1 user. Can access senstitive data but need 100% accurate Data
  UserCategory2:
    Value: !Ref DLUser2
    Description: Data Lake user corresponding to category 2 user. Cannot access senstitive columns in the table. Needs >75% accurate Data
  UserCategory3:
    Value: !Ref DLUser3
    Description: Data Lake user corresponding to category 3 user. Cannot access table containing sensitive data. Data Quality can be 0%.
  StepFunctionName:
    Value: !Ref AutoGovMachine
    Description: Step Function
  AthenaWorkgroupNameUser1:
    Value: !Ref AthenaWorkgroup1
    Description: Athena Workgroup Name For User1. Switch to this workgroup to run  Athena queries for User 1 for this post.
  AthenaWorkgroupNameUser2:
    Value: !Ref AthenaWorkgroup2
    Description: Athena Workgroup Name For User1. Switch to this workgroup to run  Athena queries for User 1 for this post.
  AthenaWorkgroupNameUser3:
    Value: !Ref AthenaWorkgroup3
    Description: Athena Workgroup Name For User1. Switch to this workgroup to run  Athena queries for User 1 for this post.
  S3DataLocation:
    Value: !Sub 's3://${ArtifactsS3BucketName}/data'
    Description: Data Location.This location is managed by Lake Formation.
  S3ScriptLocation:
    Value: !Sub 's3://${ArtifactsS3BucketName}/scripts'
    Description: Glue scripts are available in this location.
  S3BucketName:
    Value: !Sub '${ArtifactsS3BucketName}'
    Description: S3 Bucket name.