Cloud Intelligence™Cloud Intelligence™

Cloud Intelligence™

Automatiza la instalación y configuración del agente CloudWatch con Systems Manager y EventBridge

By Nikhil PawarMar 28, 20247 min read

Esta página también está disponible en English, Deutsch, Français, Italiano, 日本語 y Português.

Foto de Alexander+Supertramp en Shutterstock

En este post vamos a automatizar de punta a punta la instalación y configuración del agente CloudWatch en una instancia EC2 (Linux) para obtener métricas personalizadas de memoria mediante un runbook de automatización de Systems Manager. Usaremos un runbook personalizado para automatizar la instalación y configuración del agente CloudWatch, y AWS EventBridge para disparar la automatización sin intervención manual.

Diagrama básico de la arquitectura

Visión general de la automatización:

Para esta automatización vamos a usar una plantilla de AWS CloudFormation que despliega los recursos y ejecuta los siguientes pasos:

  1. Crear un rol de IAM para que AWS Systems Manager ejecute el documento de automatización — Systems Manager necesita un rol de ejecución para correr el runbook en tu nombre sobre las instancias EC2 de destino y para otorgarles permisos de escritura de métricas en CloudWatch.
  2. Subir el archivo de configuración del agente CloudWatch al Parameter Store de Systems Manager — La plantilla de CloudFormation cargará el archivo de configuración personalizado del agente CloudWatch en el Parameter Store. Las instancias tomarán ese archivo para configurar el agente.
  3. Crear el documento de automatización de Systems Manager — Con CloudFormation crearemos un runbook personalizado para instalar y configurar el agente CloudWatch.
  4. Crear un rol de IAM para que la regla de EventBridge invoque la automatización de Systems Manager — EventBridge necesita un rol de invocación para disparar el flujo de automatización de Systems Manager que instala y configura el agente CloudWatch.
  5. Crear la regla de EventBridge — CloudFormation creará una regla de EventBridge que filtra los eventos de instancias EC2 en estado "running" y dispara la automatización de SSM.
  6. Opcional (Crear una Dead Letter Queue de SQS) — Es una cola SQS estándar que actúa como Dead Letter Queue de la regla de EventBridge y captura los detalles de cualquier error en los disparos de EventBridge.

Plantilla de 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

Pasos:

1. Crea el stack de CloudFormation anterior desde la CLI o la consola:

Paso 1

2. Verifica el documento de automatización de Systems Manager que se desplegó. Este documento personalizado tiene 3 pasos:

  1. Identificar el rol asociado a la instancia de destino y adjuntarle la política administrada CloudWatchAgentServer.
  2. Instalar el agente CloudWatch en la instancia de destino.
  3. Configurar el agente CloudWatch para enviar métricas a CloudWatch.

Paso 2

3. Verifica la regla de Amazon EventBridge:

Paso 3

Patrón de evento: se utiliza el siguiente patrón de evento para filtrar los eventos en estado "running" en cuanto ocurren.

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

Y la transformación de entrada de EventBridge usa el Input Transformer que aparece abajo para obtener el ID de la instancia de destino.

Input transformer

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

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

4. Crea una nueva instancia:

- La instancia EC2 de prueba debe tener instalado el agente de AWS Systems Manager (SSM Agent) para que Systems Manager pueda comunicarse con ella. Además, las instancias EC2 deben contar con conectividad de red hacia los endpoints públicos del servicio Systems Manager o hacia los endpoints VPC de AWS PrivateLink para Systems Manager. (Nota: usé la AMI de Amazon Linux 2023 y la lancé en la VPC predeterminada).

- Crea un rol "EC2ssmCoreRole" con la política administrada de AWS "AmazonSSMManagedInstanceCore" para que Systems Manager pueda gestionar la instancia EC2. Crea un perfil de instancia y agrégale el rol. Por último, lanza una instancia de prueba (t2.micro). Yo usé la siguiente plantilla de CloudFormation de ejemplo para lanzarla.

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. Confirma que la regla de EventBridge se disparó cuando la instancia pasó al estado "running" y que Systems Manager corrió la automatización, instalando y configurando el agente CloudWatch en la instancia EC2 para enviar métricas de memoria.

6. Revisa la ejecución de la automatización en Systems Manager. En cuanto la instancia entra en estado "running", se dispara la regla de EventBridge para ejecutar el documento de automatización de Systems Manager.

Paso 6

7. Revisa el estado y el avance de la ejecución; se realizan 3 pasos:

- Adjuntar la política CloudWatch Agent Server al rol de la instancia.

- Instalar el agente CloudWatch en la instancia de destino.

- Configurar el agente CloudWatch tomando el archivo de configuración del Parameter Store de Systems Manager para enviar métricas personalizadas de memoria.

Paso 7

Paso 7

8. Verifica que el agente CloudWatch quedó instalado y configurado para enviar métricas personalizadas de memoria a CloudWatch.

Paso 8

Conclusión — En resumen, vimos cómo automatizar de punta a punta la instalación y configuración del agente CloudWatch y el envío de métricas personalizadas de memoria a CloudWatch con Systems Manager Automation y AWS EventBridge, sin pasos manuales, para cada nueva instancia EC2 que se cree.