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 1200+ tech skills courses.