When you're managing multiple AWS accounts, you need a way to control and restrict usage to for example unused AWS Services or AWS Regions.
A feature from AWS Organizations called AWS Service Control Policies (SCPs) allows you to create a set of rules to restrict or allow access to AWS resources on multiple accounts at once.
In this article, I'll be sharing 28 comprehensive AWS SCP examples that you can immediately apply to your own AWS Organization to improve the security of your AWS accounts. These examples are organized by Organizational Unit (OU) type to show you exactly where and why to apply each policy in your multi-account strategy.
By default, all actions are allowed within an AWS Organization. Therefore the AWS SCPs that we're sharing here use the deny list strategy.
Note: make sure to review and test the AWS SCP examples before you proceed. For complete implementation guidance including Organizations setup, OU structure creation, SCP testing workflows, and integration with IAM Identity Center and centralized logging, see AWS Multi-Account Best Practices.
What's New in AWS SCPs
AWS has introduced significant updates to Service Control Policies since 2025. Understanding these changes helps you write more effective policies and choose the right governance tool for each scenario.
Full IAM Language Support (September 2025)
As of September 2025, SCPs now support the complete IAM policy language. This includes:
- NotResource: Scope exceptions to specific resources (e.g., "deny everything EXCEPT this bucket")
- Conditions in Allow statements: Enable context-aware permissions requiring MFA or source IP restrictions
- Individual resource ARNs: Target specific resources instead of wildcards only
- Wildcards anywhere in Action elements: Use patterns like
s3:*Object*for flexible matching
These enhancements enable more granular policies. For example, you can now write an SCP that denies all S3 access except to a specific compliance bucket, something previously impossible.
Resource Control Policies (RCPs) Overview
In November 2024, AWS introduced Resource Control Policies (RCPs) as a new policy type in AWS Organizations. While SCPs restrict what principals (users, roles) can do, RCPs restrict what can be done to resources.
RCPs currently support:
- Amazon S3
- AWS KMS
- Amazon SQS
- AWS Secrets Manager
- Amazon ECR
Use RCPs when you need resource-centric controls like "no external accounts can access our S3 buckets" regardless of which principal makes the request.
When to Use SCPs vs RCPs vs Declarative Policies
Here's a decision framework for choosing the right policy type:
| Scenario | Use This Policy Type |
|---|---|
| Restrict what users/roles can do | SCPs |
| Restrict who can access resources | RCPs |
| Enforce resource configuration (e.g., IMDSv2) | Declarative Policies |
| Block actions in specific regions | SCPs |
| Prevent external account access to S3 | RCPs |
| Require encryption on all new EBS volumes | Declarative Policies |
| Deny root user access | SCPs |
All three policy types work together. SCPs don't protect the management account, so for protecting your management account from security risks, use AWS delegated administrators for service management instead.
Foundation SCPs: Apply These to Every OU
These fundamental SCPs prevent catastrophic mistakes regardless of environment. Apply them organization-wide at the root level or to every OU in your structure. For complete guidance on Organizations setup, OU architecture, and policy types, see AWS Organizations: Complete Implementation Guide. Many of these policies are deployed as part of production AWS Landing Zone implementations.
1. Deny access to AWS resources for the AWS account root user
When to use this: Apply this foundation SCP to every OU in your multi-account organization (Production OU, Development OU, Security OU, Infrastructure OU, and Sandbox OU) except the Root/Management account itself (where emergency root access might be needed for billing or account recovery). This is a universal guardrail that should protect all member accounts regardless of their purpose.
Why this matters: The root user bypasses all IAM policies and has unrestricted access to all resources, billing information, and account closure. This prevents accidental or malicious actions using root credentials and enforces the use of IAM users/roles with proper audit trails and scoped permissions.
It's generally a best practice to not use the root user to do your tasks in your AWS account. Instead, you should create an IAM admin user and use that to do administrative tasks.
Since the root user has full access to all your resources and billing information, root user security is critical. For comprehensive root user protection guidance including hardware MFA setup, access key deletion, group email addresses, and CloudWatch alarms for root activity, see our AWS Account Security Best Practices guide.
The foundational root user security steps include:
- Enable AWS multi-factor authentication (MFA) - preferably hardware MFA
- Delete the access keys from the Security credentials page
- Setting up a strong password
As an additional layer of protection, you can set up a guardrail in the form of a Service Control Policy to deny access to AWS resources from the root user.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyRootUser",
"Effect": "Deny",
"Action": "*",
"Resource": "*",
"Condition": {
"StringLike": {
"aws:PrincipalArn": "arn:aws:iam::*:root"
}
}
}
]
}
What this prevents: Any AWS API call using root credentials fails immediately. Developers and administrators must use IAM users or roles, which means proper audit trails, scoped permissions, and accountability.
2. Deny access to AWS services in unsupported AWS regions
When to use this: Apply this foundation SCP to all OUs (Production, Development, Security, Sandbox) except your Infrastructure OU (specifically the Network accounts, which might need global services like CloudFront, Route53, or IAM). Restrict resource creation to your approved operational regions only. For example, if you operate exclusively in eu-west-1 and eu-central-1, deny all other regions to enforce data residency requirements and limit the blast radius during security incidents.
Why this matters: Restricting unused regions prevents attackers from expanding into regions you don't monitor during a security breach, limits cryptocurrency mining in unexpected regions, enforces data residency compliance requirements, and concentrates your security monitoring and cost visibility in approved regions only.
This SCP restricts the use of AWS services in unsupported AWS Regions. This is very useful if you only deploy to a single AWS region.
By revoking access to other AWS regions you'll effectively limit the blast radius in the event of a security breach.
The services in the NotAction element are global services hosted in us-east-1 by default. Blocking these services might cause issues in your active region, so they're exempt. This enhanced version includes role exemptions for IaC automation and SSO emergency access.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyAllOutsideApprovedRegions",
"Effect": "Deny",
"NotAction": [
"a4b:*",
"acm:*",
"aws-marketplace-management:*",
"aws-marketplace:*",
"aws-portal:*",
"budgets:*",
"ce:*",
"chime:*",
"cloudfront:*",
"config:*",
"cur:*",
"directconnect:*",
"ec2:DescribeRegions",
"ec2:DescribeTransitGateways",
"ec2:DescribeVpnGateways",
"fms:*",
"globalaccelerator:*",
"health:*",
"iam:*",
"importexport:*",
"kms:*",
"mobileanalytics:*",
"networkmanager:*",
"organizations:*",
"pricing:*",
"route53:*",
"route53domains:*",
"route53-recovery-cluster:*",
"route53-recovery-control-config:*",
"route53-recovery-readiness:*",
"s3:*",
"shield:*",
"sts:*",
"support:*",
"trustedadvisor:*",
"waf-regional:*",
"waf:*",
"wafv2:*",
"wellarchitected:*"
],
"Resource": "*",
"Condition": {
"StringNotEquals": {
"aws:RequestedRegion": ["eu-west-1", "eu-central-1"]
},
"StringNotLike": {
"aws:PrincipalARN": [
"arn:aws:iam::*:role/aws-reserved/sso.amazonaws.com/*/AWSReservedSSO_AdministratorAccess_*",
"arn:aws:iam::*:role/aws-service-role/securityhub.amazonaws.com/AWSServiceRoleForSecurityHub",
"arn:aws:iam::*:role/AWSCloudFormationStackSetAdministrationRole",
"arn:aws:iam::*:role/AWSCloudFormationStackSetExecutionRole",
"arn:aws:iam::*:role/OrganizationAccountAccessRole",
"arn:aws:iam::*:role/StackSet*",
"arn:aws:iam::*:role/stacksets-exec-*",
"arn:aws:iam::*:role/YourAdminRole",
"arn:aws:iam::*:role/YourCICDRole"
]
}
}
}
]
}
What this prevents: Attackers can't expand their footprint into regions you don't monitor. Developers can't accidentally launch resources in the wrong region, causing data residency compliance violations. The role exemptions ensure IaC pipelines and emergency SSO access still function across regions when needed.
3. Enforce S3 Bucket owner enforced setting
When to use this: Apply this foundation SCP to all workload OUs (Production OU, Development OU, Staging OU, and Sandbox OU) anywhere your teams create S3 buckets for applications, data storage, or file sharing. This ensures that all new S3 buckets disable ACLs and enforce bucket owner control, preventing a common security misconfiguration that can lead to data loss or unauthorized access.
Why this matters: Without this policy, external parties can upload objects with ACLs that transfer ownership to their accounts, causing you to lose control of your own data in your own buckets. Enforcing bucket owner control prevents ownership transfer via ACLs and maintains centralized access management through bucket policies and IAM.
Deny the s3:CreateBucket permission for IAM users or roles unless you set the bucket owner enforced setting for Object Ownership and disable ACLs.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "RequireBucketOwnerFullControl",
"Effect": "Deny",
"Action": ["s3:CreateBucket"],
"Resource": "*",
"Condition": {
"StringNotEquals": {
"s3:x-amz-object-ownership": "BucketOwnerEnforced"
}
}
}
]
}
What this prevents: All S3 buckets automatically disable ACLs and enforce bucket owner control. You cannot create buckets where external entities could gain ownership of objects, eliminating a common security misconfiguration.
4. Prevent accounts from leaving the organization
When to use this: Apply this foundation SCP to every OU in your organization. This prevents rogue actors or compromised credentials from removing accounts from your governance structure. Once an account is part of your organization, it cannot escape central control.
Why this matters: An attacker with sufficient privileges could call organizations:LeaveOrganization to remove an account from your organization, escaping all SCPs, consolidated billing, and centralized security monitoring. This simple SCP, deployed as part of production AWS Landing Zone implementations, closes that attack vector permanently.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyLeavingOrganization",
"Effect": "Deny",
"Action": ["organizations:LeaveOrganization"],
"Resource": "*"
}
]
}
What this prevents: No principal in any member account can remove the account from your organization. Your governance, compliance monitoring, and consolidated billing remain intact even if credentials are compromised.
5. Deny IAM user and access key creation
When to use this: Apply this foundation SCP to all OUs where you want to enforce IAM Identity Center (SSO) as the only identity mechanism. This blocks creation of long-lived IAM user credentials that pose significant security risks.
Why this matters: IAM users with access keys are security liabilities: they don't automatically rotate, they're easily leaked in code repositories, and they lack the session-based audit trail that federated identities provide. Modern AWS security best practices mandate IAM Identity Center for human access. This SCP, deployed in production AWS Landing Zone implementations, enforces that standard.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyIAMUserAndAccessKeyCreation",
"Effect": "Deny",
"Action": [
"iam:CreateUser",
"iam:CreateAccessKey"
],
"Resource": "*"
}
]
}
What this prevents: Teams cannot create IAM users or access keys. All human access must use IAM Identity Center, providing automatic credential rotation, centralized access management, and consistent audit trails across your organization.
6. Prevent disabling EBS encryption by default
When to use this: Apply this foundation SCP to all OUs after enabling EBS encryption by default at the account level. This ensures the encryption setting cannot be disabled once established.
Why this matters: EBS encryption by default ensures all new EBS volumes are automatically encrypted. Without this SCP, anyone with sufficient IAM permissions could disable this setting, creating unencrypted volumes that violate compliance requirements. This is part of the encryption-by-default security posture in production AWS Landing Zone implementations.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyDisablingEBSEncryptionByDefault",
"Effect": "Deny",
"Action": ["ec2:DisableEbsEncryptionByDefault"],
"Resource": "*"
}
]
}
What this prevents: Once EBS encryption is enabled at the account level, no one can disable it. All new EBS volumes will be encrypted automatically, ensuring consistent data-at-rest protection.
7. Protect IAM password policy from modification
When to use this: Apply this foundation SCP after setting your organization's IAM password policy during account provisioning. This prevents weakening of password requirements.
Why this matters: Strong password policies are a compliance requirement (SOC2, PCI-DSS, HIPAA). Without protection, a malicious or careless actor could weaken password requirements, creating security vulnerabilities. This SCP allows only authorized IaC roles to modify password policies.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyPasswordPolicyModification",
"Effect": "Deny",
"Action": [
"iam:DeleteAccountPasswordPolicy",
"iam:UpdateAccountPasswordPolicy"
],
"Resource": "*",
"Condition": {
"StringNotLike": {
"aws:PrincipalARN": [
"arn:aws:iam::*:role/AWSCloudFormationStackSetExecutionRole",
"arn:aws:iam::*:role/AWSCloudFormationStackSetAdministrationRole",
"arn:aws:iam::*:role/OrganizationAccountAccessRole",
"arn:aws:iam::*:role/YourCICDRole",
"arn:aws:iam::*:role/StackSet*"
]
}
}
}
]
}
What this prevents: Password policies cannot be weakened or deleted except through authorized IaC pipelines. Your compliance-mandated password requirements remain enforced across all accounts.
8. Enforce data perimeter controls
When to use this: Apply this foundation SCP when implementing data perimeter controls to restrict access to resources based on organization identity. This ensures only principals from your organization can access AWS services within your accounts.
Why this matters: Data perimeter is a modern AWS security best practice that establishes trust boundaries using three pillars: identity perimeter (who can access), resource perimeter (what resources exist), and network perimeter (where access originates). This SCP enforces the identity perimeter by requiring that all principals accessing your resources belong to your organization.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "EnforceIdentityPerimeter",
"Effect": "Deny",
"Action": "*",
"Resource": "*",
"Condition": {
"StringNotEqualsIfExists": {
"aws:PrincipalOrgID": "o-your-org-id"
},
"BoolIfExists": {
"aws:PrincipalIsAWSService": "false"
},
"StringNotLike": {
"aws:PrincipalARN": [
"arn:aws:iam::*:role/aws-service-role/*",
"arn:aws:iam::*:role/YourCICDRole"
]
}
}
}
]
}
What this prevents: External AWS accounts cannot access resources in your organization's accounts. Only principals from your organization (identified by aws:PrincipalOrgID) can make API calls. AWS service-linked roles are exempt to allow AWS services to function properly.
With these foundation SCPs in place, you have a strong security baseline. Now let's examine SCPs for protecting your security infrastructure.
Security OU SCPs: Protecting Your Security Foundation
Your Security OU contains the crown jewels: audit logs, security tooling, and compliance validation infrastructure. These accounts need absolute protection from tampering.
9. Comprehensive security services protection
When to use this: In a Security OU containing your Log Archive Account, Audit Account, and Security Tooling Account, apply this SCP to make your security foundation immutable. As detailed in our multi-account strategy guide, these accounts house your organization's crown jewels (audit logs, compliance data, and security monitoring tools) and require absolute protection from tampering.
Why this matters: This comprehensive SCP covers 40+ actions across GuardDuty, Config, CloudTrail, and Security Hub. It prevents insider threats from deleting evidence of malicious activity, stops accidental disabling of security services during troubleshooting, and maintains immutable audit trails required for compliance investigations. This enhanced version from production AWS Landing Zone implementations goes far beyond basic protection.
For detailed configuration guidance on CloudTrail log file validation, Config compliance monitoring, GuardDuty threat detection, and Security Hub aggregation, see our AWS Account Security Best Practices covering logging and monitoring fundamentals.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ProtectSecurityServices",
"Effect": "Deny",
"Action": [
"guardduty:AcceptInvitation",
"guardduty:ArchiveFindings",
"guardduty:CreateDetector",
"guardduty:CreateFilter",
"guardduty:CreateIPSet",
"guardduty:CreateMembers",
"guardduty:CreatePublishingDestination",
"guardduty:CreateSampleFindings",
"guardduty:CreateThreatIntelSet",
"guardduty:DeclineInvitations",
"guardduty:DeleteDetector",
"guardduty:DeleteFilter",
"guardduty:DeleteInvitations",
"guardduty:DeleteIPSet",
"guardduty:DeleteMembers",
"guardduty:DeletePublishingDestination",
"guardduty:DeleteThreatIntelSet",
"guardduty:DisassociateFromMasterAccount",
"guardduty:DisassociateMembers",
"guardduty:InviteMembers",
"guardduty:StartMonitoringMembers",
"guardduty:StopMonitoringMembers",
"guardduty:TagResource",
"guardduty:UnarchiveFindings",
"guardduty:UntagResource",
"guardduty:UpdateDetector",
"guardduty:UpdateFilter",
"guardduty:UpdateFindingsFeedback",
"guardduty:UpdateIPSet",
"guardduty:UpdatePublishingDestination",
"guardduty:UpdateThreatIntelSet",
"config:DeleteConfigRule",
"config:DeleteConfigurationRecorder",
"config:DeleteDeliveryChannel",
"config:StopConfigurationRecorder",
"cloudtrail:DeleteTrail",
"cloudtrail:PutEventSelectors",
"cloudtrail:StopLogging",
"cloudtrail:UpdateTrail",
"cloudtrail:CreateTrail",
"securityhub:DeleteInvitations",
"securityhub:DisableSecurityHub",
"securityhub:DisassociateFromMasterAccount",
"securityhub:DeleteMembers",
"securityhub:DisassociateMembers"
],
"Resource": "*",
"Condition": {
"StringNotLike": {
"aws:PrincipalARN": [
"arn:aws:iam::*:role/aws-reserved/sso.amazonaws.com/*/AWSReservedSSO_AdministratorAccess_*",
"arn:aws:iam::*:role/aws-service-role/securityhub.amazonaws.com/AWSServiceRoleForSecurityHub",
"arn:aws:iam::*:role/AWSCloudFormationStackSetAdministrationRole",
"arn:aws:iam::*:role/AWSCloudFormationStackSetExecutionRole",
"arn:aws:iam::*:role/OrganizationAccountAccessRole",
"arn:aws:iam::*:role/YourCICDRole"
]
}
}
}
]
}
What this prevents: Even account administrators cannot disable CloudTrail, delete audit logs, modify retention policies, turn off GuardDuty, or disable Security Hub. The comprehensive action list blocks EVERY method of tampering with security services, including creating decoy trails, archiving findings, or manipulating threat intel. IaC role exemptions allow automated security service management during account provisioning.
10. Protect Security Hub configuration
When to use this: In a Security OU containing your Security Tooling accounts, apply this SCP to prevent weakening of Security Hub compliance standards. This complements the comprehensive security services protection by covering configuration-level changes.
Why this matters: Security Hub has specific configuration actions that can weaken your security posture without technically "disabling" it. Teams might disable specific standards (CIS, PCI-DSS) or weaken individual controls. This dedicated SCP from production AWS Landing Zone implementations covers actions not included in the comprehensive security services SCP.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ProtectSecurityHubConfig",
"Effect": "Deny",
"Action": [
"securityhub:BatchDisableStandards",
"securityhub:DeleteActionTarget",
"securityhub:DeleteInsight",
"securityhub:TagResource",
"securityhub:UntagResource",
"securityhub:UpdateStandardsControl",
"securityhub:UpdateSecurityHubConfiguration",
"securityhub:UpdateFindingAggregator",
"securityhub:UpdateOrganizationConfiguration",
"securityhub:DisableImportFindingsForProduct"
],
"Resource": "*",
"Condition": {
"StringNotLike": {
"aws:PrincipalARN": [
"arn:aws:iam::*:role/aws-reserved/sso.amazonaws.com/*/AWSReservedSSO_AdministratorAccess_*",
"arn:aws:iam::*:role/aws-service-role/securityhub.amazonaws.com/AWSServiceRoleForSecurityHub",
"arn:aws:iam::*:role/AWSCloudFormationStackSetExecutionRole",
"arn:aws:iam::*:role/AWSCloudFormationStackSetAdministrationRole",
"arn:aws:iam::*:role/OrganizationAccountAccessRole",
"arn:aws:iam::*:role/YourCICDRole"
]
}
}
}
]
}
What this prevents: Teams cannot bulk disable compliance standards, weaken individual controls, change cross-region aggregation settings, or disable third-party security tool integrations. Your Security Hub configuration remains exactly as your security team defined it.
11. Restrict security accounts to security operations only
When to use this: In a Security OU containing your Log Archive, Audit, Security Tooling, and potentially Forensics accounts (as shown in the mid-size and enterprise patterns), apply this SCP to prevent scope creep where these accounts accidentally become application hosts. Security accounts should only run security-related services (GuardDuty, Security Hub, CloudTrail) and audit tools, never workloads like EC2 instances, RDS databases, or Lambda functions processing business data.
Why this matters: Prevents security accounts from becoming application hosts, maintains separation of duties for compliance audits, protects audit integrity by ensuring security accounts remain isolated from business workloads, and stops convenience deployments that violate your multi-account architecture principles.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyWorkloadDeployment",
"Effect": "Deny",
"Action": [
"ec2:RunInstances",
"rds:CreateDBInstance",
"lambda:CreateFunction",
"ecs:CreateCluster",
"eks:CreateCluster"
],
"Resource": "*"
}
]
}
What this prevents: Security accounts cannot run workloads. They remain dedicated to security functions, maintaining the integrity of your audit trail and security tooling. This separation ensures security accounts never become attack targets for production data access.
12. Enforce MFA for sensitive IAM operations
When to use this: In a Security OU or applied broadly, this SCP requires MFA for sensitive IAM operations that could lead to privilege escalation.
Why this matters: Creating IAM users, attaching policies, and creating access keys are high-risk operations. Requiring MFA adds a second factor that prevents automated attacks and forces deliberate human action for privilege changes.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "RequireMFAForSensitiveIAMOperations",
"Effect": "Deny",
"Action": [
"iam:CreateUser",
"iam:DeleteUser",
"iam:AttachUserPolicy",
"iam:AttachRolePolicy",
"iam:CreateAccessKey",
"iam:CreatePolicyVersion"
],
"Resource": "*",
"Condition": {
"BoolIfExists": {
"aws:MultiFactorAuthPresent": "false"
},
"StringNotLike": {
"aws:PrincipalARN": [
"arn:aws:iam::*:role/YourCICDRole",
"arn:aws:iam::*:role/AWSCloudFormationStackSetExecutionRole"
]
}
}
}
]
}
What this prevents: Sensitive IAM operations require MFA authentication. Automated attacks using stolen credentials (without MFA) cannot escalate privileges. CI/CD roles are exempt because they use role assumption, which has its own authentication chain.
With security accounts protected, let's examine production-specific guardrails that prevent costly mistakes.
Production OU SCPs: Strict Change Control and Protection
Production accounts require the most restrictive policies. These SCPs prevent accidental destruction while enforcing encryption and compliance requirements.
13. Enforce encryption on all production data
When to use this: In a Production OU containing your production application accounts and production data accounts, apply this SCP to enforce encryption at rest for all data storage services. Whether you're following the startup pattern with a single Production Account or the enterprise pattern with region-specific production accounts, encryption enforcement is non-negotiable for production data.
Why this matters: Prevents creation of unencrypted S3 buckets, EBS volumes, and RDS instances that violate compliance requirements (SOC2, HIPAA, PCI-DSS), makes encryption failures impossible rather than requiring detection and remediation, eliminates the risk of accidentally storing sensitive data unencrypted, and enforces security best practices at the infrastructure level.
This enhanced version also requires encryption for S3 object uploads, not just bucket creation.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyUnencryptedS3Uploads",
"Effect": "Deny",
"Action": "s3:PutObject",
"Resource": "*",
"Condition": {
"Null": {
"s3:x-amz-server-side-encryption": "true"
}
}
},
{
"Sid": "DenyUnencryptedEBSVolumes",
"Effect": "Deny",
"Action": "ec2:RunInstances",
"Resource": "arn:aws:ec2:*:*:volume/*",
"Condition": {
"Bool": {
"ec2:Encrypted": "false"
}
}
},
{
"Sid": "DenyUnencryptedRDSInstances",
"Effect": "Deny",
"Action": "rds:CreateDBInstance",
"Resource": "*",
"Condition": {
"Bool": {
"rds:StorageEncrypted": "false"
}
}
}
]
}
What this prevents: All S3 objects must be uploaded with server-side encryption. All EBS volumes and RDS instances must use encryption. No exceptions. Developers cannot create unencrypted resources even by accident. Compliance violations become technically impossible rather than policy violations requiring detection and remediation.
14. Prevent unauthorized resource termination
When to use this: In a Production OU containing your production application accounts, apply this SCP to require explicit role assumption before any destructive operations. This adds a critical human checkpoint before deletion of databases, EC2 instances, or DynamoDB tables. Production accounts (whether you have a single production account in the startup pattern or region-specific production accounts in the enterprise pattern) need protection from accidental destruction.
Why this matters: Prevents accidental termination of production resources during fatigued late-night deployments, blocks Terraform destroy commands run in the wrong account, creates an audit trail for all destructive operations through required role assumption, and forces deliberate action before deleting critical infrastructure. This SCP has prevented countless production outages caused by simple human error.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "RequireApprovalForTermination",
"Effect": "Deny",
"Action": [
"ec2:TerminateInstances",
"rds:DeleteDBInstance",
"dynamodb:DeleteTable"
],
"Resource": "*",
"Condition": {
"StringNotLike": {
"aws:PrincipalArn": [
"arn:aws:iam::*:role/ApprovedDestructionRole"
]
}
}
}
]
}
What this prevents: Critical resources cannot be terminated except by specifically authorized roles (typically tied to change management workflows). Even account administrators cannot terminate production databases or instances without assuming the approved destruction role, creating an audit trail and forcing deliberate action.
15. Protect tagged CloudFormation stacks from deletion
When to use this: In a Production OU containing IaC-managed infrastructure, apply this SCP to prevent accidental deletion of CloudFormation stacks. This protects stacks tagged with your organization identifier while allowing CI/CD pipelines to manage them.
Why this matters: IaC-managed resources should only be modified through IaC pipelines. Manual stack deletion can orphan resources, create configuration drift, and cause outages. This SCP from production AWS Landing Zone implementations protects against "oops I deleted the VPC stack" incidents.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ProtectTaggedCloudFormationStacks",
"Effect": "Deny",
"Action": [
"cloudformation:DeleteStack",
"cloudformation:DeleteStackInstances",
"cloudformation:DeleteStackSet"
],
"Resource": ["arn:aws:cloudformation:*:*:stack/*"],
"Condition": {
"StringEquals": {
"aws:ResourceTag/organization": "YourOrganizationName"
},
"StringNotLike": {
"aws:PrincipalARN": [
"arn:aws:iam::*:role/AWSCloudFormationStackSetExecutionRole",
"arn:aws:iam::*:role/AWSCloudFormationStackSetAdministrationRole",
"arn:aws:iam::*:role/OrganizationAccountAccessRole",
"arn:aws:iam::*:role/YourCICDRole"
]
}
}
}
]
}
What this prevents: Stacks tagged with your organization identifier cannot be deleted through the console or CLI by humans. Only CI/CD roles can delete stacks, ensuring all infrastructure changes go through your deployment pipeline with proper reviews and approvals.
16. Enforce IMDSv2 on all EC2 instances
When to use this: In a Production OU and ideally all workload OUs, apply this SCP to require IMDSv2 (Instance Metadata Service Version 2) for all EC2 instances. This is a critical security control that prevents SSRF attacks.
Why this matters: IMDSv1 is vulnerable to Server-Side Request Forgery (SSRF) attacks, famously exploited in the Capital One breach. IMDSv2 requires session tokens that SSRF attacks cannot easily obtain. This is a mandatory security control for production environments.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "RequireIMDSv2",
"Effect": "Deny",
"Action": "ec2:RunInstances",
"Resource": "arn:aws:ec2:*:*:instance/*",
"Condition": {
"StringNotEquals": {
"ec2:MetadataHttpTokens": "required"
}
}
}
]
}
What this prevents: EC2 instances cannot be launched with IMDSv1 enabled. All instances must require IMDSv2 tokens, protecting against credential theft via SSRF vulnerabilities in web applications.
With production accounts protected, let's examine cost controls for development environments.
Development OU SCPs: Cost Controls and Safe Experimentation
Development accounts need flexibility but not unlimited spending. These SCPs enable innovation while preventing expensive mistakes.
17. Prevent expensive instance types and services
When to use this: In a Development OU containing team-specific development accounts or a Staging OU with pre-production testing accounts, apply this SCP to enable innovation while preventing cost explosions. As outlined in the mid-size architecture pattern, development accounts need flexibility for experimentation, but developers don't need access to expensive GPU instances, high-memory machines, or the ability to purchase Reserved Instances.
Why this matters: Prevents launching expensive GPU or high-memory instances that rack up costs in non-production environments, blocks forgotten development resources from running up large bills, ensures Reserved Instance and Savings Plans purchases are centrally managed by FinOps teams, and keeps development costs predictable while maintaining sufficient resources for testing.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyExpensiveEC2Instances",
"Effect": "Deny",
"Action": "ec2:RunInstances",
"Resource": "arn:aws:ec2:*:*:instance/*",
"Condition": {
"StringNotLike": {
"ec2:InstanceType": [
"t3.*",
"t3a.*",
"t2.*",
"m5.large",
"m5.xlarge",
"m6i.large",
"m6i.xlarge"
]
}
}
},
{
"Sid": "DenyExpensiveRDSInstances",
"Effect": "Deny",
"Action": "rds:CreateDBInstance",
"Resource": "*",
"Condition": {
"StringNotLike": {
"rds:DatabaseClass": [
"db.t3.*",
"db.t4g.*"
]
}
}
},
{
"Sid": "DenyHighIOPSVolumes",
"Effect": "Deny",
"Action": "ec2:CreateVolume",
"Resource": "*",
"Condition": {
"StringEquals": {
"ec2:VolumeType": ["io2"]
}
}
},
{
"Sid": "DenyNATGatewayCreation",
"Effect": "Deny",
"Action": "ec2:CreateNatGateway",
"Resource": "*"
}
]
}
What this prevents: Developers can only launch cost-effective instance types. They cannot launch GPU instances, high-memory instances, io2 Block Express volumes (which cost significantly more), or NAT Gateways (which should be centralized in your network account). Development costs stay predictable.
18. Block Reserved Instance and Savings Plans purchases
When to use this: In Development OU, Sandbox OU, and any non-production accounts, apply this SCP to centralize commitment purchases. Reserved Instances and Savings Plans should be managed by your FinOps team in a central account.
Why this matters: Fragmented RI/Savings Plans purchases across multiple accounts lead to suboptimal utilization and wasted spend. Centralizing these purchases can save 15-20% through better coverage optimization.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyReservedPurchases",
"Effect": "Deny",
"Action": [
"ec2:PurchaseReservedInstancesOffering",
"ec2:PurchaseHostReservation",
"ec2:PurchaseScheduledInstances",
"rds:PurchaseReservedDBInstancesOffering",
"elasticache:PurchaseReservedCacheNodesOffering",
"redshift:PurchaseReservedNodeOffering",
"dynamodb:PurchaseReservedCapacityOfferings",
"savingsplans:CreateSavingsPlan"
],
"Resource": "*"
}
]
}
What this prevents: Development teams cannot purchase Reserved Instances or Savings Plans. All commitment purchases are made centrally by FinOps, ensuring optimal coverage across your organization and eliminating fragmented, underutilized commitments.
19. Prevent expensive AI/ML services
When to use this: In Development OU and Sandbox OU, apply this SCP to prevent access to expensive AI/ML services that can generate massive bills through experimentation.
Why this matters: A single SageMaker training job on p4d instances can cost $10,000+. EMR clusters and Redshift warehouses can also generate significant costs. Development experimentation with these services should require explicit approval and budget allocation.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyExpensiveAIMLServices",
"Effect": "Deny",
"Action": [
"sagemaker:CreateTrainingJob",
"sagemaker:CreateHyperParameterTuningJob",
"sagemaker:CreateNotebookInstance",
"sagemaker:CreateEndpoint",
"elasticmapreduce:RunJobFlow",
"redshift:CreateCluster",
"redshift-serverless:CreateWorkgroup"
],
"Resource": "*"
}
]
}
What this prevents: Developers cannot spin up SageMaker training jobs, EMR clusters, or Redshift warehouses in development accounts. These expensive services require provisioning in dedicated ML/Analytics accounts with proper budget controls.
20. Enforce resource tagging requirements
When to use this: In Development OU and all workload OUs, apply this SCP to ensure cost allocation and ownership tracking through mandatory tags.
Why this matters: Without consistent tagging, cost allocation becomes impossible. You can't chargeback to teams, identify orphaned resources, or enforce lifecycle policies. This SCP enforces tags at creation time, ensuring every resource is properly attributed.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "RequireTagsOnEC2",
"Effect": "Deny",
"Action": "ec2:RunInstances",
"Resource": [
"arn:aws:ec2:*:*:instance/*",
"arn:aws:ec2:*:*:volume/*"
],
"Condition": {
"Null": {
"aws:RequestTag/Environment": "true",
"aws:RequestTag/Owner": "true"
}
}
},
{
"Sid": "RequireTagsOnRDS",
"Effect": "Deny",
"Action": "rds:CreateDBInstance",
"Resource": "*",
"Condition": {
"Null": {
"aws:RequestTag/Environment": "true",
"aws:RequestTag/Owner": "true"
}
}
}
]
}
What this prevents: EC2 instances, EBS volumes, and RDS instances cannot be created without Environment and Owner tags. This ensures every resource can be attributed to a team and environment for cost allocation and lifecycle management.
With development cost controls in place, let's examine sandbox restrictions.
Sandbox OU SCPs: Aggressive Spending Limits
Sandbox accounts are for experimentation and learning. They need the most aggressive cost controls because they serve temporary, exploratory purposes.
21. Restrict sandbox accounts to basic services with spending caps
When to use this: In a Sandbox OU containing individual developer sandbox accounts (typically one per engineer), apply this SCP to create safe, isolated experimentation environments with aggressive cost controls. Following the enterprise sandbox pattern, sandbox accounts serve temporary, exploratory purposes and need the strictest spending limits. Each sandbox should be limited to $100-500 per month and auto-terminate after 30-90 days of inactivity.
Why this matters: Limits sandbox spending to basic, low-cost services only, prevents access to expensive services like SageMaker, EMR, or Redshift that aren't needed for learning, maintains complete isolation by blocking network connections to production or shared services, and keeps aggregate sandbox costs manageable across large engineering organizations. Combined with AWS Budgets, this prevents sandbox sprawl from becoming a significant cost center.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowOnlyBasicServices",
"Effect": "Deny",
"NotAction": [
"ec2:*",
"s3:*",
"lambda:*",
"dynamodb:*",
"cloudwatch:*",
"logs:*",
"iam:*",
"sts:*",
"sns:*",
"sqs:*",
"apigateway:*"
],
"Resource": "*"
},
{
"Sid": "DenyExpensiveInstancesInSandbox",
"Effect": "Deny",
"Action": "ec2:RunInstances",
"Resource": "arn:aws:ec2:*:*:instance/*",
"Condition": {
"StringNotLike": {
"ec2:InstanceType": [
"t2.micro",
"t2.small",
"t3.micro",
"t3.small"
]
}
}
},
{
"Sid": "DenyNetworkConnectivity",
"Effect": "Deny",
"Action": [
"ec2:CreateVpcPeeringConnection",
"ec2:AcceptVpcPeeringConnection",
"ec2:CreateTransitGatewayVpcAttachment",
"directconnect:*",
"globalaccelerator:*"
],
"Resource": "*"
}
]
}
What this prevents: Sandbox accounts can only use basic services (EC2, S3, Lambda, DynamoDB, API Gateway) and only tiny instance types. They cannot access expensive services like SageMaker, EMR, or Redshift. They cannot create network connections to production or shared services, maintaining complete isolation. Combined with AWS Budgets set to $100-500 per month, this creates true sandboxes: safe, isolated, cheap experimentation environments.
22. Prevent external resource sharing in sandbox
When to use this: In a Sandbox OU, apply this SCP to prevent sandbox accounts from sharing resources with external accounts or accepting shares from them.
Why this matters: Sandbox accounts should be completely isolated. Resource sharing (via RAM) could accidentally expose sandbox experiments to production accounts or accept external resources that create dependencies. This maintains sandbox isolation.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyRAMSharing",
"Effect": "Deny",
"Action": [
"ram:CreateResourceShare",
"ram:UpdateResourceShare",
"ram:AssociateResourceShare",
"ram:AcceptResourceShareInvitation"
],
"Resource": "*"
}
]
}
What this prevents: Sandbox accounts cannot share resources or accept resource shares. They remain completely isolated from your production infrastructure and external accounts.
Now let's examine an often-overlooked but critical OU type.
Suspended OU SCPs: Account Lockdown
Every organization needs a "quarantine" OU for accounts that are compromised, decommissioned, or belong to departed employees. This OU completely locks down all API access.
23. Complete lockdown for suspended accounts
When to use this: In a Suspended OU for accounts that are:
- Compromised: Under active security investigation
- Decommissioned: Projects ended, waiting for deletion
- Employee departures: Personal sandbox accounts when employees leave
This SCP denies ALL actions except for authorized admin roles needed for cleanup and compliance monitoring. This is a critical SCP from production AWS Landing Zone implementations.
Why this matters: When an account is compromised or an employee leaves, you need to immediately stop all activity while preserving evidence and maintaining compliance monitoring. Moving the account to a Suspended OU with this SCP achieves instant lockdown without deleting evidence or disrupting Security Hub monitoring.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyAllActionsForSuspendedAccounts",
"Effect": "Deny",
"Action": ["*"],
"Resource": "*",
"Condition": {
"StringNotLike": {
"aws:PrincipalARN": [
"arn:aws:iam::*:role/YourAdminRole",
"arn:aws:iam::*:role/aws-service-role/securityhub.amazonaws.com/AWSServiceRoleForSecurityHub",
"arn:aws:iam::*:role/AWSCloudFormationStackSetAdministrationRole",
"arn:aws:iam::*:role/AWSCloudFormationStackSetExecutionRole",
"arn:aws:iam::*:role/OrganizationAccountAccessRole",
"arn:aws:iam::*:root",
"arn:aws:iam::*:role/YourCICDRole"
]
}
}
}
]
}
What this prevents: All API calls fail except from authorized admin roles (for cleanup), Security Hub service role (for continued compliance monitoring), and root user (for final account closure). The compromised credentials or departed employee's access becomes immediately ineffective. Evidence is preserved for investigation.
Next, let's examine infrastructure-specific controls.
Infrastructure OU SCPs: Service-Specific Restrictions
Infrastructure accounts (Network, Shared Services, CI/CD) should only perform their designated functions. These SCPs prevent scope creep.
24. Restrict Network accounts to networking operations only
When to use this: In an Infrastructure OU containing specialized infrastructure accounts like your Network Hub Account, Network Production Account, and Network Development Account (as defined in the enterprise infrastructure pattern), apply this SCP to prevent these accounts from becoming application hosts. Network accounts should only manage VPCs, Transit Gateways, Direct Connect, Route53, VPC Lattice, and network firewall rules, never compute, storage, or application resources.
Why this matters: Enforces strict separation of duties by preventing compute or application deployments in network accounts, maintains clear account boundaries for compliance audits, stops convenience deployments that violate architectural principles, and ensures network accounts remain dedicated to networking functions only. This prevents infrastructure accounts from accidentally becoming mixed-purpose accounts that complicate security and compliance.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowOnlyNetworkingServices",
"Effect": "Deny",
"NotAction": [
"ec2:*Vpc*",
"ec2:*Subnet*",
"ec2:*Gateway*",
"ec2:*Route*",
"ec2:*NetworkAcl*",
"ec2:*SecurityGroup*",
"ec2:*TransitGateway*",
"ec2:Describe*",
"directconnect:*",
"route53:*",
"route53resolver:*",
"networkfirewall:*",
"vpc-lattice:*",
"cloudwatch:*",
"logs:*",
"iam:*",
"sts:*"
],
"Resource": "*"
},
{
"Sid": "DenyComputeAndStorage",
"Effect": "Deny",
"Action": [
"ec2:RunInstances",
"rds:*",
"s3:CreateBucket",
"lambda:*",
"ecs:*",
"eks:*"
],
"Resource": "*"
}
]
}
What this prevents: Network accounts can only manage networking resources (VPCs, Transit Gateways, Route53, Direct Connect, Network Firewall, VPC Lattice). They cannot launch compute instances, create databases, or deploy applications. This enforces strict separation: networking infrastructure remains purely infrastructure, never becoming an application hosting platform.
25. Protect VPC Flow Logs from deletion
When to use this: In Infrastructure OU and all accounts where VPC Flow Logs are critical for security investigations, apply this SCP to prevent deletion of flow logs.
Why this matters: VPC Flow Logs are essential for security incident investigation, network troubleshooting, and compliance auditing. Deleting flow logs destroys evidence and creates compliance gaps.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ProtectVPCFlowLogs",
"Effect": "Deny",
"Action": [
"ec2:DeleteFlowLogs",
"logs:DeleteLogGroup"
],
"Resource": "*",
"Condition": {
"StringNotLike": {
"aws:PrincipalARN": [
"arn:aws:iam::*:role/YourCICDRole",
"arn:aws:iam::*:role/AWSCloudFormationStackSetExecutionRole"
]
}
}
}
]
}
What this prevents: VPC Flow Logs and their associated log groups cannot be deleted except by authorized IaC roles. Network audit trails remain intact for security investigations.
Now let's address modern services that require specific governance.
Modern Services SCPs
These SCPs govern newer AWS services that require specific guardrails for cost control and security.
26. Control Amazon Bedrock model access
When to use this: In Development OU, Production OU, and any accounts using generative AI, apply this SCP to restrict which foundation models can be invoked. This prevents expensive model usage and enforces your AI governance policies.
Why this matters: Amazon Bedrock provides access to multiple foundation models with vastly different costs. Claude Opus and GPT-4 class models are significantly more expensive than Claude Haiku or Titan. Without governance, developers might use expensive models for simple tasks, generating unexpected bills.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyExpensiveBedrockModels",
"Effect": "Deny",
"Action": [
"bedrock:InvokeModel",
"bedrock:InvokeModelWithResponseStream"
],
"Resource": [
"arn:aws:bedrock:*::foundation-model/anthropic.claude-3-opus-*",
"arn:aws:bedrock:*::foundation-model/anthropic.claude-3-5-sonnet-*",
"arn:aws:bedrock:*::foundation-model/meta.llama3-1-405b-*"
]
}
]
}
What this prevents: Teams cannot invoke expensive foundation models (Claude Opus, Claude 3.5 Sonnet, Llama 405B) without explicit exception. Development work should use cost-effective models like Claude Haiku or Titan.
Note on cross-region inference: Bedrock's cross-region inference feature may route requests to different regions. If you use region deny SCPs, you may need to exempt Bedrock service-linked roles or allow specific fulfillment regions.
27. Restrict Amazon Q Developer operations
When to use this: In accounts using Amazon Q Developer or AWS Chatbot, apply this SCP to prevent IAM operations from being executed through chat interfaces.
Why this matters: Amazon Q Developer allows executing AWS CLI commands from Slack or Teams. While convenient, executing IAM operations (creating users, attaching policies) through chat is a security risk with limited audit context.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyIAMOperationsFromChat",
"Effect": "Deny",
"Action": [
"iam:CreateUser",
"iam:DeleteUser",
"iam:CreateRole",
"iam:DeleteRole",
"iam:AttachUserPolicy",
"iam:AttachRolePolicy",
"iam:CreateAccessKey"
],
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:CalledViaFirst": "chatbot.amazonaws.com"
}
}
}
]
}
What this prevents: IAM operations cannot be executed through Amazon Q Developer or AWS Chatbot. These sensitive operations must go through the console, CLI, or IaC with proper authentication context.
28. Require VPC configuration for SageMaker
When to use this: In accounts where SageMaker is permitted, apply this SCP to require VPC configuration for notebooks and training jobs. This prevents data exfiltration through public internet access.
Why this matters: SageMaker notebooks and training jobs with public internet access can exfiltrate training data or model artifacts. Requiring VPC configuration ensures all network traffic routes through your controlled network infrastructure.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "RequireVPCForSageMaker",
"Effect": "Deny",
"Action": [
"sagemaker:CreateNotebookInstance",
"sagemaker:CreateTrainingJob"
],
"Resource": "*",
"Condition": {
"Null": {
"sagemaker:VpcSubnets": "true"
}
}
}
]
}
What this prevents: SageMaker notebooks and training jobs cannot be created without VPC configuration. All SageMaker workloads run within your VPC where network traffic can be monitored and controlled.
With all SCP categories covered, let's address what happens when things go wrong.
SCP Troubleshooting: When Policies Don't Work
Even well-designed SCPs can cause unexpected behavior. This section helps you debug issues quickly.
How to debug SCP denials in CloudTrail
When an action fails unexpectedly, CloudTrail is your first debugging tool. SCP denials appear with specific error patterns:
- Find the denial in CloudTrail: Filter for
errorCode: AccessDeniedand the affected principal - Check the error message: SCP denials include "with an explicit deny in a service control policy"
- Identify which SCP: The
serviceEventDetailsfield shows the SCP name
Example CloudTrail filter for debugging:
eventName = "RunInstances" AND errorCode = "Client.UnauthorizedOperation"
For setting up CloudTrail filters and alarms for monitoring SCP denials, see our AWS Account Security Best Practices guide on logging and monitoring.
Common SCP mistakes and how to fix them
| Mistake | Symptom | Fix |
|---|---|---|
Forgetting NotAction for global services | IAM, CloudFront, Route53 operations fail in allowed regions | Add global services to NotAction list in region deny SCP |
| Missing service-linked role exemptions | AWS services stop working despite SCP appearing correct | Add arn:aws:iam::*:role/aws-service-role/* to exemptions |
| Incorrect condition operator | SCP denies more or less than intended | Use StringEquals for exact match, StringLike for wildcards |
| Resource ARN too broad | SCP denies actions on unintended resources | Use specific resource ARNs instead of * |
| Conflicting SCPs at different OU levels | Unexpected denials from parent OU SCPs | Check all SCPs in the hierarchy using Organizations console |
| Testing with wrong principal | SCP works in test but fails for actual users | Test with same role/user type that will use it in production |
Understanding SCP evaluation logic
SCPs follow a specific evaluation order:
- Explicit Deny (SCP): If any SCP in the hierarchy has an explicit deny, the action is denied
- Allow (SCP): The action must be allowed by SCPs at every level in the hierarchy
- Allow (IAM): The principal's IAM policies must allow the action
- Implicit Deny: If not explicitly allowed, the action is denied
Key insight: An action must be allowed by BOTH SCPs AND IAM policies. An SCP Allow does not grant permissions; it only permits the possibility of having that permission via IAM.
For a comprehensive explanation of SCP syntax and evaluation, see our AWS SCP guide.
Service-linked role exemptions explained
Service-linked roles are special IAM roles that AWS services use to perform actions on your behalf. SCPs generally don't apply to actions taken by AWS services using these roles.
| Service | Service-Linked Role | Why SCP Exemption Exists |
|---|---|---|
| Organizations | AWSServiceRoleForOrganizations | Enables service integration across accounts |
| Config | AWSServiceRoleForConfig | Records resource configurations for compliance |
| Security Hub | AWSServiceRoleForSecurityHub | Aggregates security findings across regions |
| GuardDuty | AWSServiceRoleForAmazonGuardDuty | Monitors VPC Flow Logs and DNS logs |
When your SCP isn't blocking an action you expect it to block, check if a service-linked role is performing the action instead of a user or role.
Advanced SCP Patterns
With full IAM language support, you can implement sophisticated SCP patterns.
Using NotResource for scoped exceptions
The NotResource element lets you deny everything except specific resources. This is useful for compliance buckets that must remain accessible regardless of other restrictions.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyS3ExceptComplianceBucket",
"Effect": "Deny",
"Action": "s3:*",
"NotResource": [
"arn:aws:s3:::compliance-audit-bucket",
"arn:aws:s3:::compliance-audit-bucket/*"
]
}
]
}
This denies all S3 operations except on the compliance bucket, ensuring audit data always remains accessible.
Conditions in Allow statements
Since September 2025, you can use conditions in SCP Allow statements. This enables context-aware permissions:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowOnlyFromCorporateNetwork",
"Effect": "Allow",
"Action": "*",
"Resource": "*",
"Condition": {
"IpAddress": {
"aws:SourceIp": ["203.0.113.0/24"]
}
}
}
]
}
This allows actions only from your corporate IP range, blocking access from personal networks or compromised credentials used from unknown locations.
Break-glass procedures and emergency access
Every organization needs emergency access procedures when SCPs cause unexpected issues. Here's a recommended pattern:
- Create a BreakGlassRole in each account with SCP exemptions
- Require MFA and approval for assuming this role
- Set short session duration (1 hour maximum)
- Alert on usage via CloudWatch alarms on BreakGlassRole assumption
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowBreakGlassRole",
"Effect": "Allow",
"Action": "*",
"Resource": "*",
"Condition": {
"StringLike": {
"aws:PrincipalARN": "arn:aws:iam::*:role/BreakGlassRole"
}
}
}
]
}
Document your break-glass procedure and test it quarterly. When production is down at 3 AM, you need this process to be muscle memory.
Implementation Strategy: Rolling Out SCPs Safely
Don't apply these SCPs all at once across your entire organization. That's a recipe for breaking production systems and creating chaos. Here's an approach you can apply in phases to make sure you implement new scp's with confidence within your aws organization and OU's:
Phase 1: Test in Development
- Apply SCPs to a single development account using the testing and deployment strategy
- Monitor CloudTrail for denied actions
- Identify legitimate use cases that need exceptions
- Refine policies based on findings
Phase 2: Expand to Non-Production
- Apply SCPs to Development OU and Sandbox OU
- Communicate changes to development teams
- Provide 1-week notice before enforcement
- Document exceptions and approval processes
Phase 3: Protect Production
- Apply SCPs to Production OU during maintenance window
- Start with least restrictive policies (root user denial, region restrictions)
- Gradually add encryption enforcement and resource protection
- Monitor for legitimate denials and adjust
Phase 4: Lock Down Security and Infrastructure
- Apply strictest SCPs to Security OU and Infrastructure OU
- These should rarely deny legitimate actions (they're specialized accounts)
- Monitor for 2 weeks to ensure no operational impact
Validation with IAM Access Analyzer
Before attaching any SCP to production OUs, validate with IAM Access Analyzer:
- Use ValidatePolicy to check syntax and identify issues
- Use CheckNoNewAccess to verify the SCP doesn't grant unintended permissions
- Use CheckAccessNotGranted to confirm specific actions are blocked
This validation prevents production outages from SCP syntax errors or unexpected behavior.
Conclusion
The 28 AWS SCP examples provided in this article will help you better secure the multiple environments you're managing within your AWS Organization from a central point.
These policies represent real-world lessons learned from security incidents, cost overruns, and compliance failures across dozens of organizations. Each SCP prevents a specific category of disaster: data breaches, accidental deletions, cost explosions, compliance violations, or operational chaos.
The key insight: SCPs are preventive controls, not detective controls. They stop mistakes before they happen rather than alerting you after damage is done. A developer cannot accidentally delete production databases if an SCP prevents it. An attacker cannot expand into unsupported regions if an SCP blocks it. A data scientist cannot launch $30,000 GPU instances in development if an SCP denies it.
Using the deny list strategy to block access to specific AWS Services or regions can have a huge impact on the teams and applications that are running on your AWS accounts.
Therefore it's important to test a new AWS SCP on the development or test account before proceeding to activate the permission policy on production.
Start with foundation SCPs (root user denial, region restrictions, encryption enforcement). Expand to environment-specific policies (production protection, development cost controls, sandbox restrictions). Add the Suspended OU for account quarantine. Finish with infrastructure lockdown (security account immutability, network account restrictions). Consider new policy types (RCPs for resource-centric controls, Declarative Policies for configuration enforcement) as complementary governance tools.
The structure presented here aligns with the multi-account strategy patterns we've detailed previously. As your organization grows from startup to mid-size to enterprise, your SCP strategy should evolve with it, adding guardrails that match your increasing complexity and risk exposure.
Get Production-Ready, SOC 2 Compliant AWS Accounts from Day One
We deploy our AWS Landing Zone (using infrastructure as code) with pre-configured multi-account architecture, built-in security controls and guardrails including monitoring to stay in control of what happens so you can safely start deploying workloads immediately.

