← Back to DevBytes

Monitoring CloudFormation: Metrics, Alarms, and Dashboards

Understanding CloudFormation Monitoring

AWS CloudFormation gives you a powerful way to model and provision your entire infrastructure using code. But once your stacks are created or updated, the story doesn’t end. Without proper monitoring, you can miss drift, silent failures, or rolled-back changes until they cause an outage. Monitoring CloudFormation means tracking stack events, detecting configuration drift, and surfacing critical status changes through metrics, alarms, and dashboards — so your team can respond before customers are impacted.

This tutorial covers exactly what to monitor, why it matters, and how to implement it step by step using CloudWatch, EventBridge, and CloudFormation itself. You’ll see real code examples that you can adapt immediately.

Why Monitoring CloudFormation Matters

CloudFormation stacks are the backbone of many AWS environments. A stack stuck in UPDATE_FAILED or ROLLBACK_IN_PROGRESS can leave resources in an inconsistent state, block further deployments, and create hidden security gaps. Monitoring gives you:

By turning CloudFormation activity into metrics, you can apply the same rigorous monitoring you already use for application performance, but to your infrastructure code pipeline.

Key Metrics for CloudFormation

CloudFormation does not publish built-in CloudWatch metrics. Instead, you generate metrics from CloudTrail logs, EventBridge events, or custom code. Below are the three essential metric categories you should collect.

Stack Events and Status Metrics

Every CloudFormation stack change generates CloudTrail events like CreateStack, UpdateStack, DeleteStack, and detailed resource-level events. By creating a CloudWatch metric filter on the CloudTrail log group, you can count stack statuses and publish a metric that tracks failures over time.

A common approach is to publish a metric named StackFailureCount whenever a stack operation ends with a FAILED or ROLLBACK status. The metric filter pattern looks like this:


{
  "eventSource": "cloudformation.amazonaws.com",
  "eventName": "UpdateStack",
  "responseElements": {
    "stackStatus": "UPDATE_FAILED"
  }
}

You can combine patterns for multiple failure statuses using || in the filter. For example:


{ ($.eventName = "UpdateStack" AND $.responseElements.stackStatus = "UPDATE_FAILED") 
|| ($.eventName = "CreateStack" AND $.responseElements.stackStatus = "CREATE_FAILED") 
|| ($.eventName = "DeleteStack" AND $.responseElements.stackStatus = "DELETE_FAILED") }

Resource-level Metrics

Sometimes you need to monitor specific resources inside a stack — for example, whether an EC2 instance was replaced unexpectedly, or whether a security group was modified outside of CloudFormation. Resource-level CloudTrail events (like CreateSecurityGroup with requestParameters showing the stack ID) can be filtered to create per-resource or per-stack metrics. You can then build alarms on, say, unauthorized changes to a critical security group that is supposed to be managed only by CloudFormation.

Custom Metrics via CloudWatch

For complex monitoring logic — such as tracking stack deployment duration, counting drift occurrences, or checking for stacks that haven’t been updated in weeks — a Lambda function can push custom metrics directly to CloudWatch. This is covered later in the alarms section.

Setting Up CloudWatch Alarms

Alarms translate metrics into actionable notifications. The following patterns cover the most critical CloudFormation scenarios.

Alarms for Stack Failures

Once you have a metric filter publishing a failure metric, you can create an alarm that triggers when any failure occurs, or when failures exceed a threshold within a period. Here’s an example CloudFormation snippet that creates the metric filter and alarm together:


Resources:
  CloudTrailLogGroup:
    Type: AWS::Logs::LogGroup
    Properties:
      RetentionInDays: 90

  StackFailureMetricFilter:
    Type: AWS::Logs::MetricFilter
    Properties:
      LogGroupName: !Ref CloudTrailLogGroup
      FilterPattern: '{ ($.eventName = "UpdateStack" AND $.responseElements.stackStatus = "UPDATE_FAILED") || ($.eventName = "CreateStack" AND $.responseElements.stackStatus = "CREATE_FAILED") }'
      MetricTransformations:
        - MetricName: StackFailureCount
          MetricNamespace: CloudFormationMonitoring
          MetricValue: "1"

  StackFailureAlarm:
    Type: AWS::CloudWatch::Alarm
    Properties:
      AlarmName: CloudFormation-Stack-Failure
      AlarmDescription: "Triggers when a CloudFormation stack creation or update fails"
      Namespace: CloudFormationMonitoring
      MetricName: StackFailureCount
      Statistic: Sum
      Period: 60
      EvaluationPeriods: 1
      Threshold: 0
      ComparisonOperator: GreaterThanThreshold
      TreatMissingData: notBreaching
      AlarmActions:
        - !Ref SnsNotificationTopic

This alarm fires immediately on the first failure within a one-minute period. Adjust EvaluationPeriods and Threshold if you want to suppress transient single failures and only alert on repeated issues.

