Evaluation flow

Learn about the steps IAM takes in allowing or denying a request.

Now that we’ve discussed how IAM sees the request and how policies work that control access, it’s time to look into the exact steps it takes to reach a decision whether it allows or denies the request.

Step 1: Build the request context

First, it builds the request context based on the elements we’ve discussed in the Access elements lessons. This context includes the Principal, the entity making the request, the Action, describing what is being done, the Resource, the AWS entity that is the target of the operation, and other metadata attached to the request.

Unfortunately, there is little insight we have into the result of this step. It is probably a key-value structure where each key is populated from the request.

For example, when a user sends a request to AWS to read an object from an S3 bucket, the request context will be something like this:

Principal: arn:aws:iam::<id>:user/user1
Action: s3:GetObject
Resource: <bucket>/text.txt

These values are coming directly from what is in the operation, the Principal is doing an Action on a Resource. Then IAM populates the metadata with all the other available values:

Principal: arn:aws:iam::<id>:user/user1
Action: s3:GetObject
Resource: <bucket>/text.txt
aws:SourceIp: 203.0.113.0
aws:MultiFactorAuthPresent: true
aws:MultiFactorAuthAge: 3000

The above request context contains the IP address where the request came from, aws:SourceIp, and that the user is authenticated with an MFA device, aws:MultiFactorAuthPresent and aws:MultiFactorAuthAge. In practice, the request context contains a lot more information. This includes the username and the userid of the Principal, tags attached to the resource, regardless of if the request used SSL or not.

Note: The exact values in the request context are not known. We can only assume what they are by reading the documentation.

Step 2: Collect all applicable policies

The next step is to collect all applicable policies. As we’ve seen in the Filters lessons, most of the properties of an IAM policy specify which requests the policy is used for. IAM considers all policies, looks into the request context assembled in the previous step and considers each filter in each policy. The goal of this step is to remove all policies that do not match this request.

Note: This process is done for each policy individually. A policy is used in the next step only if all its filters match the request context.

For example, let’s consider an identity-based policy that is attached to a user called user1. In this case, the Principal element is implied:

{
    "Effect": "Allow",
    "Action": "s3:*",
    "Resource": "*"
}

Matching this against the request context example:

Principal: arn:aws:iam::<id>:user/user1
Action: s3:GetObject
Resource: <bucket>/text.txt

The filters in the policy are "Action": "s3:*", Resource: "*", and Principal: user1, as it is attached to that user.

Filter Value Match?
Action: s3:* s3:GetObject
Principal: user1 user1
Resource: * <bucket>/text.txt

Since all of the filers match, the policy will be used in the next step.

But when the request was made by a different user, user2, the request context contains a different Principal:

Principal: arn:aws:iam::<id>:user/user2
Action: s3:GetObject
Resource: <bucket>/text.txt

The filters in the above policy no longer match this request, so they won’t be used in the next step.

Filter Value Match?
Action: s3:* s3:GetObject
Principal: user1 user2 -
Resource: * <bucket>/text.txt

Note: It does not matter if the policy has "Effect": "Allow" or "Effect": "Deny" in this step. IAM only collects the policies that match the request. Allowing or denying access is handled in the next step.

A resource-based policy can define the Principal element to define what entities it applies to. The following policy allows user1 to read objects from the bucket:

{
    "Effect": "Allow",
    "Action": "s3:GetObject",
    "Principal": {
        "AWS": "arn:aws:iam::<id>:user/user1"
    },
    "Resource": "<bucket>/*"
}

When user1 is trying to read an object, this policy matches.

Filter Value Match?
Action: s3:GetObject s3:GetObject
Principal: user1 user1
Resource: <bucket>/* <bucket>/text.txt

But when user2 does the same, it does not:

Filter Value Match?
Action: s3:GetObject s3:GetObject
Principal: user1 user2 -
Resource: <bucket>/* <bucket>/text.txt

This process affects negated values too. For example, when the resource policy defines a NotPrincipal, it affects users who are not in the policy:

{
    "Effect": "Allow",
    "Action": "s3:GetObject",
    "NotPrincipal": {
        "AWS": "arn:aws:iam::<id>:user/user2"
    },
    "Resource": "<bucket>/*"
}

A request made by user1 passes all filters:

Filter Value Match?
Action: s3:GetObject s3:GetObject
NotPrincipal: user2 user1
Resource: <bucket>/* <bucket>/text.txt

But the same request made by user2 won’t:

Filter Value Match?
Action: s3:GetObject s3:GetObject
NotPrincipal: user2 user2 -
Resource: <bucket>/* <bucket>/text.txt

The same process works for NotAction and NotResource elements.

Finally, the Condition elements check the metadata in the request context. This resource-based policy requires authentication using an MFA device:

{
    "Version": "2012-10-17",
    "Statement": {
        "Effect": "Deny",
        "Principal": "*",
        "Action": "*",
        "Resource": "<bucket>/*",
        "Condition": {
            "Bool": {
                "aws:MultiFactorAuthPresent": "false"
            }
        }
    }
}

When a user is using an MFA device, this policy won’t match:

Filter Value Match?
Action: * s3:GetObject
Principal: * user1
Resource: <bucket>/* <bucket>/text.txt
aws:MultiFactorAuthPresent: false true -

Similarly, when not using an MFA device, the policy matches:

Filter Value Match?
Action: * s3:GetObject
Principal: * user1
Resource: <bucket>/* <bucket>/text.txt
aws:MultiFactorAuthPresent: false false

Note: The result of this step is a set of policies that match the request context. These policies are used in the next step.

Step 3: Run the evaluation logic

After collecting the effective statements using the filters, it uses the policy evaluation logic to decide if the request is allowed. The AWS documentation has a descriptive image to summarize how it works:

Get hands-on with 1400+ tech skills courses.