← All posts
2 min read

Restrict an IAM policy by source IP

#aws#cli#iam#security#identity
📑 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"}
    }
  }]
}
EOF

203.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.json

Read 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.json

Include 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.json

No live policy was attached.

Next, we will learn Prove that explicit IAM Deny wins.

Official AWS CLI reference