Many AWS administrators face this scenario: despite clear organizational policies requiring resources to be created in eu-west-1
, developers keep spawning EC2 instances and S3 buckets in us-east-1
due to AWS's default region behavior. This creates operational overhead, compliance issues, and unexpected costs.
The most effective solution is implementing IAM policies with explicit region restrictions. Here's a comprehensive policy example:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Deny",
"NotAction": [
"iam:*",
"organizations:*",
"route53:*",
"cloudfront:*",
"sts:*"
],
"Resource": "*",
"Condition": {
"StringNotEquals": {
"aws:RequestedRegion": "eu-west-1"
}
}
}
]
}
The policy works by:
- Denying all actions except global services (IAM, Route53 etc.)
- Using
StringNotEquals
condition to restrict toeu-west-1
- Whitelisting necessary global services that don't operate regionally
For organizations with more complex needs:
// Multi-region restriction example
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Deny",
"NotAction": [
"iam:*",
"route53:*"
],
"Resource": "*",
"Condition": {
"ForAnyValue:StringNotEquals": {
"aws:RequestedRegion": [
"eu-west-1",
"eu-central-1"
]
}
}
}
]
}
Combine IAM policies with AWS Config rules for additional protection:
// AWS Config rule to detect non-compliant resources
{
"ConfigRuleName": "restrict-resources-to-region",
"Description": "Ensures resources are created only in eu-west-1",
"Source": {
"Owner": "AWS",
"SourceIdentifier": "RESOURCES_IN_REGION"
},
"InputParameters": {
"regionName": "eu-west-1"
},
"Scope": {
"ComplianceResourceTypes": [
"AWS::EC2::Instance",
"AWS::S3::Bucket"
]
}
}
For organizations using AWS Organizations, SCPs provide account-wide enforcement:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyAllOutsideIreland",
"Effect": "Deny",
"Action": "*",
"Resource": "*",
"Condition": {
"StringNotEquals": {
"aws:RequestedRegion": "eu-west-1"
},
"Null": {
"aws:RequestedRegion": "false"
}
}
}
]
}
To minimize disruption:
- Set
eu-west-1
as default in AWS CLI profiles - Configure region in SDK initialization for all applications
- Create CloudFormation templates with hardcoded regions
# AWS CLI configuration example
[profile dev-team]
region = eu-west-1
output = json
Implement CloudWatch alarms to detect region policy violations:
aws cloudwatch put-metric-alarm \
--alarm-name "CrossRegionResourceCreation" \
--metric-name "ResourceCount" \
--namespace "AWS/Usage" \
--statistic "Sum" \
--dimensions "Name=Resource,Value=EC2:Instances" "Name=Region,Value=us-east-1" \
--period 300 \
--evaluation-periods 1 \
--threshold 1 \
--comparison-operator "GreaterThanOrEqualToThreshold"
In multi-region AWS environments, developers frequently create resources in unintended regions (typically us-east-1) due to:
- CLI default configurations
- Forgetting to specify --region parameter
- SDKs falling back to default regions
- Console users not changing the region selector
Here's a comprehensive IAM policy that enforces eu-west-1 exclusively:
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Deny",
"NotAction": [
"iam:*",
"organizations:*",
"budgets:*",
"support:*",
"sts:*",
"cloudfront:*",
"route53:*",
"s3:Get*",
"s3:List*"
],
"Resource": "*",
"Condition": {
"StringNotEquals": {
"aws:RequestedRegion": "eu-west-1"
}
}
}
]
}
The policy works through several critical mechanisms:
- The
Deny
effect takes precedence over any Allow permissions NotAction
whitelists global services that don't require region specification- The
aws:RequestedRegion
condition key checks API calls - S3 read operations are exempted since bucket locations are region-specific
For organizations using AWS Organizations, implement this via SCPs:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyAllOutsideIreland",
"Effect": "Deny",
"Action": "*",
"Resource": "*",
"Condition": {
"StringNotEquals": {
"aws:RequestedRegion": "eu-west-1",
"aws:PrincipalArn": [
"arn:aws:iam::*:role/breakglass-admin",
"arn:aws:iam::*:user/emergency-user"
]
}
}
}
]
}
Certain scenarios require special consideration:
- Global services like IAM, Route53, and CloudFront
- Cross-region operations for DR purposes
- CI/CD pipelines that need multi-region deployments
Create explicit Allow policies for these use cases with strong naming conventions like AllowGlobalServices
.
Complement IAM policies with AWS Config rules:
# config-rule-check-region.py
import boto3
def evaluate_compliance(config_item, rule_parameters):
if config_item['resourceType'] not in rule_parameters['ApplicableResourceTypes']:
return 'NOT_APPLICABLE'
return 'NON_COMPLIANT' if config_item['awsRegion'] != rule_parameters['TargetRegion'] else 'COMPLIANT'
To minimize productivity impact:
- Set AWS_DEFAULT_REGION in shared environment variables
- Configure region in AWS CLI profiles
- Create IDE plugins that validate region selection