Service Control Policies (SCPs) are the only way to enforce guardrails across your entire AWS Organization, and they work by denying actions at the root of the AWS account hierarchy, meaning they override even administrator permissions.
Let’s see this in action. Imagine you have an Organization Unit (OU) called Dev and you want to prevent anyone in that OU from launching EC2 instances in the us-east-1 region.
Here’s the SCP you’d create:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyEC2UsEast1",
"Effect": "Deny",
"Action": [
"ec2:RunInstances",
"ec2:LaunchTemplate*",
"ec2:CreateFleet",
"ec2:CreateSnapshots",
"ec2:CreateVolume",
"ec2:ImportImage",
"ec2:ImportSnapshot"
],
"Resource": "*",
"Condition": {
"ArnLike": {
"aws:RequestedRegion": "us-east-1"
}
}
}
]
}
You would then attach this SCP to the Dev OU. Now, if a user with AdministratorAccess attached to their IAM role tries to launch an EC2 instance in us-east-1 from an account within the Dev OU, the launch will fail.
The core problem SCPs solve is consistent enforcement. IAM policies are account-specific and can be modified by account administrators. SCPs, however, are attached at the Organization level (root, OUs, or individual accounts) and are evaluated before IAM policies. If an SCP denies an action, it’s denied, full stop. This is how you establish baseline security and compliance requirements that cannot be bypassed by individual account teams.
Internally, when an AWS API call is made from an account within your Organization, AWS performs a series of checks. The relevant ones for SCPs are:
- SCP Evaluation: Is the action allowed or denied by any SCPs attached to the account, its OUs, or the root of the Organization? If denied, the request fails.
- IAM Policy Evaluation: If allowed by SCPs, is the action allowed by the IAM policies attached to the user, group, or role making the request?
- Resource-based Policy Evaluation: If allowed by IAM, is the action allowed by any resource-based policies (like S3 bucket policies)?
The crucial takeaway is that SCPs act as an ultimate deny list. They don’t grant permissions; they only restrict what actions are possible. You can’t use an SCP to allow something that IAM or resource policies would otherwise deny, but you can use an SCP to deny something that IAM policies would otherwise allow. This makes them perfect for preventing the use of expensive services, restricting regions, or enforcing specific configurations.
When you apply an SCP to the root of your AWS Organization, it affects all accounts within that Organization by default. This is your most powerful tool for establishing organization-wide guardrails. You can then create more granular SCPs for specific OUs or accounts to refine these policies. For example, a general SCP at the root might deny all actions in ap-south-1 for cost control, while a more specific SCP attached to a Research OU might allow only specific EC2 instance types in us-east-1 for a particular project.
It’s common to create an SCP that denies all root-level actions, forcing all API calls to go through IAM roles. This is a powerful security pattern. You would attach an SCP to the root of your organization like this:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyRootUserActions",
"Effect": "Deny",
"Action": "*",
"Resource": "*",
"Condition": {
"StringEquals": {
"aws:PrincipalArn": "arn:aws:iam::*:root"
}
}
}
]
}
This SCP denies any action where the principal is the root user of any account. This forces users to assume IAM roles, which are auditable and can have fine-grained permissions, greatly improving security posture.
The next hurdle you’ll face is managing the complexity of multiple SCPs and understanding their interactions with IAM policies and resource policies, especially when dealing with inheritance.