######### Apache License ########################################
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.

# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
# the Software, and to permit persons to whom the Software is furnished to do so.

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


#################################################################################

AWSTemplateFormatVersion: '2010-09-09'
Description: Creates resources  for agentic Quality review blog

################# parameter groups ###############################

Metadata:
   AWS::CloudFormation::Interface:
    ParameterGroups:
      - Label:
          default: "dynamodb resources"
        Parameters:
          - DynamoDBTableName
      - Label:
          default: "Email Configuration"
        Parameters:
          - Fromemailaddress
          - Toemailaddress

################ parameters ####################################         

Parameters:

  DynamoDBTableName:
    Type: String
    Default: Deviceclassifications
    Description: Name of the DynamoDB table

  # Email Configuration
  Toemailaddress:
    Type: String
    Default: "abc@gmail.com"
    AllowedPattern: '[^@]+@[^@]+\.[^@]+'
    Description: Email address to receive email
   
  Fromemailaddress:
    Type: String
    Default: "xyz@gmail.com"
    AllowedPattern: '[^@]+@[^@]+\.[^@]+'
    Description: Email address to send email

  AppianHostEndpoint:
    Type: String
    Description: Host endpoint of the Appian instance

  AppianAPIKey:
    Type: String
    Description: API Key of the Appian instance   


  

###########################################################################################################
############## RESOURCES ##############
###########################################################################################################

Resources:

##################### Encryption key ############################


  MyKMSKey:
    Type: AWS::KMS::Key
    Properties:
      Description: KMS key for S3 bucket encryption and VPC Flow Logs
      EnableKeyRotation: true
      KeyPolicy:
        Version: '2012-10-17'
        Id: key-default-1
        Statement:        
          - Sid: Enable IAM User Permissions
            Effect: Allow
            Principal:
              AWS: !Sub 'arn:aws:iam::${AWS::AccountId}:root'
            Action: 'kms:*'
            Resource: '*'
          - Sid: AllowCloudWatchLogs
            Effect: Allow
            Principal:
              Service: !Sub 'logs.${AWS::Region}.amazonaws.com'
            Action:
              - kms:Encrypt*
              - kms:Decrypt*
              - kms:ReEncrypt*
              - kms:GenerateDataKey*
              - kms:Describe*
            Resource: '*'
          - Sid: AllowQBusinessService
            Effect: Allow
            Principal:
              Service:
                - qbusiness.amazonaws.com
                - kendra.amazonaws.com
                - secretsmanager.amazonaws.com
                - lambda.amazonaws.com
            Action:
              - kms:Decrypt
              - kms:GenerateDataKey
              - kms:DescribeKey
            Resource: '*'



