Restrict an IAM policy by source IP
📑 On this page
Part 107 of AWS from Zero. This lesson changes or inspects one IAM concept so the permission model stays understandable.
What we are learning
Global condition keys can narrow when an allow statement applies. Source-IP controls work only when the request context contains the expected public IP.
Before you run it
aws sts get-caller-identity
ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
USER_NAME="aws-zero-learner"
GROUP_NAME="aws-zero-readers"
ROLE_NAME="aws-zero-demo-role"IAM is global rather than regional. Use a sandbox account and a delegated administrator identity, never root access keys.
The command
cat > source-ip-policy.json <<'EOF'
{
"Version": "2012-10-17",
"Statement": [{
"Effect": "Allow",
"Action": "s3:ListAllMyBuckets",
"Resource": "*",
"Condition": {
"IpAddress": {"aws:SourceIp": "203.0.113.0/24"}
}
}]
}
EOF203.0.113.0/24 is documentation-only address space. Replace it with a reviewed corporate egress range before real use.
Inspect the result
aws accessanalyzer validate-policy \
--policy-type IDENTITY_POLICY \
--policy-document file://source-ip-policy.jsonRead the returned ARN, path, IDs, and attachment state instead of checking only the command exit code.
One tiny variation
sed 's/"203.0.113.0\/24"/["203.0.113.0\/24","2001:db8::\/32"]/' source-ip-policy.json > source-ip-dual-stack.jsonInclude IPv6 egress ranges when clients can reach AWS over IPv6.
Common mistake
Source IP conditions can break calls routed through VPC endpoints, proxies, VPNs, or AWS services because the observed context differs from a laptop's address.
Cleanup
rm source-ip-policy.json source-ip-dual-stack.jsonNo live policy was attached.
Next, we will learn Prove that explicit IAM Deny wins.