CloudWatch alarms should have an action configured
A CloudWatch alarm that fires but triggers no action is operationally invisible. Without configured actions, threshold breaches go unnoticed, incidents escalate silently, and the alarm exists only as a dashboard decoration. At that point it tells you nothing you'll ever act on.
Configuring SNS topics, Auto Scaling policies, or Lambda functions as alarm actions gets the right people or systems notified when metrics deviate from expected baselines. For regulated workloads, actionless alarms create a gap between detection and response that auditors will flag immediately.
Retrofit consideration
Existing alarms may have been created without actions, or with actions_enabled set to false. Each alarm needs review to identify the correct notification target (SNS topic, Auto Scaling policy, etc.), and in larger environments that coordination spans multiple teams.
Implementation
Choose the approach that matches how you manage Terraform.
Use the compliance.tf module to enforce this control by default. See get started with compliance.tf.
module "cloudwatch" {
source = "soc2.compliance.tf/terraform-aws-modules/cloudwatch/aws//modules/metric-alarm"
version = ">=5.0.0"
actions_enabled = true
alarm_actions = ["arn:aws:sns:us-east-1:123456789012:example-topic"]
alarm_name = "pofix-abc123"
comparison_operator = "GreaterThanThreshold"
evaluation_periods = 1
metric_name = "CPUUtilization"
namespace = "AWS/EC2"
period = 300
statistic = "Average"
threshold = 80
}
module "cloudwatch" {
source = "pcidss.compliance.tf/terraform-aws-modules/cloudwatch/aws//modules/metric-alarm"
version = ">=5.0.0"
actions_enabled = true
alarm_actions = ["arn:aws:sns:us-east-1:123456789012:example-topic"]
alarm_name = "pofix-abc123"
comparison_operator = "GreaterThanThreshold"
evaluation_periods = 1
metric_name = "CPUUtilization"
namespace = "AWS/EC2"
period = 300
statistic = "Average"
threshold = 80
}
module "cloudwatch" {
source = "hipaa.compliance.tf/terraform-aws-modules/cloudwatch/aws//modules/metric-alarm"
version = ">=5.0.0"
actions_enabled = true
alarm_actions = ["arn:aws:sns:us-east-1:123456789012:example-topic"]
alarm_name = "pofix-abc123"
comparison_operator = "GreaterThanThreshold"
evaluation_periods = 1
metric_name = "CPUUtilization"
namespace = "AWS/EC2"
period = 300
statistic = "Average"
threshold = 80
}
module "cloudwatch" {
source = "nist80053.compliance.tf/terraform-aws-modules/cloudwatch/aws//modules/metric-alarm"
version = ">=5.0.0"
actions_enabled = true
alarm_actions = ["arn:aws:sns:us-east-1:123456789012:example-topic"]
alarm_name = "pofix-abc123"
comparison_operator = "GreaterThanThreshold"
evaluation_periods = 1
metric_name = "CPUUtilization"
namespace = "AWS/EC2"
period = 300
statistic = "Average"
threshold = 80
}
module "cloudwatch" {
source = "nistcsf.compliance.tf/terraform-aws-modules/cloudwatch/aws//modules/metric-alarm"
version = ">=5.0.0"
actions_enabled = true
alarm_actions = ["arn:aws:sns:us-east-1:123456789012:example-topic"]
alarm_name = "pofix-abc123"
comparison_operator = "GreaterThanThreshold"
evaluation_periods = 1
metric_name = "CPUUtilization"
namespace = "AWS/EC2"
period = 300
statistic = "Average"
threshold = 80
}
module "cloudwatch" {
source = "fedrampmoderate.compliance.tf/terraform-aws-modules/cloudwatch/aws//modules/metric-alarm"
version = ">=5.0.0"
actions_enabled = true
alarm_actions = ["arn:aws:sns:us-east-1:123456789012:example-topic"]
alarm_name = "pofix-abc123"
comparison_operator = "GreaterThanThreshold"
evaluation_periods = 1
metric_name = "CPUUtilization"
namespace = "AWS/EC2"
period = 300
statistic = "Average"
threshold = 80
}
module "cloudwatch" {
source = "nist800171.compliance.tf/terraform-aws-modules/cloudwatch/aws//modules/metric-alarm"
version = ">=5.0.0"
actions_enabled = true
alarm_actions = ["arn:aws:sns:us-east-1:123456789012:example-topic"]
alarm_name = "pofix-abc123"
comparison_operator = "GreaterThanThreshold"
evaluation_periods = 1
metric_name = "CPUUtilization"
namespace = "AWS/EC2"
period = 300
statistic = "Average"
threshold = 80
}
module "cloudwatch" {
source = "awswellarchitected.compliance.tf/terraform-aws-modules/cloudwatch/aws//modules/metric-alarm"
version = ">=5.0.0"
actions_enabled = true
alarm_actions = ["arn:aws:sns:us-east-1:123456789012:example-topic"]
alarm_name = "pofix-abc123"
comparison_operator = "GreaterThanThreshold"
evaluation_periods = 1
metric_name = "CPUUtilization"
namespace = "AWS/EC2"
period = 300
statistic = "Average"
threshold = 80
}
module "cloudwatch" {
source = "ffiec.compliance.tf/terraform-aws-modules/cloudwatch/aws//modules/metric-alarm"
version = ">=5.0.0"
actions_enabled = true
alarm_actions = ["arn:aws:sns:us-east-1:123456789012:example-topic"]
alarm_name = "pofix-abc123"
comparison_operator = "GreaterThanThreshold"
evaluation_periods = 1
metric_name = "CPUUtilization"
namespace = "AWS/EC2"
period = 300
statistic = "Average"
threshold = 80
}
module "cloudwatch" {
source = "cccsmedium.compliance.tf/terraform-aws-modules/cloudwatch/aws//modules/metric-alarm"
version = ">=5.0.0"
actions_enabled = true
alarm_actions = ["arn:aws:sns:us-east-1:123456789012:example-topic"]
alarm_name = "pofix-abc123"
comparison_operator = "GreaterThanThreshold"
evaluation_periods = 1
metric_name = "CPUUtilization"
namespace = "AWS/EC2"
period = 300
statistic = "Average"
threshold = 80
}
module "cloudwatch" {
source = "acscessentialeight.compliance.tf/terraform-aws-modules/cloudwatch/aws//modules/metric-alarm"
version = ">=5.0.0"
actions_enabled = true
alarm_actions = ["arn:aws:sns:us-east-1:123456789012:example-topic"]
alarm_name = "pofix-abc123"
comparison_operator = "GreaterThanThreshold"
evaluation_periods = 1
metric_name = "CPUUtilization"
namespace = "AWS/EC2"
period = 300
statistic = "Average"
threshold = 80
}
module "cloudwatch" {
source = "eugmpannex11.compliance.tf/terraform-aws-modules/cloudwatch/aws//modules/metric-alarm"
version = ">=5.0.0"
actions_enabled = true
alarm_actions = ["arn:aws:sns:us-east-1:123456789012:example-topic"]
alarm_name = "pofix-abc123"
comparison_operator = "GreaterThanThreshold"
evaluation_periods = 1
metric_name = "CPUUtilization"
namespace = "AWS/EC2"
period = 300
statistic = "Average"
threshold = 80
}
module "cloudwatch" {
source = "fedramplow.compliance.tf/terraform-aws-modules/cloudwatch/aws//modules/metric-alarm"
version = ">=5.0.0"
actions_enabled = true
alarm_actions = ["arn:aws:sns:us-east-1:123456789012:example-topic"]
alarm_name = "pofix-abc123"
comparison_operator = "GreaterThanThreshold"
evaluation_periods = 1
metric_name = "CPUUtilization"
namespace = "AWS/EC2"
period = 300
statistic = "Average"
threshold = 80
}
module "cloudwatch" {
source = "cisv120.compliance.tf/terraform-aws-modules/cloudwatch/aws//modules/metric-alarm"
version = ">=5.0.0"
actions_enabled = true
alarm_actions = ["arn:aws:sns:us-east-1:123456789012:example-topic"]
alarm_name = "pofix-abc123"
comparison_operator = "GreaterThanThreshold"
evaluation_periods = 1
metric_name = "CPUUtilization"
namespace = "AWS/EC2"
period = 300
statistic = "Average"
threshold = 80
}
module "cloudwatch" {
source = "hipaasecurity2003.compliance.tf/terraform-aws-modules/cloudwatch/aws//modules/metric-alarm"
version = ">=5.0.0"
actions_enabled = true
alarm_actions = ["arn:aws:sns:us-east-1:123456789012:example-topic"]
alarm_name = "pofix-abc123"
comparison_operator = "GreaterThanThreshold"
evaluation_periods = 1
metric_name = "CPUUtilization"
namespace = "AWS/EC2"
period = 300
statistic = "Average"
threshold = 80
}
module "cloudwatch" {
source = "iso270012013.compliance.tf/terraform-aws-modules/cloudwatch/aws//modules/metric-alarm"
version = ">=5.0.0"
actions_enabled = true
alarm_actions = ["arn:aws:sns:us-east-1:123456789012:example-topic"]
alarm_name = "pofix-abc123"
comparison_operator = "GreaterThanThreshold"
evaluation_periods = 1
metric_name = "CPUUtilization"
namespace = "AWS/EC2"
period = 300
statistic = "Average"
threshold = 80
}
module "cloudwatch" {
source = "nistcsfv11.compliance.tf/terraform-aws-modules/cloudwatch/aws//modules/metric-alarm"
version = ">=5.0.0"
actions_enabled = true
alarm_actions = ["arn:aws:sns:us-east-1:123456789012:example-topic"]
alarm_name = "pofix-abc123"
comparison_operator = "GreaterThanThreshold"
evaluation_periods = 1
metric_name = "CPUUtilization"
namespace = "AWS/EC2"
period = 300
statistic = "Average"
threshold = 80
}
module "cloudwatch" {
source = "nist80053rev4.compliance.tf/terraform-aws-modules/cloudwatch/aws//modules/metric-alarm"
version = ">=5.0.0"
actions_enabled = true
alarm_actions = ["arn:aws:sns:us-east-1:123456789012:example-topic"]
alarm_name = "pofix-abc123"
comparison_operator = "GreaterThanThreshold"
evaluation_periods = 1
metric_name = "CPUUtilization"
namespace = "AWS/EC2"
period = 300
statistic = "Average"
threshold = 80
}
module "cloudwatch" {
source = "pcidssv321.compliance.tf/terraform-aws-modules/cloudwatch/aws//modules/metric-alarm"
version = ">=5.0.0"
actions_enabled = true
alarm_actions = ["arn:aws:sns:us-east-1:123456789012:example-topic"]
alarm_name = "pofix-abc123"
comparison_operator = "GreaterThanThreshold"
evaluation_periods = 1
metric_name = "CPUUtilization"
namespace = "AWS/EC2"
period = 300
statistic = "Average"
threshold = 80
}
If you use terraform-aws-modules/cloudwatch/aws//modules/metric-alarm, set the right module inputs for this control. You can later migrate to the compliance.tf module with minimal changes because it is compatible by design.
module "cloudwatch" {
source = "terraform-aws-modules/cloudwatch/aws//modules/metric-alarm"
version = ">=5.0.0"
alarm_actions = ["arn:aws:sns:us-east-1:123456789012:example-topic"]
alarm_name = "pofix-abc123"
comparison_operator = "GreaterThanThreshold"
evaluation_periods = 1
metric_name = "CPUUtilization"
namespace = "AWS/EC2"
period = 300
statistic = "Average"
threshold = 80
actions_enabled = true
}
Use AWS provider resources directly. See docs for the resources involved: aws_cloudwatch_metric_alarm.
resource "aws_cloudwatch_metric_alarm" "this" {
alarm_actions = ["arn:aws:sns:us-east-1:123456789012:example-topic"]
alarm_name = "pofix-abc123"
comparison_operator = "GreaterThanOrEqualToThreshold"
evaluation_periods = 1
metric_name = "CPUUtilization"
namespace = "AWS/EC2"
period = 300
statistic = "Average"
threshold = 80
actions_enabled = true
}
What this control checks
For aws_cloudwatch_metric_alarm, the control validates two things: actions_enabled must be true (the default, but can be set to false explicitly), and at least one of alarm_actions, insufficient_data_actions, or ok_actions must contain a valid ARN. Setting actions_enabled = false fails the control even if action ARNs are present. Leaving all three action lists empty or omitted also fails.
The ARNs typically reference aws_sns_topic resources, but can also point to Auto Scaling policies, SSM OpsItems, or Lambda functions. When the optional named ARN parameter is used by the underlying AWS Config rule, that ARN must appear in one of the action lists.
Common pitfalls
actions_enabled defaults to true but can be silently overridden
The
actions_enabledargument defaults totrue, so most alarm configurations never set it explicitly. That makes it easy to miss when a module or variable override flips it tofalseduring testing to suppress notifications. The alarm passes Terraform validation but fails this control. Pinactions_enabled = trueexplicitly in production modules.Empty action lists are valid Terraform but fail the control
Terraform accepts
alarm_actions = []without error, which makes this easy to miss. If conditional logic that builds the list resolves to empty in certain environments, the alarm has no actions and will be flagged as non-compliant. Check your variable resolution, not just your resource definition.SNS topic exists but has no subscriptions
This control checks that an action ARN is present on the alarm, not that the target actually works. You can reference an
aws_sns_topicinalarm_actionswith zeroaws_sns_topic_subscriptionresources and pass the control fine. Alarms will fire into the void. Pair this with subscription verification.Composite alarms require separate action configuration
The
aws_cloudwatch_composite_alarmresource has its ownalarm_actionsandok_actionsarguments, separate fromaws_cloudwatch_metric_alarm, and it doesn't supportinsufficient_data_actions. If you're using composite alarms alongside metric alarms, configure their actions separately. This control evaluates metric alarms only.
Audit evidence
Auditors expect AWS Config rule evaluation results showing each AWS::CloudWatch::Alarm resource as COMPLIANT. Supporting evidence includes the CloudWatch console alarm list filtered to show the "Actions" column populated for every alarm, or aws cloudwatch describe-alarms output showing non-empty AlarmActions, InsufficientDataActions, or OKActions arrays alongside ActionsEnabled: true.
For deeper validation, auditors may request SNS subscription confirmations proving alarm action targets actually deliver to recipients, along with CloudTrail events showing SetAlarmState or PutMetricAlarm API calls that confirm alarms were configured with actions at creation.
Framework-specific interpretation
SOC 2: CC7.2 and CC7.3 call for monitoring system components and evaluating detected events. SOC 2 Trust Services Criteria also require that identified events reach responsible personnel. An alarm with no action fails that communication requirement outright.
PCI DSS v4.0: Requirement 10.7 wants failures of critical security controls detected, reported, and responded to promptly. Requirement 12.10.1 ties to incident response planning. PCI DSS v4.0 expects monitoring mechanisms to generate actionable alerts, not passive records.
HIPAA Omnibus Rule 2013: 45 CFR 164.312(b) requires audit controls that record and examine activity in information systems. Alarms with configured actions support the timely notification and response workflows that the HIPAA Security Rule expects for incident detection and handling.
NIST SP 800-53 Rev 5: SI-4, AU-6, and IR-4 all depend on alerts reaching someone who can act. NIST 800-53 Rev 5 expects automated mechanisms to integrate monitoring with alerting. An actionless alarm collects data but satisfies none of that automation intent.
NIST Cybersecurity Framework v2.0: DE.CM and RS.AN both come into play here. CloudWatch alarm actions close the loop between detection and automated response, which is core to the Detect and Respond functions in CSF v2.
FedRAMP Moderate Baseline Rev 4: SI-4(5) requires automated mechanisms that alert personnel to unusual or inappropriate activity. At the Moderate baseline, alarms without configured actions fail this requirement directly, and IR-4 incident handling depends on those alerts actually reaching someone.
Related controls
Tool mappings
Use these identifiers to cross-reference this control across tools, reports, and evidence.
Compliance.tf Control:
cloudwatch_alarm_action_enabledAWS Config Managed Rule:
CLOUDWATCH_ALARM_ACTION_CHECKCheckov Check:
CKV_AWS_319Powerpipe Control:
aws_compliance.control.cloudwatch_alarm_action_enabledProwler Checks:
cloudwatch_alarm_actions_alarm_state_configured,cloudwatch_alarm_actions_enabledAWS Security Hub Control:
CloudWatch.15
Last reviewed: 2026-03-09