################# VPC for hosting Lambda  #######################


  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/16
      EnableDnsHostnames: true
      EnableDnsSupport: true
      Tags:
        - Key: Name
          Value: !Sub ${AWS::StackName}-VPC

  VPCFlowLogsRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: vpc-flow-logs.amazonaws.com
            Action: sts:AssumeRole
      Policies:
        - PolicyName: FlowLogsPolicy
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - logs:CreateLogGroup
                  - logs:CreateLogStream
                  - logs:PutLogEvents
                  - logs:DescribeLogGroups
                  - logs:DescribeLogStreams
                Resource: !Sub arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:${AWS::StackName}-VPCFlowLogs:*

  VPCFlowLogsGroup:
    Type: AWS::Logs::LogGroup
    Properties:
      LogGroupName: !Sub ${AWS::StackName}-VPCFlowLogs
      RetentionInDays: 30
      KmsKeyId: !GetAtt MyKMSKey.Arn

  VPCFlowLog:
    Type: AWS::EC2::FlowLog
    Properties:
      DeliverLogsPermissionArn: !GetAtt VPCFlowLogsRole.Arn
      LogGroupName: !Ref VPCFlowLogsGroup
      ResourceId: !Ref VPC
      ResourceType: VPC
      TrafficType: ALL
      MaxAggregationInterval: 60
      Tags:
        - Key: Name
          Value: !Sub ${AWS::StackName}-VPCFlowLog

  PrivateSubnet1:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      CidrBlock: 10.0.1.0/24
      AvailabilityZone: !Select [0, !GetAZs '']
      Tags:
        - Key: Name
          Value: !Sub ${AWS::StackName}-PrivateSubnet1

  PrivateSubnet2:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      CidrBlock: 10.0.2.0/24
      AvailabilityZone: !Select [1, !GetAZs '']
      Tags:
        - Key: Name
          Value: !Sub ${AWS::StackName}-PrivateSubnet2

  LambdaSecurityGroup:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Security group for Lambda function
      VpcId: !Ref VPC
      SecurityGroupEgress:
         - IpProtocol: tcp
           FromPort: 587
           ToPort: 587
           CidrIp: 0.0.0.0/0
           Description: "Allow SMTP traffic to SES through NAT Gateway"
         - IpProtocol: tcp
           FromPort: 465
           ToPort: 465
           CidrIp: 0.0.0.0/0
           Description: "Allow SMTPS traffic to SES through NAT Gateway"
         - IpProtocol: tcp
           FromPort: 443
           ToPort: 443
           CidrIp: 0.0.0.0/0
           Description: "Allow HTTPS traffic to AWS services through NAT Gateway"
      Tags:
        - Key: Name
          Value: !Sub ${AWS::StackName}-Lambda-SG

  InternetGateway:
    Type: AWS::EC2::InternetGateway

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

  PublicSubnet1:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      CidrBlock: 10.0.3.0/24
      AvailabilityZone: !Select [0, !GetAZs '']
      Tags:
        - Key: Name
          Value: !Sub ${AWS::StackName}-PublicSubnet1

  NatGatewayEIP:
    Type: AWS::EC2::EIP
    DependsOn: AttachGateway
    Properties:
      Domain: vpc

  NatGateway:
    Type: AWS::EC2::NatGateway
    Properties:
      AllocationId: !GetAtt NatGatewayEIP.AllocationId
      SubnetId: !Ref PublicSubnet1

  PublicRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: !Sub ${AWS::StackName}-Public

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

  PublicSubnet1RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PublicSubnet1
      RouteTableId: !Ref PublicRouteTable

  PrivateRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: !Sub ${AWS::StackName}-Private

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

  PrivateSubnet1RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PrivateSubnet1
      RouteTableId: !Ref PrivateRouteTable

  PrivateSubnet2RouteTableAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PrivateSubnet2
      RouteTableId: !Ref PrivateRouteTable

######################## Gateway endpoints for Amazon S3 and Amazon DynamoDB

#gateway endpoint for S3
  S3GatewayEndpoint:
    Type: 'AWS::EC2::VPCEndpoint'
    Properties:
      VpcEndpointType: Gateway
      VpcId: !Ref VPC
      ServiceName: !Sub 'com.amazonaws.${AWS::Region}.s3'
      PolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal: '*'
            Action:
              - 's3:*'
            Resource: '*'
      

  # gateway endpoint for dynamodb
  DynamoDBGatewayEndpoint:
    Type: 'AWS::EC2::VPCEndpoint'
    Properties:
      VpcEndpointType: Gateway
      VpcId: !Ref VPC
      ServiceName: !Sub 'com.amazonaws.${AWS::Region}.dynamodb'
      PolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal: '*'
            Action:
                - 'dynamodb:Query'
                - 'dynamodb:DescribeTable'
                - 'dynamodb:GetItem'
                - 'dynamodb:PutItem'
                - 'dynamodb:UpdateItem'
                - 'dynamodb:DeleteItem'
                - 'dynamodb:Scan'
                - 'dynamodb:BatchGetItem'
                - 'dynamodb:BatchWriteItem'
            Resource: 
                - !Sub 'arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/${DynamoDBTableName}'
                - !Sub 'arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/${DynamoDBTableName}/*'
      
  


########## Secrets Manager resources ############

  APIKeySecret:
    Type: 'AWS::SecretsManager::Secret'
    Properties:
      Name: 'AppianAPIKey'
      Description: 'This is a secret created by CloudFormation'
      SecretString: !Ref AppianAPIKey
      KmsKeyId: !Ref MyKMSKey

  HostEndpointSecret:
    Type: 'AWS::SecretsManager::Secret'
    Properties:
      Name: 'AppianHostEndpoint'
      Description: 'This is a secret created by CloudFormation'
      SecretString: !Ref AppianHostEndpoint  
      KmsKeyId: !Ref MyKMSKey


########################## Amazon SES resources ####################################


  ToEmail:
    Type: AWS::SES::EmailIdentity
    Properties:
      EmailIdentity: !Ref Toemailaddress

  FromEmail:
    Type: AWS::SES::EmailIdentity
    Properties:
      EmailIdentity: !Ref Fromemailaddress


