Cloud Intelligence™Cloud Intelligence™

Cloud Intelligence™

Automatizzare installazione e configurazione di CloudWatch Agent con Systems Manager ed EventBridge

By Nikhil PawarMar 28, 20247 min read

Questa pagina è disponibile anche in English, Deutsch, Español, Français, 日本語 e Português.

Foto di Alexander+Supertramp da Shutterstock

In questo articolo automatizzeremo end-to-end l'installazione e la configurazione del CloudWatch agent su istanze EC2 (Linux) per raccogliere metriche di memoria personalizzate, sfruttando un runbook di automazione di Systems Manager. Useremo un runbook personalizzato per gestire installazione e configurazione del CloudWatch agent e AWS EventBridge per avviare l'automazione senza alcun intervento manuale.

Diagramma architetturale di base

Panoramica dell'automazione

Per questa automazione utilizzeremo un template AWS CloudFormation per il deploy delle risorse, articolato nei seguenti passaggi:

  1. Creazione di un ruolo IAM con cui AWS Systems Manager esegue il documento di automazione — Systems Manager necessita di un ruolo di esecuzione per lanciare il runbook per Suo conto sulle istanze EC2 di destinazione e per concedere a tali istanze le autorizzazioni necessarie a scrivere metriche su CloudWatch.
  2. Caricamento del file di configurazione del CloudWatch agent nel Parameter Store di Systems Manager — il template CloudFormation carica il file di configurazione personalizzato del CloudWatch agent nel Parameter Store di Systems Manager. Le istanze recupereranno questo file per configurare il CloudWatch agent.
  3. Creazione del documento di automazione di Systems Manager — con CloudFormation costruiamo un runbook personalizzato per installare e configurare il CloudWatch agent.
  4. Creazione del ruolo IAM con cui la regola EventBridge invoca l'automazione di Systems Manager — EventBridge richiede un ruolo di invocazione per attivare il workflow di automazione di Systems Manager che installa e configura il CloudWatch agent.
  5. Creazione della regola EventBridge — CloudFormation crea una regola EventBridge che intercetta gli eventi di stato "running" delle istanze EC2 e fa partire l'automazione SSM.
  6. Opzionale (creazione di una SQS Dead Letter Queue) — una coda SQS standard che funge da Dead Letter Queue per la regola EventBridge, utile a raccogliere gli eventuali dettagli degli errori nei trigger.

Template CloudFormation