Alarms for Drift Detection

Drift detection tells you when live resources no longer match their CloudFormation template. CloudFormation emits CloudTrail events for DetectStackDrift and DescribeStackDriftDetectionStatus. You can set up a metric filter for drift results that contain "StackDriftStatus": "DRIFTED" and create an alarm that triggers daily if drift is found.

A more proactive method is to run drift detection on a schedule using a Lambda function, and push a custom metric DriftedStackCount. The Lambda can query all stacks, count those with drift, and publish the number. The alarm below watches that custom metric:


DriftCheckAlarm:
  Type: AWS::CloudWatch::Alarm
  Properties:
    AlarmName: Drift-Detected-Across-Stacks
    AlarmDescription: "Alerts when one or more stacks have drifted"
    Namespace: CloudFormationMonitoring
    MetricName: DriftedStackCount
    Statistic: Maximum
    Period: 86400
    EvaluationPeriods: 1
    Threshold: 0
    ComparisonOperator: GreaterThanThreshold
    AlarmActions:
      - !Ref SnsNotificationTopic

Combine this with a daily Lambda schedule (via CloudWatch Events) to keep your environment consistently monitored for configuration drift.

Alarms for Rollback States

A stack entering ROLLBACK_IN_PROGRESS or ROLLBACK_FAILED is a serious incident. You can extend the failure metric filter to also match rollback statuses. For example:


FilterPattern: '{ ($.eventName = "UpdateStack" AND ($.responseElements.stackStatus = "UPDATE_FAILED" OR $.responseElements.stackStatus = "ROLLBACK_IN_PROGRESS" OR $.responseElements.stackStatus = "ROLLBACK_FAILED")) }'

Then use an identical alarm configuration. This ensures you’re alerted even when CloudFormation tries to revert changes but encounters issues.

Building CloudWatch Dashboards

Dashboards give your team a real-time view of CloudFormation health across stacks, environments, and accounts. You can create dashboards directly in the AWS Console, but a better practice is to define them as CloudFormation resources so they are versioned and reproducible.

Creating a Dashboard via Console

In the CloudWatch console, you can add widgets that show your custom metrics (like StackFailureCount) alongside alarms. A typical layout includes:

However, manual dashboard creation doesn’t scale across multiple accounts. That’s where CloudFormation-managed dashboards shine.

Dashboard via CloudFormation

The AWS::CloudWatch::Dashboard resource lets you define a JSON string with the entire dashboard body. Below is a complete example that displays stack failures, drift count, and alarm statuses:


MonitoringDashboard:
  Type: AWS::CloudWatch::Dashboard
  Properties:
    DashboardName: CloudFormation-Health
    DashboardBody: |
      {
        "widgets": [
          {
            "type": "metric",
            "x": 0,
            "y": 0,
            "width": 12,
            "height": 6,
            "properties": {
              "metrics": [
                [ "CloudFormationMonitoring", "StackFailureCount", { "stat": "Sum", "period": 300 } ]
              ],
              "view": "timeSeries",
              "stacked": false,
              "region": "us-east-1",
              "title": "Stack Failures (5 min intervals)"
            }
          },
          {
            "type": "metric",
            "x": 12,
            "y": 0,
            "width": 6,
            "height": 6,
            "properties": {
              "metrics": [
                [ "CloudFormationMonitoring", "DriftedStackCount", { "stat": "Maximum", "period": 86400 } ]
              ],
              "view": "singleValue",
              "region": "us-east-1",
              "title": "Drifted Stacks (last 24h)"
            }
          },
          {
            "type": "alarm",
            "x": 0,
            "y": 6,
            "width": 18,
            "height": 6,
            "properties": {
              "alarms": [
                "CloudFormation-Stack-Failure",
                "Drift-Detected-Across-Stacks"
              ],
              "title": "Active CloudFormation Alarms"
            }
          }
        ]
      }

This dashboard gives you a single pane of glass for CloudFormation operations. You can extend it with widgets for stack update duration (using custom metrics from a Lambda) or per-environment breakdowns by including multiple metric queries.

Best Practices

Conclusion

Monitoring CloudFormation is not an afterthought — it’s a critical part of running infrastructure as code reliably. By turning stack events and drift detection into CloudWatch metrics, wrapping those metrics in alarms, and surfacing everything through coded dashboards, you gain continuous visibility into the health of your infrastructure deployment pipeline. The examples in this tutorial give you a production-ready starting point. Implement them, extend them for your own stack landscape, and make CloudFormation monitoring a seamless part of your DevOps observability strategy.

🚀 Need a reliable AI agent for your project?

Deploy Hermes Agent in 10 minutes. Managed hosting, zero DevOps.

Get Started — $23.99/mo
← Back to all articles