############################# DynamoDB resources #################################

  DeviceClassification:
    Type: AWS::DynamoDB::Table
    DeletionPolicy: Delete
    Properties:
      BillingMode: PROVISIONED
      AttributeDefinitions:
        -
          AttributeName: "device_name"
          AttributeType: "S"
        -
          AttributeName: "classification"
          AttributeType: "N"  
      KeySchema:
        - AttributeName: device_name
          KeyType: HASH
        - AttributeName: classification
          KeyType: RANGE
      ProvisionedThroughput:
        ReadCapacityUnits: 5
        WriteCapacityUnits: 5
      # Add SSE Configuration
      SSESpecification:
        SSEEnabled: true
        # Optional: Specify KMS key
        SSEType: KMS
        KMSMasterKeyId: alias/aws/dynamodb
      PointInTimeRecoverySpecification:
        PointInTimeRecoveryEnabled: true

  
# role for lambda function which populates dynamodb table
  LambdaRole:
    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/service-role/AWSLambdaBasicExecutionRole
        - arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole
      Policies:
        - PolicyName: dynamodbAccessPolicy
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
            - Effect: Allow
              Action:
                - dynamodb:PutItem
                - dynamodb:BatchWriteItem
                - dynamodb:GetItem
                - dynamodb:BatchGetItem
                - dynamodb:Scan
                - dynamodb:Query
                - dynamodb:UpdateItem
                - dynamodb:DescribeTable
              Resource: 
                - !GetAtt DeviceClassification.Arn
                - !Sub '${DeviceClassification.Arn}/index/*'
        - PolicyName: LogsAccessPolicyName
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
            - Effect: Allow
              Action:
                - logs:CreateLogGroup
                - logs:CreateLogStream
                - logs:PutLogEvents
              Resource: 
                - !Sub 'arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/${AWS::StackName}-*'


# Lambda function which populates the dynamodb table     
  InitializeTableFunction:
    Type: AWS::Lambda::Function
    Properties:
    # add lambda code to add values to dynamodb
      Handler: index.lambda_handler
      Code: 
        ZipFile: |
          import json
          import boto3
          import cfnresponse
          import os

          TABLE_NAME = os.environ.get('TABLE_NAME')
          REGION = os.environ.get('AWS_REGION')

          def lambda_handler(event, context):
              # Initialize responseData dictionary at the beginning
              responseData = {}
              
              try:
                  dynamodb = boto3.resource('dynamodb', region_name=REGION)
                  table = dynamodb.Table(TABLE_NAME)

                  # add multiple items to dynamodb routeTableName:
                 
                  with table.batch_writer() as batch:
                    batch.put_item(
                        Item={
                            'device_name': 'HIV diagnostic tests',
                            'classification': 3

                        }
                    )
                    batch.put_item(
                        Item={
                            'device_name': 'syringes',
                            'classification': 1
                        }
                    )   
                    batch.put_item(
                        Item={
                            'device_name': 'blood pressure cuff',
                            'classification': 2
                        }
                    )
                    batch.put_item(
                        Item={
                            'device_name': 'pacemakers',
                            'classification': 3
                        }
                    )              
                  
                  response = table.put_item(
                      Item={
                          'device_name': 'oxygen masks',
                          'classification': 2
                      }
                  )
                  
                  # Add successful response data
                  responseData['Data'] = response
                  responseData['Message'] = 'Item added successfully'
                  
                  # Send success response to CloudFormation
                  cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData)
                  
                  return {
                      'statusCode': 200,
                      'body': json.dumps(responseData)
                  }
                  
              except Exception as e:
                  print(f"Error: {str(e)}")
                  
                  # Add error information to responseData
                  responseData['Error'] = str(e)
                  responseData['Message'] = 'Error adding item to the database'
                  
                  # Send failure response to CloudFormation
                  cfnresponse.send(event, context, cfnresponse.FAILED, responseData)
                  
                  return {
                      'statusCode': 500,
                      'body': json.dumps(responseData)
                  }
              
      Role: !GetAtt LambdaRole.Arn
      Runtime: python3.12
      Environment:
        Variables:
          TABLE_NAME: !Ref DeviceClassification
      Timeout: 60
      ReservedConcurrentExecutions: 2

  InitializeDynamoDB:
      Type: Custom::InitializeTable
      Properties:
        ServiceToken: !GetAtt InitializeTableFunction.Arn
        TableName: !Ref DeviceClassification
        Version: "1.0"  # Add version to trigger updates when needed
  

