【CloudFormation】SSM ステートマネージャーを使ってCloudWatch Agentのインストールとログ出力設定を自動化してみる

起動したEC2インスタンスに自動でCloudWatch Agentのインストールとログ出力設定をしてみたよ
2023.07.20

Systems Manager State Manager(以下ステートマネージャー)はSSM管理下のインスタンスのあるべき状態を定義できる機能です。

インスタンスが起動したタイミングで、必ず設定しておきたい状態をステートマネージャーで定義することでアカウント内の統制をとることが可能です。

今回はこのステートマネージャーを使うことで、CloudWatch AgentのインストールとCloudWatch Logsへのログ出力設定を自動化してみました。

作成するもの

こんな感じのイメージです。Systems Mmanagerのリソースを展開したあと、EC2インスタンス(Linux/Windows)を作成してCloudWatch Logsにログが出力されるか確認します。

SSMドキュメント

自作のInstallAndManageCloudWatchDocumentを作成してます。AWS提供のドキュメントを組み合わせてCloudWatch Agentのインストールとログ出力設定を行います。 また、Amazon Linux 2023ではrsyslogがインストールされておらず、これまでの/var/log/messagesなどのログが出力されなくなっているので、Linuxの場合はインストールする処理も入れています。

Amazon Linux 2023の詳細については以下をご参照ください。

Amazon Linux 2023とAmazon Linux2のデフォルトで起動しているサービスやインストールされているパッケージを比較してみた | DevelopersIO

  • AWS-ConfigureAWSPackage
    • CloudWatch Agentをインストール
  • AmazonCloudWatch-ManageAgent
    • CloudWatch Agentのログ出力設定
      • 設定値はパラメータストアから取得
    • Windows/Linuxのプラットフォームで処理を分岐
  • AWS-RunShellScript(Linuxの場合のみ)
    • rsyslogをインストール・起動

ステートマネージャー

以下の設定で行います。 - 実行対象 - 全てのインスタンス - スケジュール - 1回のみ(インスタンス起動時のみ)

パラメータストア

ログ出力の定義値を登録します。今回はLunixとWindowsで以下2つです。

  • AmazonCloudWatch-Linux-syslog
    • /var/log/messagesを出力
  • AmazonCloudWatch-Windows-syslog
    • Systemを出力

やってみる

CloudFormationスタックの作成

Systems ManagerのリソースはCloudFormationテンプレートで作成しました。

以下のテンプレートを使ってスタックを作成してください。

ちょっと長いので折りたたみます。(↓クリックして開いてね)

CloudFormationテンプレート
AWSTemplateFormatVersion: "2010-09-09"

Parameters:
  LogGroupPrefix:
    Type: "String"
    Default: "oslog-linux-syslog"
    AllowedValues: ["oslog-linux-syslog"]
  LogGroupPrefixWindows:
    Type: "String"
    Default: "oslog-windows-syslog"
    AllowedValues: ["oslog-windows-syslog"]
  RetentionDays:
    Description: The number of days to retain the log events in the specified log group.
    Type: Number
    Default: 30
    AllowedValues: [1, 3, 5, 7, 14, 30, 60, 90, 120, 150, 180, 365]

