AWS SCP Policy Rule Sets for Popular AWS Services
AWS SCP Policy Rule Sets for Popular AWS Services
Practical Service Control Policy guardrails for AWS Regions, S3, EC2, IAM, KMS, CloudTrail, GuardDuty, AWS Config, RDS, Lambda, VPC, DynamoDB, and EKS.
AWS Service Control Policies (SCPs) establish the maximum permissions available to accounts in an AWS Organization. They do not grant permissions; IAM policies and resource policies must still allow an operation.
1. Restrict operations to approved AWS Regions
This organization-wide guardrail denies most activity outside approved Regions while exempting selected global services.
{
"Version": "2012-10-17",
"Statement": [{
"Sid": "DenyUnapprovedRegions",
"Effect": "Deny",
"NotAction": [
"account:*", "aws-portal:*", "billing:*", "budgets:*",
"cloudfront:*", "iam:*", "organizations:*", "route53:*",
"route53domains:*", "support:*", "waf:*"
],
"Resource": "*",
"Condition": {
"StringNotEquals": {
"aws:RequestedRegion": ["us-east-1", "us-west-2"]
}
}
}]
}
Use case: Data residency, cost control, and attack-surface reduction.
2. Amazon S3 guardrails
Prevent public-access protection from being disabled
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyDisablingAccountPublicAccessBlock",
"Effect": "Deny",
"Action": "s3:PutAccountPublicAccessBlock",
"Resource": "*"
},
{
"Sid": "DenyChangingBucketPublicAccessBlock",
"Effect": "Deny",
"Action": ["s3:DeleteBucketPublicAccessBlock", "s3:PutBucketPublicAccessBlock"],
"Resource": "*"
}
]
}
The second statement is deliberately restrictive. A practical deployment can exempt a centrally controlled security role:
"Condition": {
"ArnNotLike": {
"aws:PrincipalArn": "arn:aws:iam::*:role/SecurityAdministrationRole"
}
}
Require encrypted object uploads
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyUnencryptedS3Uploads",
"Effect": "Deny",
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::*/*",
"Condition": {"Null": {"s3:x-amz-server-side-encryption": "true"}}
},
{
"Sid": "DenyUnsupportedS3Encryption",
"Effect": "Deny",
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::*/*",
"Condition": {
"StringNotEquals": {
"s3:x-amz-server-side-encryption": ["AES256", "aws:kms"]
}
}
}
]
}
Caution: Some AWS services write to S3 through service-specific mechanisms and may require carefully scoped exemptions.
3. Amazon EC2 guardrails
Permit only approved instance types
{
"Version": "2012-10-17",
"Statement": [{
"Sid": "DenyUnapprovedEC2InstanceTypes",
"Effect": "Deny",
"Action": "ec2:RunInstances",
"Resource": "arn:aws:ec2:*:*:instance/*",
"Condition": {
"StringNotEquals": {
"ec2:InstanceType": ["t3.micro", "t3.small", "t3.medium", "m6i.large"]
}
}
}]
}
Use case: Prevent expensive GPU or high-capacity instances from being launched.
Prevent disabling EBS encryption by default
{
"Version": "2012-10-17",
"Statement": [{
"Sid": "DenyDisablingDefaultEBSEncryption",
"Effect": "Deny",
"Action": "ec2:DisableEbsEncryptionByDefault",
"Resource": "*"
}]
}
Prevent creation of unencrypted EBS volumes
{
"Version": "2012-10-17",
"Statement": [{
"Sid": "DenyUnencryptedEBSVolumes",
"Effect": "Deny",
"Action": "ec2:CreateVolume",
"Resource": "*",
"Condition": {"Bool": {"ec2:Encrypted": "false"}}
}]
}
4. IAM guardrails
Prevent member accounts from creating IAM users
This encourages workforce access through IAM Identity Center and temporary roles.
{
"Version": "2012-10-17",
"Statement": [{
"Sid": "DenyIAMUserManagement",
"Effect": "Deny",
"Action": ["iam:CreateUser", "iam:CreateAccessKey", "iam:CreateLoginProfile"],
"Resource": "*"
}]
}
Protect designated administrative and security roles
{
"Version": "2012-10-17",
"Statement": [{
"Sid": "ProtectSecurityRoles",
"Effect": "Deny",
"Action": [
"iam:DeleteRole", "iam:DeleteRolePolicy", "iam:DetachRolePolicy",
"iam:PutRolePolicy", "iam:UpdateAssumeRolePolicy"
],
"Resource": [
"arn:aws:iam::*:role/SecurityAdministrationRole",
"arn:aws:iam::*:role/IncidentResponseRole",
"arn:aws:iam::*:role/OrganizationAccountAccessRole"
],
"Condition": {
"ArnNotLike": {
"aws:PrincipalArn": "arn:aws:iam::*:role/SecurityAdministrationRole"
}
}
}]
}
Restrict role passing
{
"Version": "2012-10-17",
"Statement": [{
"Sid": "DenyPassingPrivilegedRoles",
"Effect": "Deny",
"Action": "iam:PassRole",
"Resource": [
"arn:aws:iam::*:role/SecurityAdministrationRole",
"arn:aws:iam::*:role/OrganizationAccountAccessRole"
]
}]
}
This prevents users from indirectly gaining privilege by attaching a powerful role to Lambda, EC2, Glue, or another AWS service.
5. AWS KMS guardrails
Prevent deletion of KMS keys
{
"Version": "2012-10-17",
"Statement": [{
"Sid": "DenyKMSKeyDeletion",
"Effect": "Deny",
"Action": ["kms:ScheduleKeyDeletion", "kms:DeleteImportedKeyMaterial"],
"Resource": "*",
"Condition": {
"ArnNotLike": {"aws:PrincipalArn": "arn:aws:iam::*:role/KMSAdministrationRole"}
}
}]
}
Prevent key rotation from being disabled
{
"Version": "2012-10-17",
"Statement": [{
"Sid": "DenyDisablingKMSKeyRotation",
"Effect": "Deny",
"Action": "kms:DisableKeyRotation",
"Resource": "*"
}]
}
6. AWS CloudTrail guardrails
Prevent users in member accounts from disabling or deleting audit trails.
{
"Version": "2012-10-17",
"Statement": [{
"Sid": "ProtectCloudTrail",
"Effect": "Deny",
"Action": [
"cloudtrail:DeleteTrail", "cloudtrail:StopLogging", "cloudtrail:UpdateTrail",
"cloudtrail:PutEventSelectors", "cloudtrail:PutInsightSelectors"
],
"Resource": "*",
"Condition": {
"ArnNotLike": {"aws:PrincipalArn": "arn:aws:iam::*:role/SecurityAdministrationRole"}
}
}]
}
7. Amazon GuardDuty guardrails
{
"Version": "2012-10-17",
"Statement": [{
"Sid": "ProtectGuardDuty",
"Effect": "Deny",
"Action": [
"guardduty:DeleteDetector", "guardduty:DisassociateFromAdministratorAccount",
"guardduty:DisassociateMembers", "guardduty:StopMonitoringMembers",
"guardduty:UpdateDetector"
],
"Resource": "*",
"Condition": {
"ArnNotLike": {"aws:PrincipalArn": "arn:aws:iam::*:role/SecurityAdministrationRole"}
}
}]
}
8. AWS Config guardrails
{
"Version": "2012-10-17",
"Statement": [{
"Sid": "ProtectAWSConfig",
"Effect": "Deny",
"Action": [
"config:DeleteConfigurationRecorder", "config:DeleteDeliveryChannel",
"config:StopConfigurationRecorder"
],
"Resource": "*",
"Condition": {
"ArnNotLike": {"aws:PrincipalArn": "arn:aws:iam::*:role/SecurityAdministrationRole"}
}
}]
}
9. Amazon RDS guardrails
Require storage encryption
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyUnencryptedRDSInstances",
"Effect": "Deny",
"Action": "rds:CreateDBInstance",
"Resource": "*",
"Condition": {"Bool": {"rds:StorageEncrypted": "false"}}
},
{
"Sid": "DenyUnencryptedRDSClusters",
"Effect": "Deny",
"Action": "rds:CreateDBCluster",
"Resource": "*",
"Condition": {"Bool": {"rds:StorageEncrypted": "false"}}
}
]
}
Prevent public RDS databases
{
"Version": "2012-10-17",
"Statement": [{
"Sid": "DenyPublicRDSInstances",
"Effect": "Deny",
"Action": ["rds:CreateDBInstance", "rds:ModifyDBInstance"],
"Resource": "*",
"Condition": {"Bool": {"rds:PubliclyAccessible": "true"}}
}]
}
10. AWS Lambda guardrails
Restrict approved Lambda runtimes
{
"Version": "2012-10-17",
"Statement": [{
"Sid": "DenyUnapprovedLambdaRuntimes",
"Effect": "Deny",
"Action": ["lambda:CreateFunction", "lambda:UpdateFunctionConfiguration"],
"Resource": "*",
"Condition": {
"StringNotEqualsIfExists": {
"lambda:Runtime": ["python3.13", "nodejs22.x", "java21"]
}
}
}]
}
Container-image Lambda functions do not use the standard runtime parameter, so this policy requires careful testing.
Prevent public Lambda function URLs
{
"Version": "2012-10-17",
"Statement": [{
"Sid": "DenyPublicLambdaURLs",
"Effect": "Deny",
"Action": ["lambda:CreateFunctionUrlConfig", "lambda:UpdateFunctionUrlConfig"],
"Resource": "*",
"Condition": {"StringEquals": {"lambda:FunctionUrlAuthType": "NONE"}}
}]
}
11. Amazon VPC guardrails
Prevent unmanaged internet gateways
{
"Version": "2012-10-17",
"Statement": [{
"Sid": "DenyInternetGatewayChanges",
"Effect": "Deny",
"Action": [
"ec2:CreateInternetGateway", "ec2:AttachInternetGateway",
"ec2:DetachInternetGateway", "ec2:DeleteInternetGateway"
],
"Resource": "*",
"Condition": {
"ArnNotLike": {"aws:PrincipalArn": "arn:aws:iam::*:role/NetworkAdministrationRole"}
}
}]
}
Prevent VPC Flow Logs from being deleted
{
"Version": "2012-10-17",
"Statement": [{
"Sid": "ProtectVPCFlowLogs",
"Effect": "Deny",
"Action": "ec2:DeleteFlowLogs",
"Resource": "*",
"Condition": {
"ArnNotLike": {"aws:PrincipalArn": "arn:aws:iam::*:role/NetworkAdministrationRole"}
}
}]
}
12. Amazon DynamoDB guardrails
Prevent point-in-time recovery from being disabled
An SCP cannot force every new table to have point-in-time recovery enabled as part of a single table-creation operation because recovery is normally enabled through a separate API call. It can, however, prevent recovery from being disabled.
{
"Version": "2012-10-17",
"Statement": [{
"Sid": "DenyDisablingDynamoDBRecovery",
"Effect": "Deny",
"Action": "dynamodb:UpdateContinuousBackups",
"Resource": "*",
"Condition": {"Bool": {"dynamodb:PointInTimeRecoveryEnabled": "false"}}
}]
}
Use AWS Config or CloudFormation hooks to identify or prevent tables that never enable recovery.
13. Amazon EKS guardrails
Prevent public Kubernetes API endpoints
{
"Version": "2012-10-17",
"Statement": [{
"Sid": "DenyPublicEKSEndpoint",
"Effect": "Deny",
"Action": ["eks:CreateCluster", "eks:UpdateClusterConfig"],
"Resource": "*",
"Condition": {"Bool": {"eks:EndpointPublicAccess": "true"}}
}]
}
This is appropriate where administrative access is available through private connectivity. Confirm relevant condition-key support before production deployment.
14. Consolidated security-service protection
This example protects CloudTrail, AWS Config, GuardDuty, Security Hub, and IAM Access Analyzer against tampering.
{
"Version": "2012-10-17",
"Statement": [{
"Sid": "DenySecurityServiceTampering",
"Effect": "Deny",
"Action": [
"access-analyzer:DeleteAnalyzer", "cloudtrail:DeleteTrail",
"cloudtrail:StopLogging", "config:DeleteConfigurationRecorder",
"config:DeleteDeliveryChannel", "config:StopConfigurationRecorder",
"guardduty:DeleteDetector", "securityhub:DisableSecurityHub"
],
"Resource": "*",
"Condition": {
"ArnNotLike": {
"aws:PrincipalArn": [
"arn:aws:iam::*:role/SecurityAdministrationRole",
"arn:aws:iam::*:role/AWSControlTowerExecution"
]
}
}
}]
}
Recommended SCP rule-set structure
| Rule set | Typical controls |
|---|---|
| Organization baseline | Approved Regions, prohibited services, and root-user restrictions |
| Security protection | Protect CloudTrail, AWS Config, GuardDuty, and Security Hub |
| Identity protection | Protect security roles; restrict IAM users and role passing |
| Data protection | Require encryption for S3, EBS, and RDS |
| Network protection | Restrict internet gateways, public endpoints, and VPC changes |
| Cost protection | Approved EC2 instance types, GPU restrictions, and expensive Regions |
| Workload-specific | Separate controls for production, development, and sandbox OUs |
Implementation cautions
- Test each SCP against a sandbox OU before attaching it to production.
- An explicit SCP denial overrides IAM permissions, including administrator permissions.
- SCPs restrict the permissions available to principals; they do not grant permissions.
- Service-linked roles have special behavior and may not be restricted by SCPs in the same way as ordinary IAM principals.
- Use
ArnNotLikewithaws:PrincipalArnfor carefully controlled break-glass exemptions. - Avoid one enormous policy. Smaller policies are easier to test, version, and attach by OU.
- Combine SCPs with AWS Config, AWS Control Tower controls, CloudFormation hooks, and detective controls. Not every configuration requirement can be enforced reliably through an SCP alone.
These examples are starting points, not drop-in production policies. Validate action names, condition-key support, service dependencies, and exemption paths against your organization’s current AWS architecture.
Leave a Reply