######### resources for dynamodblambda  ########

  LambdaExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: lambda.amazonaws.com
            Action: sts:AssumeRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
        - arn:aws:iam::aws:policy/AmazonDynamoDBReadOnlyAccess
        - arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole
  DeviceClassificationFunction:
    Type: AWS::Lambda::Function
    Properties:
      Description: A Lambda function to finds the classification of a device by querying dynamodb
      Handler: lambda_function.lambda_handler
      Role: !GetAtt LambdaExecutionRole.Arn
      VpcConfig:
        SecurityGroupIds: 
          - !Ref LambdaSecurityGroup
        SubnetIds:
          - !Ref PrivateSubnet1
          - !Ref PrivateSubnet2
      Code:
        S3Bucket: aws-blogs-artifacts-public
        S3Key: ML-17263/lambda/deviceClassification.zip
      Runtime: python3.12
      Timeout: 30
      MemorySize: 128   
      ReservedConcurrentExecutions: 100
      Environment:
        Variables:
          TABLE_NAME: !Ref DeviceClassification
          DYNAMODB_ENDPOINT: !Sub 'dynamodb.${AWS::Region}.amazonaws.com'
    

# add permissions for bedrock to invokelambda
  InvokePermissionDynamodbLambda:
    Type: AWS::Lambda::Permission
    Properties:
      FunctionName: !GetAtt DeviceClassificationFunction.Arn
      Action: lambda:InvokeFunction
      Principal: bedrock.amazonaws.com    

 ########### resources for Appian Lambda ##############

  AppianLambdaExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: lambda.amazonaws.com
            Action: sts:AssumeRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
        - arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole
      Policies:
        - PolicyName: SecretsManagerAccessPolicy
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
            - Effect: Allow
              Action:
                - secretsmanager:GetSecretValue
                - secretsmanager:PutSecretValue
                - secretsmanager:ListSecrets
                - secretsmanager:GetRandomPassword
              Resource:
                - !Ref APIKeySecret
                - !Ref HostEndpointSecret
        - PolicyName: kmsAccessPolicy
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
            - Effect: Allow
              Action:
                - kms:Decrypt
              Resource: !GetAtt MyKMSKey.Arn

  AppianLambdaFunction:
    Type: AWS::Lambda::Function
    Properties:
      Description: A Lambda function to call appian to check the status of a case
      Handler: lambda_function.lambda_handler
      Runtime: python3.12
      Timeout: 10
      VpcConfig:
        SecurityGroupIds: 
          - !Ref LambdaSecurityGroup
        SubnetIds:
          - !Ref PrivateSubnet1
          - !Ref PrivateSubnet2
      Code:
        S3Bucket: aws-blogs-artifacts-public
        S3Key: ML-17263/lambda/AppianCase.zip
      Role: !GetAtt AppianLambdaExecutionRole.Arn
      ReservedConcurrentExecutions: 100
      Environment:
        Variables:
          api_key:  !Ref APIKeySecret
          host_endpoint:  !Ref HostEndpointSecret
  
  
  # # add permissions for bedrock to invokelambda
  InvokePermissionAppianLambda:
    Type: AWS::Lambda::Permission
    Properties:
      FunctionName: !GetAtt AppianLambdaFunction.Arn
      Action: lambda:InvokeFunction
      Principal: bedrock.amazonaws.com    
  
  
########### resources for S3 Lambda  ##############
  LambdaExecutionRoZle:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: lambda.amazonaws.com
            Action: sts:AssumeRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
        - arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole
      #policy to read from s3 bucket
      Policies:
        - PolicyName: s3AccessRole
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
            - Effect: Allow
              Action:
                - s3:GetObject
                - s3:ListBucket
              Resource: 
                - !GetAtt QualityFormsBucket.Arn  
                - !Sub '${QualityFormsBucket.Arn}/*'  
            - Effect: Allow
              Action: kms:Decrypt
              Resource: !GetAtt MyKMSKey.Arn
             

  VerifyQualityDocumentsFunction:
    Type: AWS::Lambda::Function
    Properties:
      Description: A Lambda function to check objects in S3
      Handler: lambda_function.lambda_handler
      Role: !GetAtt LambdaExecutionRoZle.Arn
      VpcConfig:
        SecurityGroupIds: 
          - !Ref LambdaSecurityGroup
        SubnetIds:
          - !Ref PrivateSubnet1
          - !Ref PrivateSubnet2
      Code:
        S3Bucket: aws-blogs-artifacts-public
        S3Key: ML-17263/lambda/verifyQualityDocuments.zip
      Runtime: python3.12
      Timeout: 30
      MemorySize: 128
      ReservedConcurrentExecutions: 100
      Environment:
        Variables:
          BUCKET_NAME: !Ref QualityFormsBucket
          S3_ENDPOINT: !Sub 's3.${AWS::Region}.amazonaws.com'

  

  # add permissions for bedrock to invokelambda
  InvokePermissionS3Lambda:
    Type: AWS::Lambda::Permission
    Properties:
      FunctionName: !GetAtt VerifyQualityDocumentsFunction.Arn
      Action: lambda:InvokeFunction
      Principal: bedrock.amazonaws.com  


