Ubuntu 20.04 The story of creating CFn that installs CloudWatch agent on LTS and creates a configuration file

Introduction

CloudFormation helper scripts are very useful, aren't they? Just by defining a script in the template, you can install the software and start the service when creating EC2.

This time, I had the opportunity to install the Cloudwatch agent and create a configuration file using that helper script, so I'd like to write it so that I don't forget it.

Environment to build

Create CFn

Preparing helper scripts

Immediately install the cloudwatch agent using the helper script! Unfortunately, it is not installed on Ubuntu by default. So, first download the aws-cfn-bootstrap package. Add the following script to the helper script in UserDate that is executed when EC2 starts.


apt-get update
apt-get install -y python-setuptools
mkdir -p /opt/aws/bin
apt-get install -y wget
wget https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-py3-latest.tar.gz
python3 -m easy_install --script-dir /opt/aws/bin aws-cfn-bootstrap-py3-latest.tar.gz

▶ Helper Script Reference

Install CloudWatch Agent

Then install the cloudwatch agent. Add this to UserDate as well.


wget https://s3.amazonaws.com/amazoncloudwatch-agent/ubuntu/amd64/latest/amazon-cloudwatch-agent.deb -O /tmp/amazon-cloudwatch-agent.deb
dpkg -i /tmp/amazon-cloudwatch-agent.deb
/opt/aws/bin/cfn-init -v --stack ${AWS::StackId} --resource EC2 --region ${AWS::Region} --configsets default
/opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackId} --resource EC2 --region ${AWS::Region}

Creating amazon-cloudwatch-agent.json

Now that we have installed the helper script and cloudwatch agent, let's create the configuration file amazon-cloudwatch-agent.json. For how to write the configuration file, I referred to Official Document.

Creating a helper script

Next is finally the helper script. You can bring metadata for the cfn-init helper script into EC2 by using the AWS :: CloudFormation :: Init type.

--hooks.conf configuration file A user action that the cfn-hup daemon calls on a regular basis is defined.

--cfn-hup.conf configuration file Contains the name of the stack targeted by the cfn-hup daemon and AWS credentials.

This time, when creating a new stack, go to default, and when updating the metadata by updating the stack, go to UpdateEnvironment.

  EC2:
    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"
 
        01_setupCfnHup:
          files:
            /etc/cfn/cfn-hup.conf:
              content: !Sub |
                [main]
                stack=${AWS::StackName}
                region=${AWS::Region}
                interval=1
              mode: '000400'
              owner: root
              group: root
            /etc/cfn/hooks.d/cfn-auto-reloader.conf:
              content: !Sub |
                [cfn-auto-reloader-hook]
                triggers=post.update
                path=Resources.EC2.Metadata.AWS::CloudFormation::Init
                action=/opt/aws/bin/cfn-init -v --stack ${AWS::StackName} --resource EC2 --configsets UpdateEnvironment --region ${AWS::Region}
                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: "systemctl enable cfn-hup.service"
            02start_cfn_hup:
              command: "systemctl start cfn-hup.service"
        02_config_amazon-cloudwatch-agent:
          files:
            /opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.json:
              content: !Sub |
                {
                  //Here amazon-cloudwatch-agent.write json//
                }
              mode: '000644'
              owner: root
              group: root

        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 -s -c file:/opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.json"

It's a bit of a mess, but the "03_restart_amazon-cloudwatch-agent" command

/opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -a fetch-config -m ec2 -s -c file:/opt/aws/amazon-cloudwatch-agent/etc/amazon-cloudwatch-agent.json

Then, it seems that the agent is started by converting the json file to the toml format configuration file amazon-cloudwatch-agent.toml. Therefore, the file amazon-cloudwatch-agent.json does not exist in EC2 created with this CFn.

Create roles for CloudWatch Agent

You must have permission to access AWS resources. Let's create an IAM role that gives EC2 the necessary privileges. I have created a role CloudwatchRole with the following policy attached.

--AWS Managed Policy - CloudWatchAgentServerPolicy - CloudWatchAgentAdminPolicy - AmazonSSMManagedInstanceCore --Custom policy --This time, I added a policy to allow access to S3 and logs. Good luck with the situation.

  CloudwatchRole:
    Type: AWS::IAM::Role
    Properties: 
      RoleName: "CloudwatchRole"
      Path: /
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - ec2.amazonaws.com
            Action:
              - 'sts:AssumeRole'
      Path: /
      Policies:
        - PolicyName: CloudwatchRolePolicy
          PolicyDocument:
            Version: 2012-10-17
            Statement: 
                  - Effect: Allow
                    Action:
                      //abridgement//
                    Resource: '*'
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy
        - arn:aws:iam::aws:policy/CloudWatchAgentAdminPolicy
        - arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore

Creating an instance profile

Finally, create an instance profile to pass the role you just created to EC2.

  CWAgentInstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Properties:
      Path: "/"
      Roles:
      - !Ref CloudwatchRole

in conclusion

I've been addicted to creating CloudFormation, but it's easier to do it with CFn than to set it up with a wizard!

CloudFormation is full of things I still don't understand. It's deep.

(I would be grateful if you could tell me if there is another better way, I'm making a mistake here!)

Reference site

--CloudFormation Helper Script Reference --AWS CloudFormation

--Manually create or edit CloudWatch agent configuration file --Amazon CloudWatch

--Install AWS CloudFormation helper scripts on Ubuntu or RHEL AMI

-First CloudWatch Agent introduction (SSM & CentOS) --Serverworks Engineer Blog

-(For beginners) Install CloudWatch Agent on EC2 and launch it on SSM | Developers.IO

-Try CloudWatch Agent-ngyuki's diary

Recommended Posts

Ubuntu 20.04 The story of creating CFn that installs CloudWatch agent on LTS and creates a configuration file
The story of installing raspi-config on ubuntu 18.04 and changing the initial settings of GPIO
A story that deepened the understanding of devise's methods user_signed_in? And current_user through error resolution
A story of frustration trying to create a penetration environment on Ubuntu 20.04
A story that struggled with the introduction of Web Apple Pay
Create a development environment for Ruby 3.0.0 and Rails 6.1.0 on Ubuntu 20.04.1 LTS
Creating a dual boot environment for Ubuntu Server 20.04.1 LTS and Windows 10
A story that confirmed the profile of Yasuko Sawaguchi 36 years ago
Creating an ArrayList that allows you to throw in and retrieve the coordinates of a two-dimensional plane
A story that I was addicted to twice with the automatic startup setting of Tomcat 8 on CentOS 8
How to operate IGV using socket communication, and the story of making a Ruby Gem using that method
A story about creating a service that proposes improvements to a website using a machine learning API
A story about making a Builder that inherits the Builder
A story about creating a library that operates next-generation sequencer data with Ruby ruby-htslib
A story about developing ROS called rosjava with java
A story about making catkin_make of rosjava compatible offline
A story that turbolinks was confused by doing something wrong
Creating a batch of Liferay
A story about hitting the League Of Legends API with JAVA
A story that struggled with the introduction of Web Apple Pay
A story that confirmed the profile of Yasuko Sawaguchi 36 years ago
Ubuntu 20.04 The story of creating CFn that installs CloudWatch agent on LTS and creates a configuration file
This and that of the JDK
A collection of phrases that impresses the "different feeling" of Java and JavaScript
Sample program that returns the hash value of a file in Java
A story that was embarrassing to give anison file to the production environment