AWSTemplateFormatVersion: '2010-09-09'
Description: Defines configuration for DynamoDB and Subscription Filter Used to Process File Acess Auditing Events


Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:

      - Label:
          default: CloudWatch Log Group
        Parameters:
        - CloudWatchLogsDestination
   
      - Label:
          default: Log Retension Period Parameters
        Parameters:
        - LogRetensionPeriod
        - LogRetentionPeriodFormat

Parameters:
 
  CloudWatchLogsDestination:
    Description: CloudWatch Logs Destination. The Log group that the Lambda function will be subscribed to.
    Type: String
    Default: "/aws/fsx/windows"
    
  LogRetensionPeriod:
    Description: Time Period for Access Audit Logs Retension in DynamoDB. By default the logs will be retained for 10 years.
    Type: String
    Default: 10
    AllowedPattern: ^([0-9]+)$

  LogRetentionPeriodFormat:
    Description: Log Retention Format
    Type: String
    Default: Years
    AllowedValues:
      - Days
      - Years


Resources:

  RemoveCharacters:
    Type: AWS::Lambda::Function
    Properties:
      Runtime: python3.7
      Timeout: 5
      Handler: index.lambda_handler
      Role: !GetAtt StringLambdaExecutionRole.Arn
      Code:
        ZipFile: |
          import json
          import boto3
          import cfnresponse
          import logging
          def lambda_handler(event, context):
            print(event)
            logger = logging.getLogger()
            logger.setLevel(logging.DEBUG)
            responseData = {}
            physicalResourceId = {}
           
            try:
              if event['RequestType'] == 'Delete':
                logger.info('Deleted!')
                cfnresponse.send(event, context, cfnresponse.SUCCESS, {})
                return

              elif event['RequestType'] == 'Create' or event['RequestType'] == 'Update':
                logger.info('Create or Update Event Received')
                org_string = event['ResourceProperties']['CloudWatchLogsDestination']

                new_string = org_string[:50]
                
                # Remove special characters
                char_to_replace = {'/': '-','#': '-'}
                for key, value in char_to_replace.items():
                # Replace key character with value character in string
                    new_string = new_string.replace(key, value)
          
                responseData = {'Response': new_string}
                cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData, physicalResourceId)
                return
  
            except Exception: 
              logger.exception('Signaling failure to CloudFormation.')
              cfnresponse.send(event, context, cfnresponse.FAILED, {}) 
                    

  StringLambdaExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub Custom-Resource-Lambda-Role-${AWS::StackName}-${AWS::Region}
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
        - Effect: Allow
          Principal: {Service: [lambda.amazonaws.com]}
          Action: ['sts:AssumeRole']
      Path: /
      Policies:
      - PolicyName: !Sub String-Resource-Policy-${AWS::StackName}-${AWS::Region}
        PolicyDocument:
          Version: '2012-10-17'
          Statement:
          - Effect: Allow
            Action:
            - logs:CreateLogGroup
            - logs:CreateLogStream
            - logs:PutLogEvents
            Resource: !Sub "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/*"
          
      ManagedPolicyArns:
      - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
      - arn:aws:iam::aws:policy/service-role/AWSLambdaRole


  GetCleanUpString:
    Type: Custom::CleanUpString
    Properties:
      ServiceToken: !GetAtt RemoveCharacters.Arn
      CloudWatchLogsDestination: !Ref CloudWatchLogsDestination


  DdbTable:
    Type: AWS::DynamoDB::Table
    Properties: 
      AttributeDefinitions: 
        - AttributeName: "FileSystemID"
          AttributeType: 'S'
        - AttributeName: "SystemTime"
          AttributeType: 'S'
       
      KeySchema: 
        - AttributeName: "FileSystemID"
          KeyType: 'HASH'
        - AttributeName: "SystemTime"
          KeyType: "RANGE"

      TimeToLiveSpecification:
          AttributeName: "TTL"
          Enabled: "TRUE" 


      ProvisionedThroughput: 
        ReadCapacityUnits: "5"
        WriteCapacityUnits: "5"
      TableName: !Sub FSxAudit-${GetCleanUpString.Response}


  LambdaExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
        - Effect: Allow
          Principal:
            Service:
            - lambda.amazonaws.com
          Action:
          - sts:AssumeRole
      
      Policies:
      - PolicyName: !Sub DDb-Custom-Resource-Policy-${AWS::StackName}-${AWS::Region}
        PolicyDocument:
          Version: '2012-10-17'
          Statement:
          - Effect: Allow
            Action:
            - dynamodb:BatchGetItem
            - dynamodb:BatchWriteItem
            - dynamodb:DeleteItem
            - dynamodb:DescribeTable
            - dynamodb:GetItem
            - dynamodb:GetRecords
            - dynamodb:PutItem
            - dynamodb:Query
            - dynamodb:Scan
            - dynamodb:UpdateItem
            - dynamodb:UpdateTable
            Resource: !GetAtt DdbTable.Arn 
                     
      ManagedPolicyArns:
      - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole
      - arn:aws:iam::aws:policy/service-role/AWSLambdaRole

  CloudWatchFilterRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
        - Effect: Allow
          Principal:
            Service:
            - cloudwatch.amazonaws.com
          Action:
          - sts:AssumeRole
      
      Policies:
      - PolicyName: !Sub Cloudwatch-Put-Events-Policy-${AWS::StackName}-${AWS::Region}
        PolicyDocument:
          Version: '2012-10-17'
          Statement:
          - Effect: Allow
            Action:
            - logs:PutLogEvents
            Resource: "arn:aws:logs:*:*:*" 
  
          - Effect: Allow
            Action:
            - lambda:InvokeFunction
            Resource: !GetAtt CreateFunction.Arn

  CreateFunction:
    Type: AWS::Lambda::Function
    Properties:
      Code:
        S3Bucket: !Sub solution-references-${AWS::Region}
        S3Key: 'fsx/FileAccessAuditing/FSxAudit.zip'
      FunctionName: !Sub FSxAudit-${GetCleanUpString.Response}
      Environment:
        Variables:
          DDBTableName: !Sub FSxAudit-${GetCleanUpString.Response}
          TTL: !Ref LogRetensionPeriod
          TTLFormat: !Ref LogRetentionPeriodFormat
      Handler: FSxAudit::FSxAudit.Function::FunctionHandler
      MemorySize: 192
      Role: !GetAtt LambdaExecutionRole.Arn
      Runtime: dotnetcore3.1
      Timeout: 90
      TracingConfig: 
        Mode: PassThrough

  LogGroupLambdaInvokePermission:
    Type: AWS::Lambda::Permission
    DependsOn: CreateFunction
    Properties:
      FunctionName: !Sub FSxAudit-${GetCleanUpString.Response}
      Action: "lambda:InvokeFunction"
      Principal: !Sub "logs.${AWS::Region}.amazonaws.com"
      SourceArn: !Sub "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:${CloudWatchLogsDestination}:*"
      SourceAccount:
        Ref: "AWS::AccountId"
  
  SubscriptionFilter: 
    Type: AWS::Logs::SubscriptionFilter
    Properties: 
      LogGroupName: !Ref CloudWatchLogsDestination
      FilterPattern: ""
      DestinationArn: !GetAtt CreateFunction.Arn
        

Outputs:
  ValidCloudWatchLogDestination:
    Description: Cleaned up CloudWatch Log Group
    Value: !GetAtt GetCleanUpString.Response

  DynamoDBTableName:
    Description: DynamoDB Table Name
    Value: !Sub FSxAudit-${GetCleanUpString.Response}
  LambdaFunctionName:
    Description: Name of the Lambda Function
    Value: !Ref CreateFunction
