AWSTemplateFormatVersion: "2010-09-09"
Description: Provision the required resources for your blog post example 'Shipping AWS EC2 logs to CloudWatch
  using the CloudWatch agent'. Wait for the creation to complete before testing.
Parameters:
  AmiId:
    Type: 'AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>'
    Default: '/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2'
    Description: AMI ID pointer in AWS Systems Manager Parameter Store. Default value points to the
      latest Amazon Linux 2 AMI ID.
Resources:
  VPC:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.0.0.0/24
      Tags:
        - Key: Name
          Value: !Sub 'VPC - ${AWS::StackName}'
  InternetGateway:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
        - Key: Name
          Value: !Sub 'IGW - ${AWS::StackName}'
  AttachGateway:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId: !Ref VPC
      InternetGatewayId: !Ref InternetGateway
  PublicSubnet:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref VPC
      CidrBlock: 10.0.0.128/26
      MapPublicIpOnLaunch: True
      AvailabilityZone: !Select
        - 0
        - !GetAZs
          Ref: 'AWS::Region'
      Tags:
        - Key: Name
          Value: !Sub 'Public Subnet 1 - ${AWS::StackName}'
  PublicRouteTable:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: !Sub 'Public Route Table - ${AWS::StackName}'
  PublicRouteTableEntry:
    Type: AWS::EC2::Route
    DependsOn: AttachGateway
    Properties:
      RouteTableId: !Ref PublicRouteTable
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref InternetGateway
  PublicRouteTableSubnetAssociation:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref PublicSubnet
      RouteTableId: !Ref PublicRouteTable
  EC2Instance:
    Type: AWS::EC2::Instance
    Metadata:
      AWS::CloudFormation::Init:
        configSets:
          default:
            - 01_setupCfnHup
            - 02_config-amazon-cloudwatch-agent
            - 03_restart_amazon-cloudwatch-agent
          UpdateEnvironment:
            - 02_config-amazon-cloudwatch-agent
            - 03_restart_amazon-cloudwatch-agent
        # Definition of json configuration of AmazonCloudWatchAgent, you can change the configuration below.
        02_config-amazon-cloudwatch-agent:
          files:
            '/opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.json':
              content: !Sub |
                {
                  "logs": {
                    "logs_collected": {
                      "files": {
                        "collect_list": [
                          {
                            "file_path": "/var/log/secure",
                            "log_group_name": "${EC2LogGroup}",
                            "log_stream_name": "{instance_id}/var/log/secure"
                          }
                        ]
                      }
                    }
                  }
                }
        # Invoke amazon-cloudwatch-agent-ctl to restart the AmazonCloudWatchAgent.
        03_restart_amazon-cloudwatch-agent:
          commands:
            01_stop_service:
              command: /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -a stop
            02_start_service:
              command: /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -a fetch-config -m ec2 -c file:/opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.json -s
        # Cfn-hup setting, it is to monitor the change of metadata.
        # When there is change in the contents of json file in the metadata section, cfn-hup will call cfn-init to restart the AmazonCloudWatchAgent.
        01_setupCfnHup:
          files:
            '/etc/cfn/cfn-hup.conf':
              content: !Sub |
                [main]
                stack=${AWS::StackId}
                region=${AWS::Region}
                interval=1
              mode: '000400'
              owner: root
              group: root
            '/etc/cfn/hooks.d/amazon-cloudwatch-agent-auto-reloader.conf':
              content: !Sub |
                [cfn-auto-reloader-hook]
                triggers=post.update
                path=Resources.EC2Instance.Metadata.AWS::CloudFormation::Init.02_config-amazon-cloudwatch-agent
                action=/opt/aws/bin/cfn-init -v --stack ${AWS::StackId} --resource EC2Instance --region ${AWS::Region} --configsets UpdateEnvironment
                runas=root
              mode: '000400'
              owner: root
              group: root
            "/lib/systemd/system/cfn-hup.service":
              content: !Sub |
                [Unit]
                Description=cfn-hup daemon
                [Service]
                Type=simple
                ExecStart=/opt/aws/bin/cfn-hup
                Restart=always
                [Install]
                WantedBy=multi-user.target
          commands:
            01enable_cfn_hup:
              command: !Sub |
                systemctl enable cfn-hup.service
            02start_cfn_hup:
              command: !Sub |
                systemctl start cfn-hup.service
    Properties:
      IamInstanceProfile: !Ref EC2InstanceProfile
      ImageId: !Ref AmiId
      InstanceType: t3.nano
      SecurityGroupIds:
        - !GetAtt VPC.DefaultSecurityGroup
      SubnetId: !Ref PublicSubnet
      Tags:
        - Key: Name
          Value: !Sub 'CloudWatch agent demo instance - ${AWS::StackName}'
      UserData:
        # This script below is to install AmazonCloudWatchAgent, restart AmazonCloudWatchAgent and tell the result to cloudformation.
        Fn::Base64: !Sub |
          #!/bin/bash
          rpm -Uvh https://s3.amazonaws.com/amazoncloudwatch-agent/amazon_linux/amd64/latest/amazon-cloudwatch-agent.rpm
          /opt/aws/bin/cfn-init -v --stack ${AWS::StackId} --resource EC2Instance --region ${AWS::Region} --configsets default
          /opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackId} --resource EC2Instance --region ${AWS::Region}
  EC2InstanceRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - ec2.amazonaws.com
            Action:
              - sts:AssumeRole
      Path: /
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
        - arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy
      Policies:
        - PolicyName: root
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - ec2:DescribeRegions
                Resource: '*'

  EC2InstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Properties:
      Roles:
        - !Ref EC2InstanceRole
      Path: /
  EC2LogGroup:
    Type: AWS::Logs::LogGroup
    Properties:
      LogGroupName: 'ec2-instance'
      RetentionInDays: 7
  MetricFilter:
    Type: AWS::Logs::MetricFilter
    Properties:
      LogGroupName: !Ref EC2LogGroup
      FilterPattern: 'password changed'
      MetricTransformations:
        -
          MetricValue: 1
          MetricNamespace: EC2
          MetricName: ChangePassword
  Alarm:
    Type: AWS::CloudWatch::Alarm
    Properties:
      AlarmName: PasswordChangedAlarm
      MetricName: ChangePassword
      Namespace: EC2
      ComparisonOperator: GreaterThanOrEqualToThreshold
      EvaluationPeriods: 1
      Period: 60
      Statistic: Sum
      Threshold: 1
      TreatMissingData: notBreaching