Service Control Policies (SCPs)
Apply organization-wide guardrails that prevent deletion of production resources, use tag-based controls, protect critical AWS services, and understand when to use SCPs vs IAM policies.
What Are Service Control Policies?
Service Control Policies (SCPs) are a feature of AWS Organizations that set the maximum permissions for all IAM users and roles within member accounts. Unlike IAM policies which grant permissions, SCPs define the outer boundary of what is possible in an account. If an SCP denies an action, no IAM policy in that account can override it.
This makes SCPs the most powerful guardrail mechanism in AWS. Even if an AI agent compromises or escalates IAM permissions within an account, the SCP will still block the denied actions.
SCP vs IAM Policy: When to Use Which
| Feature | Service Control Policy (SCP) | IAM Policy |
|---|---|---|
| Scope | Entire account or OU | Individual user, role, or group |
| Grants permissions? | No — only restricts | Yes — grants and restricts |
| Can be overridden? | No (except by management account) | Yes (by other policies or SCPs) |
| Affects root user? | Yes (in member accounts) | No (root bypasses IAM) |
| Requires Organizations? | Yes | No |
| Best for | Broad, non-negotiable guardrails | Fine-grained, role-specific permissions |
| AI agent use case | Blanket ban on destructive actions in production accounts | Grant specific read/write permissions to agent role |
SCP: Prevent Deletion of Production Resources
The following SCP blocks all common destructive actions. Attach it to your production OU so that no user, role, or AI agent in any production account can delete critical resources:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyAllDeletion",
"Effect": "Deny",
"Action": [
"ec2:TerminateInstances",
"ec2:DeleteVpc",
"ec2:DeleteSubnet",
"ec2:DeleteSecurityGroup",
"ec2:DeleteNatGateway",
"ec2:DeleteVolume",
"rds:DeleteDBInstance",
"rds:DeleteDBCluster",
"rds:DeleteDBSnapshot",
"rds:DeleteDBClusterSnapshot",
"s3:DeleteBucket",
"s3:DeleteObject",
"s3:DeleteObjectVersion",
"lambda:DeleteFunction",
"eks:DeleteCluster",
"eks:DeleteNodegroup",
"dynamodb:DeleteTable",
"elasticache:DeleteCacheCluster",
"elasticache:DeleteReplicationGroup",
"cloudformation:DeleteStack",
"route53:DeleteHostedZone"
],
"Resource": "*"
}
]
}
# Create the SCP
aws organizations create-policy \
--name "DenyProductionDeletion" \
--description "Prevents all destructive actions in production accounts" \
--type SERVICE_CONTROL_POLICY \
--content file://deny-production-deletion.json
# Attach to the Production OU
# Replace ou-xxxx with your production OU ID
aws organizations attach-policy \
--policy-id p-xxxxxxxxxxxx \
--target-id ou-xxxx-xxxxxxxx
# Verify the policy is attached
aws organizations list-policies-for-target \
--target-id ou-xxxx-xxxxxxxx \
--filter SERVICE_CONTROL_POLICY
Tag-Based SCPs: Allow Deletion of Ephemeral Resources Only
A blanket deny on all deletion is too strict for some workflows. AI agents may need to delete temporary or test resources. Tag-based SCPs solve this by only allowing deletion of resources tagged as ephemeral:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyDeleteUnlessEphemeral",
"Effect": "Deny",
"Action": [
"ec2:TerminateInstances",
"ec2:DeleteVolume",
"rds:DeleteDBInstance",
"s3:DeleteBucket",
"lambda:DeleteFunction",
"dynamodb:DeleteTable",
"eks:DeleteCluster",
"cloudformation:DeleteStack"
],
"Resource": "*",
"Condition": {
"StringNotEquals": {
"aws:ResourceTag/Lifecycle": "ephemeral"
}
}
}
]
}
With this SCP in place, any resource tagged Lifecycle=ephemeral can be deleted, but production resources (which should be tagged Lifecycle=production or not tagged at all) cannot.
Lifecycle from production to ephemeral and then delete the resource. Add an additional SCP that prevents modifying the Lifecycle tag on production resources.SCP to Protect Tags
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyTagModificationOnProduction",
"Effect": "Deny",
"Action": [
"ec2:CreateTags",
"ec2:DeleteTags",
"rds:AddTagsToResource",
"rds:RemoveTagsFromResource",
"s3:PutBucketTagging",
"s3:DeleteBucketTagging"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:ResourceTag/Lifecycle": "production"
},
"ForAnyValue:StringEquals": {
"aws:TagKeys": "Lifecycle"
}
}
}
]
}
Protecting Critical Services
Different AWS services require different protection strategies. Here are targeted SCPs for the most critical services:
RDS Protection SCP
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyRDSDeletion",
"Effect": "Deny",
"Action": [
"rds:DeleteDBInstance",
"rds:DeleteDBCluster",
"rds:DeleteDBSnapshot",
"rds:DeleteDBClusterSnapshot",
"rds:DeleteGlobalCluster",
"rds:ModifyDBInstance",
"rds:ModifyDBCluster"
],
"Resource": "*",
"Condition": {
"StringNotEquals": {
"aws:ResourceTag/Lifecycle": "ephemeral"
}
}
},
{
"Sid": "DenySkipFinalSnapshot",
"Effect": "Deny",
"Action": "rds:DeleteDBInstance",
"Resource": "*",
"Condition": {
"Bool": {
"rds:SkipFinalSnapshot": "true"
}
}
}
]
}
S3 Protection SCP
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyS3BucketDeletion",
"Effect": "Deny",
"Action": [
"s3:DeleteBucket",
"s3:DeleteBucketPolicy",
"s3:PutBucketPolicy"
],
"Resource": "*",
"Condition": {
"StringNotEquals": {
"aws:ResourceTag/Lifecycle": "ephemeral"
}
}
},
{
"Sid": "DenyDisablingVersioning",
"Effect": "Deny",
"Action": "s3:PutBucketVersioning",
"Resource": "*"
}
]
}
EKS Protection SCP
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyEKSDeletion",
"Effect": "Deny",
"Action": [
"eks:DeleteCluster",
"eks:DeleteNodegroup",
"eks:DeleteFargateProfile",
"eks:DeleteAddon"
],
"Resource": "*",
"Condition": {
"StringNotEquals": {
"aws:ResourceTag/Lifecycle": "ephemeral"
}
}
}
]
}
Testing SCPs Safely
SCPs are powerful and potentially disruptive. Test them carefully before applying to production:
AccessDenied errors. If legitimate operations are failing, refine the SCP.
# Look for access denied events in the last hour
aws cloudtrail lookup-events \
--lookup-attributes AttributeKey=EventName,AttributeValue=TerminateInstances \
--start-time $(date -u -d '1 hour ago' +%Y-%m-%dT%H:%M:%SZ) \
--end-time $(date -u +%Y-%m-%dT%H:%M:%SZ) \
--query 'Events[?contains(CloudTrailEvent, `AccessDenied`)]'
# List all SCPs attached to an OU
aws organizations list-policies-for-target \
--target-id ou-xxxx-xxxxxxxx \
--filter SERVICE_CONTROL_POLICY \
--output table
# Describe a specific SCP
aws organizations describe-policy \
--policy-id p-xxxxxxxxxxxx
Complete SCP Strategy for AI Agent Safety
Here is a recommended SCP architecture for organizations using AI coding agents:
| OU | SCP | Purpose |
|---|---|---|
| Root | FullAWSAccess (default) | Baseline — all actions allowed |
| Production | DenyAllDeletion | No resources can be deleted by anyone |
| Staging | DenyDeleteUnlessEphemeral | Only ephemeral resources can be deleted |
| Development | DenyDeleteUnlessEphemeral | Same as staging, protects shared dev resources |
| Sandbox | AllowAllDeletion (no extra SCP) | AI agents can freely create and destroy |
Lilly Tech Systems