########## SES Lambda resources ###############################

  SESLambdaExecutionRole:
      Type: AWS::IAM::Role
      Properties:
        AssumeRolePolicyDocument:
          Version: '2012-10-17'
          Statement:
            - Effect: Allow
              Principal:
                Service: lambda.amazonaws.com
              Action: sts:AssumeRole
        ManagedPolicyArns:
          - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
          - arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole
        #policy to read from s3 bucket
        Policies:
          - PolicyName: SESAccess
            PolicyDocument:
              Version: '2012-10-17'
              Statement:
                - Effect: Allow
                  Action: 
                    - ses:SendEmail
                    - ses:SendRawEmail
                    - ses:SendTemplatedEmail
                  Resource: !Sub 'arn:aws:ses:${AWS::Region}:${AWS::AccountId}:*'       

  EmailReviewersFunction:
    Type: AWS::Lambda::Function
    Properties:
      Description: A Lambda function to check objects in S3
      Handler: lambda_function.lambda_handler
      Role: !GetAtt SESLambdaExecutionRole.Arn
      VpcConfig:
        SecurityGroupIds: 
          - !Ref LambdaSecurityGroup
        SubnetIds:
          - !Ref PrivateSubnet1
          - !Ref PrivateSubnet2
      Code:
        S3Bucket: aws-blogs-artifacts-public
        S3Key: ML-17263/lambda/emailreviewers.zip
      Runtime: python3.12
      Timeout: 30
      MemorySize: 128
      ReservedConcurrentExecutions: 100


  # add permissions for bedrock to invokelambda
  InvokePermissionSESLambda:
    Type: AWS::Lambda::Permission
    Properties:
      FunctionName: !GetAtt EmailReviewersFunction.Arn
      Action: lambda:InvokeFunction
      Principal: bedrock.amazonaws.com  

############# Amazon S3 resources ##########################



#logging bucket to store the access logs
  S3AccessLogsBucket:
    Type: AWS::S3::Bucket
    Properties:
      PublicAccessBlockConfiguration:
        BlockPublicAcls: true
        BlockPublicPolicy: true
        IgnorePublicAcls: true
        RestrictPublicBuckets: true
      BucketEncryption:
        ServerSideEncryptionConfiguration:
          - ServerSideEncryptionByDefault:
              SSEAlgorithm: 'aws:kms'
              KMSMasterKeyID: !GetAtt MyKMSKey.Arn
      VersioningConfiguration:
        Status: Enabled
      Tags:
        - Key: Purpose
          Value: S3AccessLogs
        - Key: ComplianceException
          Value: LoggingBucket

  S3AccessLogsBucketPolicy:
    Type: AWS::S3::BucketPolicy
    Properties:
      Bucket: !Ref S3AccessLogsBucket
      PolicyDocument:
        Version: '2012-10-17'
        Statement:
            - Effect: Allow
              Principal:
                Service: logging.s3.amazonaws.com
              Action: s3:PutObject
              Resource: !Sub '${S3AccessLogsBucket.Arn}/*'
              Condition:
                ArnLike:
                  aws:SourceArn: !Sub 'arn:aws:s3:::${OpenAPISpecsS3Bucket}'
                StringEquals:
                  aws:SourceAccount: !Ref 'AWS::AccountId' 
            - Effect: Allow
              Principal:
                Service: logging.s3.amazonaws.com
              Action: s3:PutObject
              Resource: !Sub '${S3AccessLogsBucket.Arn}/*'
              Condition:
                ArnLike:
                  aws:SourceArn: !Sub 'arn:aws:s3:::${QualityFormsBucket}'
                StringEquals:
                  aws:SourceAccount: !Ref 'AWS::AccountId'
              

