---
AWSTemplateFormatVersion: 2010-09-09
Description: Provides the base security, IAM, and access configuration for the AWS account (qs-1r6f0fdc6)
Parameters:
  EnableLogFileValidation:
    Type: String
    Default: 'true'
    Description: Indicates whether CloudTrail validates the integrity of log files.
    AllowedValues:
      - 'true'
      - 'false'
  IncludeGlobalEvents:
    Type: String
    Default: 'true'
    Description: Indicates whether the trail is publishing events from global services, such as IAM, to the log files.
    AllowedValues:
      - 'true'
      - 'false'
  MultiRegion:
    Type: String
    Default: 'false'
    Description: Indicates whether the CloudTrail trail is created in the region in which you create the stack (false) or in all regions (true).
    AllowedValues:
      - 'true'
      - 'false'
  PublishToCloudWatchLogs:
    Type: String
    Default: 'true'
    Description: Indicates whether notifications are published to CloudWatch Logs.
    AllowedValues:
      - 'true'
      - 'false'
  CloudWatchLogsGroupName:
    Type: String
    Default: 'CloudTrail/K-ISMS-Logs'
    Description: CloudWatchLogs Group name.
  LogsRetentionInDays:
    Description: 'Specifies the number of days you want to retain CloudTrail log events in the CloudWatch Logs.'
    Type: Number
    Default: 14
    AllowedValues: [1, 3, 5, 7, 14, 30, 60, 90, 120, 150, 180, 365, 400, 545, 731, 1827, 3653]
  QSS3BucketName:
    AllowedPattern: ^[0-9a-zA-Z]+([0-9a-zA-Z-.]*[0-9a-zA-Z])*$
    ConstraintDescription: Quick Start bucket name can include numbers, lowercase
      letters, uppercase letters, periods (.), and hyphens (-). It cannot start or
      end with a hyphen (-). If you are unsure, do not change this value.
    Default: aws-quickstart
    Description: S3 bucket name for the Quick Start assets. Quick Start bucket name
      can include numbers, lowercase letters, uppercase letters, and hyphens (-).
      It cannot start or end with a hyphen (-). If you are unsure, do not change this value.
    Type: String
  QSS3BucketRegion:
    Default: 'us-east-1'
    Description: AWS Region where the Quick Start S3 bucket (QSS3BucketName) is hosted. When using your own bucket, you must specify this value.
    Type: String
  QSS3KeyPrefix:
    AllowedPattern: ^[0-9a-zA-Z-/]*$
    ConstraintDescription: Quick Start key prefix can include numbers, lowercase letters,
      uppercase letters, hyphens (-), and forward slash (/). If you are unsure, do not change this value.
    Default: quickstart-korea-isms-p/
    Description: S3 key prefix for the Quick Start assets. Quick Start key prefix
      can include numbers, lowercase letters, uppercase letters, hyphens (-), and
      forward slash (/). If you are unsure, do not change this value.
    Type: String
  EnableGuardDuty:
    Type: String
    Default: enable
    AllowedValues: [ enable, disable ]
    Description: If you do not currently have Guard Duty enabled in your account.
Conditions:
  IsMultiRegion: !Equals
    - !Ref MultiRegion
    - 'true'
  IsPublishToCloudWatchLogs: !Equals
    - !Ref PublishToCloudWatchLogs
    - 'true'
  UsingDefaultBucket: !Equals [!Ref QSS3BucketName, 'aws-quickstart']
  GuardDutyEnabled: !Equals [!Ref EnableGuardDuty, 'enable']
