AWS IAM

The Boundary Said No, and the Boundary Won

September 4, 2026

Least privilege is easy to state but harder to enforce—several compliance frameworks such as PCI DSS 7.2.5, NIST CSF PR.AA-05, ISO 27001 A.8.2 — agree that identities should get the minimum access necessary, but leave the how up to you. In practice, permissions grow through hundreds of small, well-intentioned decisions: a new IAM administrator who doesn’t yet know the org’s conventions, a policy copy-pasted from an old template with wider scope than intended, a well-meaning grant that’s just slightly too broad.

AWS’s answer to permission creep is a permission boundary, a ceiling that caps what an identity can be granted, regardless of what gets attached to it later. It doesn’t grant access on its own or replace a well-scoped policy, but guarantees that when someone gets the identity policy wrong, the blast radius stays contained.

Here is an AWS identity with a permission boundary attached:

aws iam get-user --user-name iam-lab-student-bounded --query 'User.PermissionsBoundary'
{
    "PermissionsBoundaryType": "Policy",
    "PermissionsBoundaryArn": "arn:aws:iam::216989115214:policy/iam-lab-boundary-deny-write"
}
aws iam get-policy-version \
  --policy-arn arn:aws:iam::216989115214:policy/iam-lab-boundary-deny-write \
  --version-id v1 \
  --query 'PolicyVersion.Document'
{
    "Statement": [
        {
            "Action": [
                "s3:GetObject",
                "s3:ListBucket"
            ],
            "Effect": "Allow",
            "Resource": "*",
            "Sid": "BoundaryAllowReadOnly"
        }
    ],
    "Version": "2012-10-17"
}

The boundary states that, no matter how many buckets this identity is given access to, and regardless of which identity policy gets attached, it will only be able to read, never write, to those buckets.

Here is an identity policy attached to the same identity:

aws iam list-user-policies --user-name iam-lab-student-bounded
aws iam get-user-policy --user-name iam-lab-student-bounded --policy-name attempt-full-s3
{
    "PolicyNames": [
        "attempt-full-s3"
    ]
}
{
    "UserName": "iam-lab-student-bounded",
    "PolicyName": "attempt-full-s3",
    "PolicyDocument": {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Action": [
                    "s3:*"
                ],
                "Effect": "Allow",
                "Resource": "*",
                "Sid": "IdentityPolicyGrantsFullS3"
            }
        ]
    }
}

This policy is extremely permissive, as it allows all actions on all S3 buckets, including writes, ACL policy changes, and bucket creation and deletion. However, if this identity attempts to write to this bucket, it will fail because of the permissions boundary. Although the identity policy is extremely permissive, the boundary caps the permissions this identity can be granted.

aws s3 cp /etc/hostname s3://$(tofu output -raw bucket_name)/test.txt
upload failed: ../../../../../etc/hostname to s3://iam-lab-216989115214/test.txt An error occurred (AccessDenied) when calling the PutObject operation: User: arn:aws:iam::216989115214:user/iam-lab-student-bounded is not authorized to perform: s3:PutObject on resource: "arn:aws:s3:::iam-lab-216989115214/test.txt" because no permissions boundary allows the s3:PutObject action

Notice that it fails because “no permissions boundary allows s3:PutObject”, not because no identity policy allows it. The identity policy said yes to everything, but the boundary said no to writes - and the boundary won.