Turning an SLO-breach signal into infrastructure means wiring a CloudWatch alarm on the metric your application already emits to an SNS topic that fans out to whoever needs to act.
Structured elaboration
The alarm needs a comparison operator, an evaluation period count, and a period length that together express "exceeds 0.5% for 5 consecutive minutes" (5 evaluation periods of 60 seconds each, all breaching); treat_missing_data needs an explicit choice (here, notBreaching, so a gap in metric publication does not itself trigger a false alarm, though a stricter policy might prefer breaching for a safety-critical metric, trading false alarms for never missing a real gap). The SNS topic is a separate resource so the alarm and its notification fan-out can be composed independently (e.g., reusing the same topic across several alarms).
Worked example (validated with terraform validate against a real Terraform install, AWS provider ~> 5.0)
hcl
resource "aws_sns_topic" "slo_breach_alerts" {
name = "slo-breach-alerts"
}
resource "aws_cloudwatch_metric_alarm" "api_error_rate_high" {
alarm_name = "api-error-rate-high"
comparison_operator = "GreaterThanThreshold"
evaluation_periods = 5
metric_name = "api_error_rate"
namespace = "Custom/API"
period = 60
statistic = "Average"
threshold = 0.5
alarm_description = "Fires when api_error_rate exceeds 0.5% for 5 consecutive 1-minute periods"
treat_missing_data = "notBreaching"
alarm_actions = [aws_sns_topic.slo_breach_alerts.arn]
}
This configuration passed terraform init and terraform validate cleanly (correct resource schema for both aws_cloudwatch_metric_alarm and aws_sns_topic, and a correctly-formed reference from the alarm's alarm_actions to the topic's ARN).
Trade-offs and pitfalls
The IAM side is easy to forget: CloudWatch needs no special role to publish to SNS when the alarm references the topic directly via alarm_actions (this is a managed, AWS-internal integration), but any SUBSCRIBER of the topic (a Lambda, an HTTP endpoint, a chat-ops integration) needs its own permission to receive from SNS, and that subscription is a separate resource entirely. A custom metric like api_error_rate must actually be published by the application (via the CloudWatch PutMetricData API or an agent); this Terraform only wires the ALARM, not the metric's ingestion, so verify the metric is actually flowing before trusting the alarm.