AWSTemplateFormatVersion: '2010-09-09'
Description: A template to create an AWS Systems Manager Automation Document that installs Amazon CloudWatch agent, sets up necessary permissions, and configures CloudWatch agent to publish memory metrics to CloudWatch and trigger SSM automation with eventbridge rule
Resources:
  SsmAutomationRole:
    Type: AWS::IAM::Role
    Properties:
      Description: IAM role for AWS Systems Manager to execute automation document
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: ssm.amazonaws.com
            Action: sts:AssumeRole
            Condition:
              StringEquals:
                aws:SourceAccount: !Sub ${AWS::AccountId}
              ArnLike:
                aws:SourceArn: !Sub arn:${AWS::Partition}:ssm:*:${AWS::AccountId}:automation-execution/*
      ManagedPolicyArns:
        - !Sub arn:${AWS::Partition}:iam::aws:policy/service-role/AmazonSSMAutomationRole
      Path: /
      Policies:
        - PolicyName: SsmMemMetricIamPolicy
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - iam:GetRole
                  - iam:GetInstanceProfile
                  - iam:GetPolicy
                  - iam:AttachRolePolicy
                  - iam:ListInstanceProfiles
                  - ec2:DescribeInstances
                Resource: '*'
  CloudWatchAgentConfigFile:
    Type: AWS::SSM::Parameter
    Properties:
      Name: CloudwatchAgentConfigForMemoryMetricsLinux.json
      Description: Store CloudWatch Agent configuration file as AWS Systems Manager Parameter
      Type: String
      Value: |
        {
            "agent": {
                    "metrics_collection_interval": 60,
                    "run_as_user": "cwagent"
            },
            "metrics": {
                    "append_dimensions": {
                        "InstanceId": "${aws:InstanceId}"
                    },
                    "metrics_collected": {
                    "mem": {
                            "measurement": [\
                                "mem_used_percent"\
                            ],
                            "metrics_collection_interval": 60
                    }
                }
            }
        }
  SystemManagersMemoryMetricsRunbook:
    Type: AWS::SSM::Document
    Properties:
      DocumentFormat: YAML
      DocumentType: Automation
      Name: CloudwatchAgent_Install_Configure_MemoryMetrics_OnEC2Linux
      Content:
        description: Install CloudWatch Agent, Add permissions to target instances and configure CloudWatch agent to publish metrics
        schemaVersion: '0.3'
        assumeRole: !Sub ${SsmAutomationRole.Arn}
        parameters:
          InstanceId:
            type: String
            description: Select instances
        mainSteps:
          - name: Attach_CloudWatchAgent_ServerPolicy_to_instance_role
            action: aws:executeScript
            onFailure: Abort
            isCritical: true
            timeoutSeconds: 600
            description: |
              ## Find the attached role, attach CloudWatchAgentServer managed policy to the role
            inputs:
              Runtime: python3.8
              Handler: attach_cloudwatch_agent_managed_policy
              InputPayload:
                InstanceIds: '{{InstanceId}}'
              Script: |
                import boto3
                ec2_client = boto3.client('ec2')
                iam_client = boto3.client('iam')
                current_session = boto3.session.Session()
                current_region = current_session.region_name
                partition = current_session.get_partition_for_region(current_region)
                cloudwatchagent_policy_arn = f'arn:{partition}:iam::aws:policy/CloudWatchAgentServerPolicy'
                def attach_cloudwatch_agent_managed_policy(event,context):
                  instance_id = event['InstanceIds']
                  response = ec2_client.describe_instances(InstanceIds=[instance_id])
                  iam_role = response['Reservations'][0]['Instances'][0]['IamInstanceProfile']['Arn']
                  role_name=iam_role.split('/')[-1]
                  iam_client.attach_role_policy(RoleName=role_name, PolicyArn=cloudwatchagent_policy_arn)
          - name: Install_cloudWatchAgent_onTargetInstance
            action: aws:runCommand
            onFailure: Abort
            inputs:
              Parameters:
                action:
                  - Install
                installationType:
                  - Uninstall and reinstall
                name:
                  - AmazonCloudWatchAgent
              DocumentName: AWS-ConfigureAWSPackage
              InstanceIds:
                - '{{InstanceId}}'
          - name: Configure_CloudWatchAgen_onTargetInstance
            action: aws:runCommand
            inputs:
              DocumentName: AmazonCloudWatch-ManageAgent
              InstanceIds:
                - '{{InstanceId}}'
              Parameters:
                action: configure
                mode: ec2
                optionalConfigurationSource: ssm
                optionalConfigurationLocation: CloudwatchAgentConfigForMemoryMetricsLinux.json
                optionalRestart: 'yes'
  AutomationIAMRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: Amazon_EventBridge_Invoke_Start_Automation_Execution
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: events.amazonaws.com
            Action: sts:AssumeRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/service-role/AmazonSSMAutomationRole  # AmazonSSMAutomationRole managed policy
  EventRule:
     Type: AWS::Events::Rule
     Properties:
       EventBusName: default
       EventPattern:
         source:
           - aws.ec2
         detail-type:
           - EC2 Instance State-change Notification
         detail:
           state:
             - running
       Name: cloudwatch-install-configure-rule
       State: ENABLED
       Targets:
         - Id: cloudwatch-ssm-document
           #Arn: >-
            # arn:aws:ssm:us-east-1:XXXXXXXXXXX:automation-definition/CloudwatchAgent_Install_Configure_MemoryMetrics_OnEC2Linux
            #arn:${Partition}:ssm:${Region}:${Account}:document/${DocumentName}
           Arn: !Sub arn:${AWS::Partition}:ssm:${AWS::Region}:${AWS::AccountId}:automation-definition/CloudwatchAgent_Install_Configure_MemoryMetrics_OnEC2Linux
           RoleArn: !Sub ${AutomationIAMRole.Arn}
           InputTransformer:
             InputPathsMap:
               instance: $.detail.instance-id
             InputTemplate: '{"InstanceId":[<instance>]}'
           DeadLetterConfig:
             Arn: !Sub ${SQSQueue.Arn}
  SQSQueue:
    Type: AWS::SQS::Queue
    Properties:
      MaximumMessageSize: 262144 #integer value from 1,024 bytes (1 KiB) to 262,144 bytes (256 KiB). The default value is 262,144 (256 KiB).
      MessageRetentionPeriod: 345600 # 4 Days
      QueueName: DLQ-for-event-bridge

Outputs:
  SsmAutomationRoleName:
    Description: Name of the SSM Automation IAM Role
    Value: !Ref SsmAutomationRole
  IAMRoleArn:
    Description: ARN of the created IAM role
    Value: !GetAtt AutomationIAMRole.Arn
  IAMRoleName:
    Description: Name of the created IAM role
    Value: !Ref AutomationIAMRole
  AutomationIAMRoleArn:
    Description: EventBridge Invokation role name to Start Automation Execution
    Value: !GetAtt AutomationIAMRole.Arn
  SQSQueueArn:
    Description: SQS Queue to capture EventBridge execution errors
    Value: SQSQueue.Arn

Procedura

1. Crei lo stack CloudFormation sopra riportato da CLI o da console:

Passaggio 1

2. Verifichi il documento di automazione di Systems Manager appena distribuito: si compone di 3 passaggi:

  1. Individuare il ruolo associato all'istanza di destinazione e collegarvi la managed policy CloudWatchAgentServer.
  2. Installare il CloudWatch Agent sull'istanza di destinazione.
  3. Configurare il CloudWatch Agent affinché invii le metriche a CloudWatch.

Passaggio 2

3. Verifichi la regola Amazon EventBridge:

Passaggio 3

Event Pattern — l'event pattern seguente filtra gli eventi di stato "running" nel momento in cui si verificano.

Event
{
  "detail-type": ["EC2 Instance State-change Notification"],
  "source": ["aws.ec2"],
  "detail": {
    "state": ["running"]
  }
}

L'EventBridge Input transformation, invece, sfrutta l'Input Transformer riportato di seguito per estrarre l'ID dell'istanza di destinazione.

Input transformer

Input path
 {
   "instance": "$.detail.instance-id"
 }

Input template
 {
   "InstanceId":[<instance>]
 }

4. Crei una nuova istanza:

- L'istanza EC2 di test deve avere installato l'AWS Systems Manager Agent (SSM Agent) per poter dialogare con Systems Manager. Inoltre, le istanze EC2 devono raggiungere via rete gli endpoint pubblici di Systems Manager oppure gli endpoint AWS PrivateLink VPC per Systems Manager. (Nota: ho usato l'AMI Amazon Linux 2023, avviata nella VPC predefinita.)

- Crei un ruolo "EC2ssmCoreRole" con la managed policy AWS "AmazonSSMManagedInstanceCore", così che Systems Manager possa gestire l'istanza EC2. Crei poi un instance profile e vi associ il ruolo. Infine, avvii un'istanza di test (t2.micro). Per farlo ho usato il template CloudFormation di esempio riportato qui sotto.

AWSTemplateFormatVersion: 2010-09-09
Description: CloudFormation template to create EC2 instance with SSM role

Parameters:
  LatestAmiId:
    Type: 'AWS::SSM::Parameter::Value<AWS::EC2::Image::Id>'
    Default: '/aws/service/ami-amazon-linux-latest/amzn2-ami-hvm-x86_64-gp2'

Resources:
  EC2Role:
    Type: AWS::IAM::Role
    Properties:
      RoleName: EC2ssmCoreRole
      Description: IAM role to allow Systems Manager to manage the EC2 instance
      AssumeRolePolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service: ec2.amazonaws.com
            Action: sts:AssumeRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore

  EC2InstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Properties:
      Roles:
        - !Ref EC2Role
      InstanceProfileName: EC2ssmCoreRole

  EC2Instance:
    Type: AWS::EC2::Instance
    Properties:
      ImageId: !Ref LatestAmiId
      InstanceType: t2.micro
      IamInstanceProfile: !Ref EC2InstanceProfile
      Tags:
        - Key: Name
          Value: "Test-instance"
        - Key: Env
          Value: "test-environment"

Outputs:
  EC2ssmCoreRoleName:
    Description: Name of the SSM Automation IAM Role
    Value: !Ref EC2Role

  EC2ssmCoreRoleArn:
    Description: ARN of the created IAM role
    Value: !GetAtt EC2Role.Arn

  EC2InstanceId:
    Description: Instance Id
    Value: !Ref EC2Instance

5. Confermi che la regola EventBridge si sia attivata al passaggio dell'istanza nello stato "running" e che Systems Manager abbia eseguito l'automazione, installando e configurando il CloudWatch agent sull'istanza EC2 per l'invio delle metriche di memoria.

6. Controlli l'esecuzione dell'automazione di Systems Manager: appena l'istanza passa nello stato "running", la regola EventBridge si attiva e lancia il documento di automazione di Systems Manager.

Passaggio 6

7. Monitori stato e avanzamento dell'esecuzione: si svolge in 3 passaggi:

- Collegamento della policy CloudWatch Agent Server al ruolo dell'istanza.

- Installazione del CloudWatch Agent sull'istanza di destinazione.

- Configurazione del CloudWatch Agent recuperando il file di configurazione dal Parameter Store di Systems Manager, così da inviare le metriche di memoria personalizzate.

Passaggio 7

Passaggio 7

8. Verifichi che il CloudWatch Agent sia installato e configurato correttamente per inviare a CloudWatch le metriche di memoria personalizzate.

Passaggio 8

Conclusione — In sintesi, abbiamo visto come automatizzare end-to-end installazione e configurazione del CloudWatch Agent e l'invio di metriche di memoria personalizzate a CloudWatch tramite Systems Manager Automation e AWS EventBridge, senza alcun intervento manuale, ogni volta che viene creata una nuova istanza EC2.