###### S3 Bucket for premarket forms #######
  QualityFormsBucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Sub 'bedrockagents-qualityforms-${AWS::AccountId}-${AWS::Region}'
      PublicAccessBlockConfiguration:
        BlockPublicAcls: true
        BlockPublicPolicy: true
        IgnorePublicAcls: true
        RestrictPublicBuckets: true
      BucketEncryption:
        ServerSideEncryptionConfiguration:
          - ServerSideEncryptionByDefault:
              SSEAlgorithm: 'aws:kms'
              KMSMasterKeyID: !Ref MyKMSKey
      VersioningConfiguration:
        Status: Suspended
      LoggingConfiguration:
        DestinationBucketName: !Ref S3AccessLogsBucket
        LogFilePrefix: 'data-source-bucket-logs/'


  QualityFormBucketPolicy:
      Type: AWS::S3::BucketPolicy
      Properties:
        Bucket: !Ref QualityFormsBucket
        PolicyDocument:
          Version: '2012-10-17'
          Statement:
            - Sid: EnforceTLSRequestsOnly
              Effect: Deny
              Principal: '*'
              Action: 's3:*'
              Resource:
                - !Sub '${QualityFormsBucket.Arn}/*'
                - !GetAtt QualityFormsBucket.Arn
              Condition:
                Bool:
                  'aws:SecureTransport': false
            - Sid: EnforceEncryptionInTransit
              Effect: Deny
              Principal: '*'
              Action: 's3:*'
              Resource:
                - !Sub '${QualityFormsBucket.Arn}/*'
                - !GetAtt QualityFormsBucket.Arn
              Condition:
                NumericLessThan:
                  's3:TlsVersion': 1.2
            - Sid: DenyIncorrectEncryptionHeader
              Effect: Deny
              Principal: '*'
              Action: 's3:PutObject'
              Resource: !Sub '${QualityFormsBucket.Arn}/*'
              Condition:
                StringNotEquals:
                  's3:x-amz-server-side-encryption-aws-kms-key-id': !GetAtt MyKMSKey.Arn



###### S3 Bucket for Open API Specs #######
  OpenAPISpecsS3Bucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Sub 'bedrockagents-openapispecs-${AWS::AccountId}-${AWS::Region}'
      PublicAccessBlockConfiguration:
        BlockPublicAcls: true
        BlockPublicPolicy: true
        IgnorePublicAcls: true
        RestrictPublicBuckets: true
      BucketEncryption:
        ServerSideEncryptionConfiguration:
          - ServerSideEncryptionByDefault:
              SSEAlgorithm: 'aws:kms'
              KMSMasterKeyID: !Ref MyKMSKey
      VersioningConfiguration:
        Status: Suspended
      LoggingConfiguration:
        DestinationBucketName: !Ref S3AccessLogsBucket
        LogFilePrefix: 'data-source-bucket-logs/'

  BedrockBucketPolicy:
    Type: AWS::S3::BucketPolicy
    Properties:
      Bucket: !Ref OpenAPISpecsS3Bucket
      PolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Sid: EnforceTLSRequestsOnly
            Effect: Deny
            Principal: '*'
            Action: 's3:*'
            Resource:
              - !Sub '${OpenAPISpecsS3Bucket.Arn}/*'
              - !GetAtt OpenAPISpecsS3Bucket.Arn
            Condition:
              Bool:
                'aws:SecureTransport': false
          - Sid: EnforceEncryptionInTransit
            Effect: Deny
            Principal: '*'
            Action: 's3:*'
            Resource:
              - !Sub '${OpenAPISpecsS3Bucket.Arn}/*'
              - !GetAtt OpenAPISpecsS3Bucket.Arn
            Condition:
              NumericLessThan:
                's3:TlsVersion': 1.2
          - Sid: DenyIncorrectEncryptionHeader
            Effect: Deny
            Principal: '*'
            Action: 's3:PutObject'
            Resource: !Sub '${OpenAPISpecsS3Bucket.Arn}/*'
            Condition:
              StringNotEquals:
                's3:x-amz-server-side-encryption-aws-kms-key-id': !GetAtt MyKMSKey.Arn


Outputs:
  LambdaFunctionArn:
    Value: !GetAtt DeviceClassificationFunction.Arn
    Description: ARN of the Lambda function
  LambdaFunctionName:
    Value: !Ref DeviceClassificationFunction
    Description: Name of the Lambda function