Resources:
  SysAdminGroup:
    Type: AWS::IAM::Group
    Properties:
      Path: /
  SysAdminPolicy:
    Type: AWS::IAM::ManagedPolicy
    Properties:
      PolicyDocument:
        Version: 2012-10-17
        Statement:
        - Effect: Allow
          NotAction: iam:*
          Resource: '*'
          Condition:
            Bool:
              aws:MultiFactorAuthPresent: true
        - Effect: Deny
          Action: aws-portal:*Billing
          Resource: '*'
        - Effect: Deny
          Action:
          - cloudtrail:DeleteTrail
          - cloudtrail:StopLogging
          - cloudtrail:UpdateTrail
          Resource: '*'
        - Effect: Deny
          Action:
          - kms:Create*
          - kms:Revoke*
          - kms:Enable*
          - kms:Get*
          - kms:Disable*
          - kms:Delete*
          - kms:Put*
          - kms:Update*
          Resource: '*'
      Groups:
      - !Ref SysAdminGroup
  IAMAdminGroup:
    Type: AWS::IAM::Group
    Properties:
      Path: /
  IAMAdminPolicy:
    Type: AWS::IAM::ManagedPolicy
    Properties:
      PolicyDocument:
        Version: 2012-10-17
        Statement:
        - Effect: Allow
          Action: iam:*
          Resource: '*'
          Condition:
            Bool:
              aws:MultiFactorAuthPresent: true
        - Effect: Deny
          Action: aws-portal:*Billing
          Resource: '*'
      Groups:
      - !Ref IAMAdminGroup
  InstanceOpsGroup:
    Type: AWS::IAM::Group
    Properties:
      Path: /
  InstanceOpsPolicy:
    Type: AWS::IAM::ManagedPolicy
    Properties:
      PolicyDocument:
        Version: 2012-10-17
        Statement:
        - Action: ec2:*
          Effect: Allow
          Resource: '*'
        - Effect: Allow
          Action: elasticloadbalancing:*
          Resource: '*'
        - Effect: Allow
          Action: cloudwatch:*
          Resource: '*'
        - Effect: Allow
          Action: autoscaling:*
          Resource: '*'
        - Effect: Deny
          Action:
          - ec2:CreateVpc*
          - ec2:DeleteVpc*
          - ec2:ModifyVpc*
          - ec2:CreateSubnet*
          - ec2:DeleteSubnet*
          - ec2:ModifySubnet*
          - ec2:Create*Route*
          - ec2:DeleteRoute*
          - ec2:AssociateRoute*
          - ec2:ReplaceRoute*
          - ec2:CreateVpn*
          - ec2:DeleteVpn*
          - ec2:AttachVpn*
          - ec2:DetachVpn*
          - ec2:CreateNetworkAcl*
          - ec2:DeleteNetworkAcl*
          - ec2:ReplaceNetworkAcl*
          - ec2:*Gateway*
          - ec2:*PeeringConnection*
          Resource: '*'
        - Effect: Deny
          Action: aws-portal:*Billing
          Resource: '*'
        - Effect: Deny
          Action:
          - kms:Create*
          - kms:Revoke*
          - kms:Enable*
          - kms:Get*
          - kms:Disable*
          - kms:Delete*
          - kms:Put*
          - kms:Update*
          Resource: '*'
      Groups:
      - !Ref InstanceOpsGroup
  ReadOnlyAdminGroup:
    Type: AWS::IAM::Group
    Properties:
      Path: /
  ReadOnlyAdminPolicy:
    Type: AWS::IAM::ManagedPolicy
    Properties:
      PolicyDocument:
        Version: 2012-10-17
        Statement:
        - Action:
          - appstream:Get*
          - autoscaling:Describe*
          - cloudformation:DescribeStacks
          - cloudformation:DescribeStackEvents
          - cloudformation:DescribeStackResource
          - cloudformation:DescribeStackResources
          - cloudformation:GetTemplate
          - cloudformation:List*
          - cloudfront:Get*
          - cloudfront:List*
          - cloudtrail:DescribeTrails
          - cloudtrail:GetTrailStatus
          - cloudwatch:Describe*
          - cloudwatch:Get*
          - cloudwatch:List*
          - directconnect:Describe*
          - dynamodb:GetItem
          - dynamodb:BatchGetItem
          - dynamodb:Query
          - dynamodb:Scan
          - dynamodb:DescribeTable
          - dynamodb:ListTables
          - ec2:Describe*
          - elasticache:Describe*
          - elasticbeanstalk:Check*
          - elasticbeanstalk:Describe*
          - elasticbeanstalk:List*
          - elasticbeanstalk:RequestEnvironmentInfo
          - elasticbeanstalk:RetrieveEnvironmentInfo
          - elasticloadbalancing:Describe*
          - elastictranscoder:Read*
          - elastictranscoder:List*
          - iam:List*
          - iam:Get*
          - kinesis:Describe*
          - kinesis:Get*
          - kinesis:List*
          - opsworks:Describe*
          - opsworks:Get*
          - route53:Get*
          - route53:List*
          - redshift:Describe*
          - redshift:ViewQueriesInConsole
          - rds:Describe*
          - rds:ListTagsForResource
          - s3:Get*
          - s3:List*
          - sdb:GetAttributes
          - sdb:List*
          - sdb:Select*
          - ses:Get*
          - ses:List*
          - sns:Get*
          - sns:List*
          - sqs:GetQueueAttributes
          - sqs:ListQueues
          - sqs:ReceiveMessage
          - storagegateway:List*
          - storagegateway:Describe*
          - trustedadvisor:Describe*
          Effect: Allow
          Resource: '*'
        - Effect: Deny
          Action: aws-portal:*Billing
          Resource: '*'
      Groups:
      - !Ref ReadOnlyAdminGroup
  ReadOnlyBillingGroup:
    Type: AWS::IAM::Group
    Properties:
      Path: /
  ReadOnlyBillingPolicy:
    Type: AWS::IAM::ManagedPolicy
    Properties:
      PolicyDocument:
        Version: 2012-10-17
        Statement:
        - Effect: Allow
          Action: aws-portal:View*
          Resource: '*'
        - Effect: Deny
          Action: aws-portal:*Account
          Resource: '*'
      Groups:
      - !Ref ReadOnlyBillingGroup
  CloudTrail:
    DependsOn:
      - CloudTrailBucketPolicy
    Type: AWS::CloudTrail::Trail
    Properties:
      S3BucketName: !Ref CloudTrailS3Bucket
      KMSKeyId: !GetAtt CloudTrailKey.Arn
      IsLogging: True
      EnableLogFileValidation: !Ref EnableLogFileValidation
      IncludeGlobalServiceEvents: !If
        - IsMultiRegion
        - True
        - !Ref IncludeGlobalEvents
      IsMultiRegionTrail: !Ref MultiRegion
      CloudWatchLogsLogGroupArn: !If
        - IsPublishToCloudWatchLogs
        - !GetAtt TrailLogGroup.Arn
        - !Ref AWS::NoValue
      CloudWatchLogsRoleArn: !If
        - IsPublishToCloudWatchLogs
        - !GetAtt TrailLogGroupRole.Arn
        - !Ref AWS::NoValue
  TrailLogGroup:
    Type: 'AWS::Logs::LogGroup'
    Condition: IsPublishToCloudWatchLogs
    Properties:
      LogGroupName: !Ref CloudWatchLogsGroupName
      RetentionInDays: !Ref LogsRetentionInDays
  TrailLogGroupRole:
     Type: 'AWS::IAM::Role'
     Condition: IsPublishToCloudWatchLogs
     Properties:
       AssumeRolePolicyDocument:
         Version: '2012-10-17'
         Statement:
         - Sid: CloudTrailAssumeRole
           Effect: Allow
           Principal:
             Service: 'cloudtrail.amazonaws.com'
           Action: 'sts:AssumeRole'
       Policies:
       - PolicyName: 'cloudtrail-policy'
         PolicyDocument:
           Version: '2012-10-17'
           Statement:
           - Sid: AWSCloudTrailCreateLogStream
             Effect: Allow
             Action: 'logs:CreateLogStream'
             Resource: !GetAtt 'TrailLogGroup.Arn'
           - Sid: AWSCloudTrailPutLogEvents
             Effect: Allow
             Action: 'logs:PutLogEvents'
             Resource: !GetAtt 'TrailLogGroup.Arn'
  # Enable GuardDuty
  GuardDuty:
    Condition: GuardDutyEnabled
    Type: "AWS::GuardDuty::Detector"
    Properties:
      Enable: true
      FindingPublishingFrequency: FIFTEEN_MINUTES
  # Create KMS CloudTrail encryption key
  CloudTrailKey:
    Type: AWS::KMS::Key
    Properties:
      KeyPolicy:
        Version: 2012-10-17
        Id: k-isms-key-cloudtrail
        Statement:
          - Sid: Enable IAM User Permissions
            Effect: Allow
            Principal:
              AWS: !Join
                - ""
                - - "arn:aws:iam::"
                  - !Ref "AWS::AccountId"
                  - ":root"
            Action: "kms:*"
            Resource: "*"
          - Sid: Allow CloudTrail to encrypt logs
            Effect: Allow
            Principal:
              Service:
                - cloudtrail.amazonaws.com
            Action: "kms:GenerateDataKey*"
            Resource: "*"
            Condition:
              StringLike:
                "kms:EncryptionContext:aws:cloudtrail:arn": !Sub "arn:aws:cloudtrail:*:${AWS::AccountId}:trail/*"
          - Sid: Allow CloudTrail to describe key
            Effect: Allow
            Principal:
              Service:
                - cloudtrail.amazonaws.com
            Action: "kms:DescribeKey"
            Resource: "*"
          - Sid: Allow principals in the account to decrypt log files
            Effect: Allow
            Principal:
              AWS: "*"
            Action:
              - "kms:Decrypt"
              - "kms:ReEncryptFrom"
            Resource: "*"
            Condition:
              StringEquals:
                "kms:CallerAccount": !Sub "${AWS::AccountId}"
              StringLike:
                "kms:EncryptionContext:aws:cloudtrail:arn": !Sub "arn:aws:cloudtrail:*:${AWS::AccountId}:trail/*"
          - Sid: Allow alias creation during setup
            Effect: Allow
            Principal:
              AWS: "*"
            Action: "kms:CreateAlias"
            Resource: "*"
            Condition:
              StringEquals:
                "kms:ViaService": ec2.region.amazonaws.com
                "kms:CallerAccount": !Sub "${AWS::AccountId}"
          - Sid: Enable cross account log decryption
            Effect: Allow
            Principal:
              AWS: "*"
            Action:
              - "kms:Decrypt"
              - "kms:ReEncryptFrom"
            Resource: "*"
            Condition:
              StringEquals:
                "kms:CallerAccount": !Sub "${AWS::AccountId}"
              StringLike:
                "kms:EncryptionContext:aws:cloudtrail:arn": !Sub "arn:aws:cloudtrail:*:${AWS::AccountId}:trail/*"
  CloudTrailKeyAlias:
    Type: AWS::KMS::Alias
    Properties:
      AliasName: alias/cloudtrail
      TargetKeyId:
        Ref: CloudTrailKey
  
  SecurityGroupChangesMetricFilter:
    Type: AWS::Logs::MetricFilter
    DependsOn: TrailLogGroup
    Properties:
      LogGroupName: 
        !Ref CloudWatchLogsGroupName
      FilterPattern: "{ ($.eventName = AuthorizeSecurityGroupIngress) || ($.eventName
        = AuthorizeSecurityGroupEgress) || ($.eventName = RevokeSecurityGroupIngress)
        || ($.eventName = RevokeSecurityGroupEgress) || ($.eventName = CreateSecurityGroup)
        || ($.eventName = DeleteSecurityGroup) }"
      MetricTransformations:
        - MetricNamespace: "CloudTrailMetrics"
          MetricName: "SecurityGroupEventCount"
          MetricValue: "1"
  SecurityGroupChangesAlarm:
    Type: AWS::CloudWatch::Alarm
    Metadata:
      cfn_nag:
        rules_to_suppress:
          - id: W28
            reason: "The alarm name is defined to identify K-ISMS Quick Start resources."
    Properties:
      #AlarmName: CloudTrailSecurityGroupChanges
      AlarmDescription: Alarms when an API call is made to create, update or delete
        a Security Group.
      MetricName: SecurityGroupEventCount
      Namespace: CloudTrailMetrics
      ComparisonOperator: GreaterThanOrEqualToThreshold
      EvaluationPeriods: 1
      Period: 300
      Statistic: Sum
      Threshold: 1
      TreatMissingData: notBreaching
  NetworkAclChangesMetricFilter:
    Type: AWS::Logs::MetricFilter
    DependsOn: TrailLogGroup
    Properties:
      LogGroupName:
        !Ref CloudWatchLogsGroupName
      FilterPattern: "{ ($.eventName = CreateNetworkAcl) || ($.eventName = CreateNetworkAclEntry)
        || ($.eventName = DeleteNetworkAcl) || ($.eventName = DeleteNetworkAclEntry)
        || ($.eventName = ReplaceNetworkAclEntry) || ($.eventName = ReplaceNetworkAclAssociation)
        }"
      MetricTransformations:
      - MetricNamespace: "CloudTrailMetrics"
        MetricName: "NetworkAclEventCount"
        MetricValue: "1"
  NetworkAclChangesAlarm:
    Type: AWS::CloudWatch::Alarm
    Metadata:
      cfn_nag:
        rules_to_suppress:
          - id: W28
            reason: "The alarm name is defined to identify K-ISMS Quick Start resources."
    DependsOn: SecurityGroupChangesAlarm
    Properties:
      #AlarmName: CloudTrailNetworkAclChanges
      AlarmDescription: Alarms when an API call is made to create, update or delete
        a Network ACL.
      MetricName: NetworkAclEventCount
      Namespace: CloudTrailMetrics
      ComparisonOperator: GreaterThanOrEqualToThreshold
      EvaluationPeriods: 1
      Period: 300
      Statistic: Sum
      Threshold: 1
      TreatMissingData: notBreaching
  GatewayChangesMetricFilter:
    Type: AWS::Logs::MetricFilter
    DependsOn: TrailLogGroup
    Properties:
      LogGroupName:
        !Ref CloudWatchLogsGroupName
      FilterPattern: "{ ($.eventName = CreateCustomerGateway) || ($.eventName = DeleteCustomerGateway)
        || ($.eventName = AttachInternetGateway) || ($.eventName = CreateInternetGateway)
        || ($.eventName = DeleteInternetGateway) || ($.eventName = DetachInternetGateway)
        }"
      MetricTransformations:
      - MetricNamespace: "CloudTrailMetrics"
        MetricName: "GatewayEventCount"
        MetricValue: "1"
  GatewayChangesAlarm:
    Type: AWS::CloudWatch::Alarm
    Metadata:
      cfn_nag:
        rules_to_suppress:
          - id: W28
            reason: "The alarm name is defined to identify K-ISMS Quick Start resources."
    DependsOn: NetworkAclChangesAlarm
    Properties:
      #AlarmName: CloudTrailGatewayChanges
      AlarmDescription: Alarms when an API call is made to create, update or delete
        a Customer or Internet Gateway.
      MetricName: GatewayEventCount
      Namespace: CloudTrailMetrics
      ComparisonOperator: GreaterThanOrEqualToThreshold
      EvaluationPeriods: 1
      Period: 300
      Statistic: Sum
      Threshold: 1
      TreatMissingData: notBreaching
  VpcChangesMetricFilter:
    Type: AWS::Logs::MetricFilter
    DependsOn: TrailLogGroup
    Properties:
      LogGroupName:
        !Ref CloudWatchLogsGroupName
      FilterPattern: "{ ($.eventName = CreateVpc) || ($.eventName = DeleteVpc) ||
        ($.eventName = ModifyVpcAttribute) || ($.eventName = AcceptVpcPeeringConnection)
        || ($.eventName = CreateVpcPeeringConnection) || ($.eventName = DeleteVpcPeeringConnection)
        || ($.eventName = RejectVpcPeeringConnection) || ($.eventName = AttachClassicLinkVpc)
        || ($.eventName = DetachClassicLinkVpc) || ($.eventName = DisableVpcClassicLink)
        || ($.eventName = EnableVpcClassicLink) }"
      MetricTransformations:
      - MetricNamespace: "CloudTrailMetrics"
        MetricName: "VpcEventCount"
        MetricValue: "1"
  VpcChangesAlarm:
    Type: AWS::CloudWatch::Alarm
    Metadata:
      cfn_nag:
        rules_to_suppress:
          - id: W28
            reason: "The alarm name is defined to identify K-ISMS Quick Start resources."
    DependsOn: GatewayChangesAlarm
    Properties:
      #AlarmName: CloudTrailVpcChanges
      AlarmDescription: Alarms when an API call is made to create, update or delete
        a VPC, VPC peering connection or VPC connection to classic.
      MetricName: VpcEventCount
      Namespace: CloudTrailMetrics
      ComparisonOperator: GreaterThanOrEqualToThreshold
      EvaluationPeriods: 1
      Period: 300
      Statistic: Sum
      Threshold: 1
      TreatMissingData: notBreaching
  EC2InstanceChangesMetricFilter:
    Type: AWS::Logs::MetricFilter
    DependsOn: TrailLogGroup
    Properties:
      LogGroupName:
        !Ref CloudWatchLogsGroupName
      FilterPattern: "{ ($.eventName = RunInstances) || ($.eventName = RebootInstances)
        || ($.eventName = StartInstances) || ($.eventName = StopInstances) || ($.eventName
        = TerminateInstances) }"
      MetricTransformations:
      - MetricNamespace: "CloudTrailMetrics"
        MetricName: "EC2InstanceEventCount"
        MetricValue: "1"
  EC2InstanceChangesAlarm:
    Type: AWS::CloudWatch::Alarm
    Metadata:
      cfn_nag:
        rules_to_suppress:
          - id: W28
            reason: "The alarm name is defined to identify AWS Landing Zone resources."
    DependsOn: VpcChangesAlarm
    Properties:
      #AlarmName: CloudTrailEC2InstanceChanges
      AlarmDescription: Alarms when an API call is made to create, terminate, start,
        stop or reboot an EC2 instance.
      MetricName: EC2InstanceEventCount
      Namespace: CloudTrailMetrics
      ComparisonOperator: GreaterThanOrEqualToThreshold
      EvaluationPeriods: 1
      Period: 300
      Statistic: Sum
      Threshold: 1
      TreatMissingData: notBreaching
  EC2LargeInstanceChangesMetricFilter:
    Type: AWS::Logs::MetricFilter
    DependsOn: TrailLogGroup
    Properties:
      LogGroupName:
        !Ref CloudWatchLogsGroupName
      FilterPattern: "{ (($.eventName = RunInstances) || ($.eventName = RebootInstances)
        || ($.eventName = StartInstances) || ($.eventName = StopInstances) || ($.eventName
        = TerminateInstances)) && (($.requestParameters.instanceType
        = *.32xlarge) || ($.requestParameters.instanceType
        = *.24xlarge) || ($.requestParameters.instanceType
        = *.18xlarge) || ($.requestParameters.instanceType
        = *.16xlarge) || ($.requestParameters.instanceType
        = *.12xlarge) || ($.requestParameters.instanceType
        = *.10xlarge) || ($.requestParameters.instanceType
        = *.9xlarge) || ($.requestParameters.instanceType
        = *.8xlarge) || ($.requestParameters.instanceType = *.4xlarge)) }"
      MetricTransformations:
      - MetricNamespace: "CloudTrailMetrics"
        MetricName: "EC2LargeInstanceEventCount"
        MetricValue: "1"
  EC2LargeInstanceChangesAlarm:
    Type: AWS::CloudWatch::Alarm
    Metadata:
      cfn_nag:
        rules_to_suppress:
          - id: W28
            reason: "The alarm name is defined to identify AWS Landing Zone resources."
    DependsOn: EC2InstanceChangesAlarm
    Properties:
      #AlarmName: CloudTrailEC2LargeInstanceChanges
      AlarmDescription: Alarms when an API call is made to create, terminate, start,
        stop or reboot a 4x, 8x, 9x, 10x, 12x, 16x, 18x, 24x, 32x-large EC2 instance.
      MetricName: EC2LargeInstanceEventCount
      Namespace: CloudTrailMetrics
      ComparisonOperator: GreaterThanOrEqualToThreshold
      EvaluationPeriods: 1
      Period: 300
      Statistic: Sum
      Threshold: 1
      TreatMissingData: notBreaching
  CloudTrailChangesMetricFilter:
    Type: AWS::Logs::MetricFilter
    DependsOn: TrailLogGroup
    Properties:
      LogGroupName:
        !Ref CloudWatchLogsGroupName
      FilterPattern: "{ ($.eventName = CreateTrail) || ($.eventName = UpdateTrail)
        || ($.eventName = DeleteTrail) || ($.eventName = StartLogging) || ($.eventName
        = StopLogging) }"
      MetricTransformations:
      - MetricNamespace: "CloudTrailMetrics"
        MetricName: "CloudTrailEventCount"
        MetricValue: "1"
  CloudTrailChangesAlarm:
    Type: AWS::CloudWatch::Alarm
    Metadata:
      cfn_nag:
        rules_to_suppress:
          - id: W28
            reason: "The alarm name is defined to identify AWS Landing Zone resources."
    DependsOn: EC2LargeInstanceChangesAlarm
    Properties:
      #AlarmName: CloudTrailChanges
      AlarmDescription: Alarms when an API call is made to create, update or delete
        a CloudTrail trail, or to start or stop logging to a trail.
      MetricName: CloudTrailEventCount
      Namespace: CloudTrailMetrics
      ComparisonOperator: GreaterThanOrEqualToThreshold
      EvaluationPeriods: 1
      Period: 300
      Statistic: Sum
      Threshold: 1
      TreatMissingData: notBreaching
  ConsoleSignInFailuresMetricFilter:
    Type: AWS::Logs::MetricFilter
    DependsOn: TrailLogGroup
    Properties:
      LogGroupName:
        !Ref CloudWatchLogsGroupName
      FilterPattern: '{ ($.eventName = ConsoleLogin) && ($.errorMessage = "Failed
        authentication") }'
      MetricTransformations:
      - MetricNamespace: "CloudTrailMetrics"
        MetricName: "ConsoleSignInFailureCount"
        MetricValue: "1"
  ConsoleSignInFailuresAlarm:
    Type: AWS::CloudWatch::Alarm
    Metadata:
      cfn_nag:
        rules_to_suppress:
          - id: W28
            reason: "The alarm name is defined to identify AWS Landing Zone resources."
    DependsOn: CloudTrailChangesAlarm
    Properties:
      #AlarmName: CloudTrailConsoleSignInFailures
      AlarmDescription: Alarms when an unauthenticated API call is made to sign into
        the console.
      MetricName: ConsoleSignInFailureCount
      Namespace: CloudTrailMetrics
      ComparisonOperator: GreaterThanOrEqualToThreshold
      EvaluationPeriods: 1
      Period: 300
      Statistic: Sum
      Threshold: 3
      TreatMissingData: notBreaching
  AuthorizationFailuresMetricFilter:
    Type: AWS::Logs::MetricFilter
    DependsOn: TrailLogGroup
    Properties:
      LogGroupName:
        !Ref CloudWatchLogsGroupName
      FilterPattern: '{ ($.errorCode = "*UnauthorizedOperation") || ($.errorCode =
        "AccessDenied*") }'
      MetricTransformations:
      - MetricNamespace: "CloudTrailMetrics"
        MetricName: "AuthorizationFailureCount"
        MetricValue: "1"
  AuthorizationFailuresAlarm:
    Type: AWS::CloudWatch::Alarm
    Metadata:
      cfn_nag:
        rules_to_suppress:
          - id: W28
            reason: "The alarm name is defined to identify AWS Landing Zone resources."
    DependsOn: ConsoleSignInFailuresAlarm
    Properties:
      #AlarmName: CloudTrailAuthorizationFailures
      AlarmDescription: Alarms when an unauthorized API call is made.
      MetricName: AuthorizationFailureCount
      Namespace: CloudTrailMetrics
      ComparisonOperator: GreaterThanOrEqualToThreshold
      EvaluationPeriods: 1
      Period: 300
      Statistic: Sum
      Threshold: 1
      TreatMissingData: notBreaching
  IAMPolicyChangesMetricFilter:
    Type: AWS::Logs::MetricFilter
    DependsOn: TrailLogGroup
    Properties:
      LogGroupName:
        !Ref CloudWatchLogsGroupName
      FilterPattern: "{($.eventName=DeleteGroupPolicy)||($.eventName=DeleteRolePolicy)||($.eventName=DeleteUserPolicy)||($.eventName=PutGroupPolicy)||($.eventName=PutRolePolicy)||($.eventName=PutUserPolicy)||($.eventName=CreatePolicy)||($.eventName=DeletePolicy)||($.eventName=CreatePolicyVersion)||($.eventName=DeletePolicyVersion)||($.eventName=AttachRolePolicy)||($.eventName=DetachRolePolicy)||($.eventName=AttachUserPolicy)||($.eventName=DetachUserPolicy)||($.eventName=AttachGroupPolicy)||($.eventName=DetachGroupPolicy)}"
      MetricTransformations:
      - MetricNamespace: "CloudTrailMetrics"
        MetricName: "IAMPolicyEventCount"
        MetricValue: "1"
  IAMPolicyChangesAlarm:
    Type: AWS::CloudWatch::Alarm
    Metadata:
      cfn_nag:
        rules_to_suppress:
          - id: W28
            reason: "The alarm name is defined to identify AWS Landing Zone resources."
    DependsOn: AuthorizationFailuresAlarm
    Properties:
      #AlarmName: IAMPolicyChanges
      AlarmDescription: Alarms when IAM policy changs are made.
      MetricName: IAMPolicyEventCount
      Namespace: CloudTrailMetrics
      ComparisonOperator: GreaterThanOrEqualToThreshold
      EvaluationPeriods: 1
      Period: 300
      Statistic: Sum
      Threshold: 1
      TreatMissingData: notBreaching
  RootLoginMetricFilter:
    Type: AWS::Logs::MetricFilter
    DependsOn: TrailLogGroup
    Properties:
      LogGroupName:
        !Ref CloudWatchLogsGroupName
      FilterPattern: '{ $.userIdentity.type = "Root" && $.userIdentity.invokedBy NOT EXISTS && $.eventType != "AwsServiceEvent" }'
      MetricTransformations:
      - MetricNamespace: "CloudTrailMetrics"
        MetricName: "RootLoginEventCount"
        MetricValue: "1"
  RootLoginAlarm:
    Type: AWS::CloudWatch::Alarm
    Metadata:
      cfn_nag:
        rules_to_suppress:
          - id: W28
            reason: "The alarm name is defined to identify AWS Landing Zone resources."
    DependsOn: IAMPolicyChangesAlarm
    Properties:
      #AlarmName: RootLogin
      AlarmDescription: Alarms when the root user logs in.
      MetricName: RootLoginEventCount
      Namespace: CloudTrailMetrics
      ComparisonOperator: GreaterThanOrEqualToThreshold
      EvaluationPeriods: 1
      Period: 300
      Statistic: Sum
      Threshold: 1
      TreatMissingData: notBreaching

  # # Create KMS CloudTrail S3 bucket encryption key
  # S3CloudTrailKey:
  #   Type: AWS::KMS::Key
  #   Properties:
  #     KeyPolicy:
  #       Version: 2012-10-17
  #       Id: k-isms-key-cloudtrails3
  #       Statement:
  #         - Sid: Enable IAM User Permissions
  #           Effect: Allow
  #           Principal:
  #             AWS: !Join
  #               - ""
  #               - - "arn:aws:iam::"
  #                 - !Ref "AWS::AccountId"
  #                 - ":root"
  #           Action: "kms:*"
  #           Resource: "*"
  #         - Sid: Allow VPC Flow Logs to use the key
  #           Effect: Allow
  #           Principal:
  #             Service:
  #               - delivery.logs.amazonaws.com
  #           Action: "kms:GenerateDataKey*"
  #           Resource: "*"

  # S3CloudTrailKeyAlias:
  #   Type: AWS::KMS::Alias
  #   Properties:
  #     AliasName: alias/cloudtrails3
  #     TargetKeyId:
  #       Ref: S3CloudTrailKey

  # Create CloudTrail encrypted S3 bucket for storage
  CloudTrailS3Bucket:
    # DependsOn:
    #   - S3CloudTrailKey
    Type: AWS::S3::Bucket
    DeletionPolicy: Retain
    UpdateReplacePolicy: Retain
    # Properties:
    #   BucketEncryption:
    #     ServerSideEncryptionConfiguration:
    #       - ServerSideEncryptionByDefault:
    #           KMSMasterKeyID: !Sub "arn:aws:kms:${AWS::Region}:${AWS::AccountId}:${S3CloudTrailKeyAlias}"
    #           SSEAlgorithm: "aws:kms"
    Properties:
      AccessControl: Private
      # Block Public Access Policy
      PublicAccessBlockConfiguration:
        BlockPublicAcls: true
        BlockPublicPolicy: true
        IgnorePublicAcls: true
        RestrictPublicBuckets: true
      # Versioning
      VersioningConfiguration:
        Status: Enabled
      BucketEncryption:
        ServerSideEncryptionConfiguration:
          - ServerSideEncryptionByDefault:
              SSEAlgorithm: AES256  
      LifecycleConfiguration:
        Rules:
        - Id: GlacierRule
          Prefix: glacier
          Status: Enabled
          ExpirationInDays: 365
          Transitions:
            - TransitionInDays: 180
              StorageClass: GLACIER
              
  CloudTrailBucketPolicy:
    Type: AWS::S3::BucketPolicy
    Properties:
      Bucket: !Ref CloudTrailS3Bucket
      PolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Sid: "AWSCloudTrailAclCheck"
            Effect: Allow
            Principal:
              Service: "cloudtrail.amazonaws.com"
            Action: "s3:GetBucketAcl"
            Resource: !Sub arn:aws:s3:::${CloudTrailS3Bucket}
          - Sid: "AWSCloudTrailWrite"
            Effect: Allow
            Principal:
              Service: "cloudtrail.amazonaws.com"
            Action: "s3:PutObject"
            Resource: !Sub arn:aws:s3:::${CloudTrailS3Bucket}/AWSLogs/${AWS::AccountId}/*
            Condition:
              StringEquals:
                "s3:x-amz-acl": "bucket-owner-full-control"
  S3UploadBucket:
    DeletionPolicy: Retain
    UpdateReplacePolicy: Retain
    Type: AWS::S3::Bucket
    Properties:
      BucketName:
        !Sub
          - isms-conformance-delivery-${AWS::Region}-${X}
          - X: !Select [0, !Split [-, !Select [2, !Split [/, !Ref AWS::StackId ]]]]
      AccessControl: Private
      # Block Public Access Policy
      PublicAccessBlockConfiguration:
        BlockPublicAcls: true
        BlockPublicPolicy: true
        IgnorePublicAcls: true
        RestrictPublicBuckets: true
      # Versioning
      VersioningConfiguration:
        Status: Enabled
      BucketEncryption:
        ServerSideEncryptionConfiguration:
          - ServerSideEncryptionByDefault:
              SSEAlgorithm: AES256
  ConformanceServiceLinkedRole:
    Type: AWS::IAM::ServiceLinkedRole
    Properties: 
      AWSServiceName: config-conforms.amazonaws.com
      Description: my service linked role for config-conforms
  S3UploadBucketPolicy:
    Type: AWS::S3::BucketPolicy
    Properties:
      Bucket: !Ref S3UploadBucket
      PolicyDocument:
        Version: 2012-10-17
        Statement:
          - Sid: EnforceHTTPSConnections
            Action: s3:*
            Effect: Deny
            Principal: '*'
            Resource:
              !Sub
                - arn:aws:s3:::isms-conformance-delivery-${AWS::Region}-${X}/*
                - X: !Select [0, !Split [-, !Select [2, !Split [/, !Ref AWS::StackId ]]]]
            Condition:
              Bool:
                aws:SecureTransport: false
          - Sid: AWSConfigConformsBucketPermissionsCheck
            Effect: Allow
            Principal:
              AWS:
              - !Sub arn:aws:iam::${AWS::AccountId}:role/aws-service-role/config-conforms.amazonaws.com/AWSServiceRoleForConfigConforms
            Action: s3:GetBucketAcl
            Resource:
              !Sub
                - arn:aws:s3:::isms-conformance-delivery-${AWS::Region}-${X}
                - X: !Select [0, !Split [-, !Select [2, !Split [/, !Ref AWS::StackId ]]]]
          - Sid: AWSConfigConformsBucketDelivery
            Effect: Allow
            Principal:
              AWS:
              - !Sub arn:aws:iam::${AWS::AccountId}:role/aws-service-role/config-conforms.amazonaws.com/AWSServiceRoleForConfigConforms
            Action: s3:PutObject
            Resource:
              !Sub
                - arn:aws:s3:::isms-conformance-delivery-${AWS::Region}-${X}/AWSLogs/${AWS::AccountId}/Config/*
                - X: !Select [0, !Split [-, !Select [2, !Split [/, !Ref AWS::StackId ]]]]
            Condition:
              StringEquals:
                s3:x-amz-acl: bucket-owner-full-control
          - Sid: AWSConfigConformsBucketReadAccess
            Effect: Allow
            Principal:
              AWS:
              - !Sub arn:aws:iam::${AWS::AccountId}:role/aws-service-role/config-conforms.amazonaws.com/AWSServiceRoleForConfigConforms
            Action: s3:GetObject
            Resource:
              !Sub
                - arn:aws:s3:::isms-conformance-delivery-${AWS::Region}-${X}/AWSLogs/${AWS::AccountId}/Config/*
                - X: !Select [0, !Split [-, !Select [2, !Split [/, !Ref AWS::StackId ]]]]
  ISMSConformancePack:
    Type: AWS::Config::ConformancePack
    DependsOn: S3UploadBucketPolicy
    Properties:
      ConformancePackName: !Sub ISMS-ConformancePackName-${AWS::StackName}
      DeliveryS3Bucket: !Ref S3UploadBucket
      TemplateS3Uri: !Sub s3://${QSS3BucketName}/${QSS3KeyPrefix}templates/config-rules.template.yaml
      # TemplateS3Uri: !Sub
      #   - https://${S3Bucket}.s3.${S3Region}.${AWS::URLSuffix}/${QSS3KeyPrefix}templates/config-rules.template.yaml
      #   - S3Region: !If [ UsingDefaultBucket, !Ref 'AWS::Region', !Ref QSS3BucketRegion ]
      #     S3Bucket: !If [ UsingDefaultBucket, !Sub '${QSS3BucketName}-${AWS::Region}', !Ref QSS3BucketName ]
Outputs:
  SysAdmin:
    Value: !Ref SysAdminGroup
  IAMAdminGroup:
    Value: !Ref IAMAdminGroup
  InstanceOpsGroup:
    Value: !Ref InstanceOpsGroup
  ReadOnlyBillingGroup:
    Value: !Ref ReadOnlyBillingGroup
  ReadOnlyAdminGroup:
    Value: !Ref ReadOnlyAdminGroup
  CloudTrailKMSKeyAlias:
    Description: "CloudTrail KMS Key Alias"
    Value:
      Ref: "CloudTrailKeyAlias"
  # S3KMSKeyAlias:
  #   Description: "S3 KMS Key Alias"
  #   Value:
  #     Ref: "S3CloudTrailKeyAlias"
  CloudTrailS3Bucket:
    Description: "Encrypted S3 Bucket for CloudTrail Logs"
    Value:
      Ref: "CloudTrailS3Bucket"
  # CloudTrailS3BucketPolicy:
  #   Description: "S3 Bucket Policy for CloudTrail Logs"
  #   Value:
  #     Ref: "CloudTrailBucketPolicy"
  CloudTrail:
    Description: "CloudTrail"
    Value:
      Ref: "CloudTrail"