Resources:
  # 取得する syslog を定義する SSM Parameter
  ## Linux
  SSMParameterLinuxLogs:
    Type: "AWS::SSM::Parameter"
    Properties:
      Name: !Sub "AmazonCloudWatch-Linux-syslog"
      Description: "SSM Parameter for Linux to export syslog."
      DataType: "text"
      Tier: "Standard"
      Type: "String"
      Value: !Sub |-
        {
          "agent": {
            "run_as_user": "root"
          },
          "logs":
            {
              "logs_collected":
                {
                  "files":
                    {
                      "collect_list":
                        [
                          {
                            "file_path": "/var/log/messages",
                            "log_group_name": "${LogGroupPrefix}-${AWS::Region}/var/log/messages",
                            "log_stream_name": "{instance_id}",
                            "retention_in_days": ${RetentionDays}
                          }                        
                        ]
                    }
                }
            }
        }
  ## Windows
  SSMParameterWindowsLogs:
    Type: "AWS::SSM::Parameter"
    Properties:
      Name: !Sub "AmazonCloudWatch-Windows-syslog"
      Description: "SSM Parameter for Windows to export syslog."
      DataType: "text"
      Tier: "Standard"
      Type: "String"
      Value: !Sub |-
        {
          "agent": {
            "run_as_user": "root"
          },
          "logs":
            {
              "logs_collected":
                {
                  "windows_events":
                    {
                      "collect_list":
                        [
                          {
                            "event_format": "xml",
                            "event_levels": [
                              "WARNING",
                              "ERROR",
                              "CRITICAL"
                            ],
                            "event_name": "System",
                            "log_group_name": "${LogGroupPrefixWindows}-${AWS::Region}/System",
                            "log_stream_name": "{instance_id}",
                            "retention_in_days": ${RetentionDays}
                          }
                        ]
                    }
                }
            }
        }

  InstallAndManageCloudWatchDocument:
    Type: "AWS::SSM::Document"
    Properties:
      DocumentType: Command
      Name: InstallAndManageCloudWatchDocument
      UpdateMethod: NewVersion
      Content:
        schemaVersion: "2.2"
        description: "The AWS-InstallAndManageCloudWatch command document installs the Amazon CloudWatch agent and manages the configuration of the agent for Amazon EC2 instances."
        mainSteps:
          - name: installCWAgent
            action: "aws:runDocument"
            inputs:
              documentType: SSMDocument
              documentPath: AWS-ConfigureAWSPackage
              documentParameters:
                action: Install
                name: AmazonCloudWatchAgent
          # Amazon Linux 2023では rsyslog が未インストール
          - name: installRsyslogLinux
            action: "aws:runDocument"
            precondition:
              StringEquals:
                - platformType
                - Linux
            inputs:
              documentType: SSMDocument
              documentPath: AWS-RunShellScript
              documentParameters:
                commands:
                  - yum install rsyslog -y
                  - sudo systemctl enable rsyslog
                  - sudo systemctl restart rsyslog
          - name: manageCWAgentLinux
            action: "aws:runDocument"
            precondition:
              StringEquals:
                - platformType
                - Linux
            inputs:
              documentType: SSMDocument
              documentPath: AmazonCloudWatch-ManageAgent
              documentParameters:
                action: configure
                mode: ec2
                optionalConfigurationSource: ssm
                optionalConfigurationLocation: !Ref SSMParameterLinuxLogs
                optionalRestart: "yes"
          - name: manageCWAgentWindows
            action: "aws:runDocument"
            precondition:
              StringEquals:
                - platformType
                - Windows
            inputs:
              documentType: SSMDocument
              documentPath: AmazonCloudWatch-ManageAgent
              documentParameters:
                action: configure
                mode: ec2
                optionalConfigurationSource: ssm
                optionalConfigurationLocation: !Ref SSMParameterWindowsLogs
                optionalRestart: "yes"

  SystemAssociationForInstallAndConfigureCloudWatchAgent:
    Type: "AWS::SSM::Association"
    Properties:
      Name:
        Ref: InstallAndManageCloudWatchDocument
      AssociationName: ManageCloudWatchAgent
      ScheduleExpression:
        Ref: "AWS::NoValue"
      Targets:
        - Key: InstanceIds
          Values:
            - "*"

パラメータとしてロググループのプレフィクスと保持期間が設定できます。今回はすべてデフォルトのまま進めます。

スタックの作成が完了したらOKです。

EC2の起動

起動するEC2は以下が前提です。

今回は以下のAMIを使います。

  • Amazon linux 2
  • Amazon linux 2023
  • Windows Server 2022 Base

IAMロールの権限が不足しないよう注意してください。最小権限であれば、以下2つのポリシーをアタッチします。

  • CloudWatchAgentServerPolicy
  • AmazonSSMManagedInstanceCore

以下3つのインスタンスを起動して、すべてにIAMロールをアタッチしました。

CloudWatch Logsの確認

少し時間をおいてCloudWatch Logsを見ると、CloudWatch Logsのロググループが作成されているのを確認できました。

Linux側は2つのインスタンスを起動したので、ログストリームに2つのインスタンスIDが作成されています。

Amazon Lunux 2023のインスタンスもログが出力できたので、rsyslogのインストールと起動も問題ないようです。

無事ステートマネージャーを使って、EC2のCloudWatch Agentのインストールとログ出力設定を自動化できました。

まとめ

ステートマネージャーを使ってCloudWatch Agentのインストールとログ出力設定を自動化してみました。

この仕組みはEC2がSSM管理になっていることが前提なので、以下のようなConfigルールで非管理状態のものを検知できる仕組みがあるとよさそうです。

ec2-instance-managed-by-systems-manager - AWS Config

SSMドキュメントをうまく書ければ他にも色々できるので、管理方法に合わせたものを作れると運用が楽になります!EC2管理に統制をかけたい場合は是非試してみてください。

参考