---
AWSTemplateFormatVersion: '2010-09-09'
Description: AWS CloudFormation template for setting up AWS Backup event with Amazon EventBridge
Resources:
  AwsBackupEventsBucket:
    Type: AWS::S3::Bucket
    Properties:
      BucketName: !Sub  aws-backup-events-records-${AWS::AccountId}-${AWS::Region}
      BucketEncryption:
        ServerSideEncryptionConfiguration:
          - ServerSideEncryptionByDefault:
              SSEAlgorithm: AES256
      PublicAccessBlockConfiguration:
            BlockPublicAcls : true
            BlockPublicPolicy : true
            IgnorePublicAcls : true
            RestrictPublicBuckets : true
  
  AwsBackupEventsBucketPolicy:
    Type: AWS::S3::BucketPolicy
    Properties:
      Bucket: !Ref AwsBackupEventsBucket
      PolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Sid: DenyNonSecureTransport
            Effect: Deny
            Principal: "*"
            Action: s3:*
            Resource: 
              - !Sub "${AwsBackupEventsBucket.Arn}"
              - !Sub "${AwsBackupEventsBucket.Arn}/*"
            Condition:
              Bool:
                aws:SecureTransport: false
  
  FirehoseLogGroup:
    Type: AWS::Logs::LogGroup
    Properties:
      LogGroupName: /aws/kinesisfirehose/aws-backup-events
      RetentionInDays: 7
  FirehoseLogStream:
    Type: AWS::Logs::LogStream
    Properties:
      LogGroupName: !Ref FirehoseLogGroup
      LogStreamName: BackupEventsDeliveryStream
  MyKinesisFirehoseDeliveryStream:
    Type: AWS::KinesisFirehose::DeliveryStream
    Properties:
      DeliveryStreamName: aws-backup-events-delivery-stream
      DeliveryStreamType: DirectPut
      DeliveryStreamEncryptionConfigurationInput:
        KeyType: AWS_OWNED_CMK
      ExtendedS3DestinationConfiguration:
        BucketARN: !GetAtt AwsBackupEventsBucket.Arn
        RoleARN: !GetAtt FirehoseRole.Arn
        Prefix: "backup-events/!{partitionKeyFromQuery:source}/year=!{timestamp:yyyy}/month=!{timestamp:MM}/day=!{timestamp:dd}/hour=!{timestamp:HH}/"
        ErrorOutputPrefix: "aws-backup-events-firehose-error/"
        CompressionFormat: "UNCOMPRESSED"
        BufferingHints:
          IntervalInSeconds: 60
          SizeInMBs: 64
        DynamicPartitioningConfiguration:
          Enabled: true
          RetryOptions:
            DurationInSeconds: 300
        ProcessingConfiguration:
          Enabled: true
          Processors:
            - Type: AppendDelimiterToRecord
            - Type: MetadataExtraction
              Parameters:
                - ParameterName: MetadataExtractionQuery
                  ParameterValue: "{source:.source}"
                - ParameterName: JsonParsingEngine
                  ParameterValue: JQ-1.6
        CloudWatchLoggingOptions:
             Enabled: true
             LogGroupName: !Ref FirehoseLogGroup
             LogStreamName: !Ref FirehoseLogStream
  EventBridgeRole:
    Type: AWS::IAM::Role
    Properties:
      Description: "IAM role allowing EventBridge to invoke Kinesis Firehose"
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Principal:
              Service: events.amazonaws.com
            Action: sts:AssumeRole
      Policies:
        - PolicyName: AmazonEventBridgeInvokeFirehose
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Effect: Allow
                Action:
                 - firehose:PutRecord
                 - firehose:PutRecordBatch
                Resource: !GetAtt MyKinesisFirehoseDeliveryStream.Arn
  FirehoseRole:
    Type: AWS::IAM::Role
    Properties:
      Description: "IAM role granting Kinesis Firehose permissions to write to S3 and CloudWatch Logs"
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Principal:
              Service: firehose.amazonaws.com
            Action: sts:AssumeRole
      Policies:
        # Policy allowing CloudWatch Logs access
        - PolicyName: CloudWatchLogsAccess
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - logs:CreateLogGroup
                Resource: !Sub "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/kinesisfirehose/aws-backup-events"
              - Effect: Allow
                Action:
                  - logs:CreateLogStream
                  - logs:PutLogEvents
                Resource: !Sub "arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/kinesisfirehose/*"
        - PolicyName: AllowS3Access
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Sid: AllowS3Access
                Effect: Allow
                Action:
                  - "s3:AbortMultipartUpload"
                  - "s3:GetBucketLocation"
                  - "s3:GetObject"
                  - "s3:ListBucket"
                  - "s3:ListBucketMultipartUploads"
                  - "s3:PutObject"
                Resource:
                  - !Sub "arn:${AWS::Partition}:s3:::${AwsBackupEventsBucket}"
                  - !Sub "arn:${AWS::Partition}:s3:::${AwsBackupEventsBucket}/*"
  BackupEventRule:
    Type: AWS::Events::Rule
    Properties:
      EventBusName: default
      EventPattern:
        source:
          - aws.backup
        detail-type:
          - Backup Plan State Change
          - Restore Job State Change
          - Copy Job State Change
      Name: aws-backup-events-records
      State: ENABLED
      Targets:
        - Id: backup-event-target
          Arn: !GetAtt MyKinesisFirehoseDeliveryStream.Arn
          RoleArn: !GetAtt EventBridgeRole.Arn
  BackupAthenaDatabase:
    Type: AWS::Glue::Database
    Properties:
      DatabaseInput:
        Name: 'aws-backup-event-records'
      CatalogId: !Ref AWS::AccountId
  BackupEventGlueCrawler:
    Type: AWS::Glue::Crawler
    Properties:
      Description: "AWS Glue crawler to automatically update the schema of AWS Backup event data in S3"
      Name: aws-backup-event-crawler
      Role: !GetAtt GlueCrawlerRole.Arn
      DatabaseName: !Ref BackupAthenaDatabase
      Targets:
        S3Targets:
          - Path: !Ref AwsBackupEventsBucket
      Configuration: "{\"Version\":1.0,\"CrawlerOutput\":{\"Partitions\":{\"AddOrUpdateBehavior\":\"InheritFromTable\"}}}"
      Schedule:
        ScheduleExpression: cron(0 */1 * * ? *)
  GlueCrawlerRole:
    Type: AWS::IAM::Role
    Properties:
      Description: "IAM role granting AWS Glue crawler permissions to access S3 and update the Glue Data Catalog"
      AssumeRolePolicyDocument:
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - glue.amazonaws.com
            Action:
              - sts:AssumeRole
        Version: 2012-10-17
      ManagedPolicyArns:
        - !Sub "arn:${AWS::Partition}:iam::aws:policy/service-role/AWSGlueServiceRole"
      Path: /
      Policies:
        - PolicyName: aws-backup-events-GlueCrawlerRolePolicy
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action: ['s3:ListBucket', 's3:GetObject']
                Resource:
                  - !Sub "arn:${AWS::Partition}:s3:::${AwsBackupEventsBucket}"
                  - !Sub "arn:${AWS::Partition}:s3:::${AwsBackupEventsBucket}/*"
              - Effect: Allow
                Action:
                  - "s3:PutObject"
                  - "s3:GetObject"
                Resource:
                  - !Sub "arn:${AWS::Partition}:s3:::${AwsBackupEventsBucket}/*"
  BackupEventsAthenaView:
    Type: AWS::Athena::NamedQuery
    Properties:
      Name: aws-backup-events-view
      Database: aws-backup-event-records
      Description: Provides a summary view of the AWS Backup event records
      QueryString: |
        CREATE OR REPLACE VIEW "grafana_view" AS
          SELECT
            id
          , "detail-type" eventType
          , COALESCE(TRY_CAST(detail.backupsizeinbytes AS DOUBLE), 0.0) AS backupsizeinbytes
          , detail.creationdate creationdate
          , detail.resourcetype
          , CAST(detail.percentdone AS int) percentdone
          , detail.statusmessage
          , CAST(account AS bigint) account
          , detail.status
          , detail.state
          FROM
            aws_backup_events_records_<account-id>_us_east_1
          WHERE ("date_parse"("concat"("year", "month", "day"), '%Y%m%d') >= (current_timestamp - INTERVAL  '3' MONTH))
          GROUP BY 1, 2, 3, 4, 5, 6, 7, 8, 9, 10
Outputs:
  # Output the event bus rule ARN
  EventbusruleArn:
    Value: !GetAtt BackupEventRule.Arn