← SCP Explorer

CloudWatch protection policy

Prevents deletion of critical CloudWatch logs and alarms, ensuring your monitoring infrastructure remains intact.

Policy description

What this SCP does

This Service Control Policy (SCP) prevents deletion of critical CloudWatch logs and alarms, ensuring your monitoring and alerting infrastructure remains intact. This provides protection against accidental or malicious deletion of monitoring resources.

The policy explicitly denies the deletion of CloudWatch log groups, log streams, and alarms. This ensures that important monitoring data and alert configurations cannot be removed, preserving operational visibility and compliance capabilities.

Validation strategy

How to test this SCP works

To validate this SCP, create test log groups, log streams, and alarms, then attempt to delete them:

  • Valid test: Create CloudWatch log groups, log streams, and alarms (should succeed)
  • Invalid test: Delete a log group (should be denied)
  • Invalid test: Delete a log stream (should be denied)
  • Invalid test: Delete a CloudWatch alarm (should be denied)

We expect resource creation to succeed, while any deletion operations should be denied with an AccessDenied error, confirming that the SCP is protecting these monitoring resources.

SCP policy & validation scenarios

{ "Version": "2012-10-17", "Statement": [ { "Sid": "DenyCloudWatchTampering", "Effect": "Deny", "Action": [ "logs:DeleteLogGroup", "logs:DeleteLogStream", "cloudwatch:DeleteAlarms" ], "Resource": "*" } ] }
# Create test CloudWatch resources aws logs create-log-group \ --log-group-name test-protected-logs aws logs create-log-stream \ --log-group-name test-protected-logs \ --log-stream-name test-stream aws cloudwatch put-metric-alarm \ --alarm-name test-protected-alarm \ --metric-name CPUUtilization \ --namespace AWS/EC2 \ --statistic Average \ --period 300 \ --threshold 80 \ --comparison-operator GreaterThanThreshold \ --evaluation-periods 2 # Try to delete these resources (these should be denied) aws logs delete-log-group \ --log-group-name test-protected-logs aws logs delete-log-stream \ --log-group-name test-protected-logs \ --log-stream-name test-stream aws cloudwatch delete-alarms \ --alarm-names test-protected-alarm # Sanity check - view resources (these should be allowed) #view Log Group aws logs describe-log-groups \ --log-group-name-prefix test-protected-logs #View Log Stream aws logs describe-log-streams \ --log-group-name test-protected-logs #View Cloud Alarm aws cloudwatch describe-alarms \ --alarm-names test-protected-alarm
import boto3 # Initialize CloudWatch and Logs clients logs_client = boto3.client('logs') cloudwatch_client = boto3.client('cloudwatch') # Create and try to delete CloudWatch resources try: # Create a log group logs_client.create_log_group(logGroupName='test-protected-logs') print("Created test log group") # Create a log stream logs_client.create_log_stream( logGroupName='test-protected-logs', logStreamName='test-stream' ) print("Created test log stream") # Create an alarm cloudwatch_client.put_metric_alarm( AlarmName='test-protected-alarm', MetricName='CPUUtilization', Namespace='AWS/EC2', Statistic='Average', Period=300, Threshold=80, ComparisonOperator='GreaterThanThreshold', EvaluationPeriods=2 ) print("Created test alarm") # Try to delete the log group (this should be denied) try: logs_client.delete_log_group(logGroupName='test-protected-logs') print("WARNING: Successfully deleted log group - SCP is NOT restricting as expected") except Exception as e: print(f"Expected error for delete log group if SCP is working: {e}") # Try to delete the log stream (this should be denied) try: logs_client.delete_log_stream( logGroupName='test-protected-logs', logStreamName='test-stream' ) print("WARNING: Successfully deleted log stream - SCP is NOT restricting as expected") except Exception as e: print(f"Expected error for delete log stream if SCP is working: {e}") # Try to delete the alarm (this should be denied) try: cloudwatch_client.delete_alarms(AlarmNames=['test-protected-alarm']) print("WARNING: Successfully deleted alarm - SCP is NOT restricting as expected") except Exception as e: print(f"Expected error for delete alarm if SCP is working: {e}") except Exception as e: print(f"Error setting up test environment: {e}")