A high level overview of identity and resource-based IAM policies

IAM is one of the most important services in AWS when it comes to security and restricting access to services. IAM has a couple of different types of policies. In this post, I'll write about identity and resource policies and the difference between them.

One of the security pillars in AWS is Identity and Access Management. The main service responsible for this pillar is called (guess what) AWS Identity and Access Management or IAM for short.

1. Policies

IAM manages access to services through policies.

Policies are JSON documents and there are multiple types of policies. Policies give permissions to IAM identities (users, groups and roles) to access services (like S3) and their APIs (like GetObject). This way, they provide a tool for authorization, i.e. which identity is allowed to do what.

Two frequently used policy types are the identity-based and resource-based policies.

2. Policy elements

The most important elements of the policy are Principal, Effect, Action and Resource.

Principal refers to the who. Who is getting (or denied) permission to a service or its API? It’s referenced by the ARN (Amazon Resource Name) of the IAM identity.

Effect can have two values, Allow or Deny. The values are straightforward: Allow lets the user access a service, Deny forbids it. By default, an IAM identity has no permissions to anything (implicit deny). An Allow rule always overrides the implicit deny, and an explicit Deny rule always stronger than the explicit Allow.

Action is about the what, i.e. the API or list of APIs the Principal is allowed or denied to. For example, it can be a permission to list the items in a DynamoDB table. It always has the form of service:ActionType, so the permission to list the items would be dynamodb:Scan. It’s possible to define multiple actions, and in this case, Action will be an array.

Resource specifies which service is the permission (Action) related to. In the case of DynamoDB, this would be the name of the table. Again, there could be multiple tables listed here, so Resource could be an array of strings.

3. Identity-based policies

Identity-based policies are attached to one or more IAM identities. They explicitly state what a user or role is allowed (or denied) to do.

Alice’s (who manages the data of secret agents) identity-based policy (or probably part of it) can look like this:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "FullSecretAgentsAccess",
      "Effect": "Allow",
      "Action": [
        "dynamodb:*"
      ],
      "Resource": "arn:aws:dynamodb:us-west-2:123456789012:table/SecretAgents"
    }
  ]
}

Alice is Allowed to do everything in the SecretAgents table in the 123456789012 account in the us-west-2 region. The * wildcard character indicates that she can list (Scan) or query (Query) the items, or even delete a particular item (DeleteItem). The permissions and the APIs almost always map one-to-one to each other, i.e. Alice can use the aws dynamodb delete-item CLI command to delete an item from the table.

It’s important to note that there is no Principal in the identity-based policies. Principals are not needed here; they are assigned to a user, group or role (i.e. an identity) and it doesn’t make much sense to define the Principal key (and it’s not even allowed).

4. Resource-based policies

They are attached to a resource, for example, to an S3 bucket. Bucket policies are the most well-known examples for resource-based policies.

A bucket policy for the gadgets-for-agents bucket can look like this:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "GadgetsReadOnlyAccess",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::123456789012:user/alice"
      },
      "Action": [
        "s3:GetObject",
        "s3:ListBucket"
      ],
      "Resource": [
        "arn:aws:s3:::gadgets-for-agents",
        "arn:aws:s3:::gadgets-for-agents/*"
      ]
    }
  ]
}

This policy Allows Alice (who is a user of the 123456789012 account) to list the objects in the bucket as well as to read the content of the objects stored in the bucket.

Resource-based policies have Principals because they need to be tied to a user, role or group of users.

The * as the value of the Principal key refers to every user (can be related to the account or a public user).

5. Get the union

If both the user and the resource belong to the same account, IAM will assess the permissions based on the union of the identity-based and resource-based policies.

This means that if a permission (for example, the s3:GetObject is Allowed) is defined either in an identity-based or an resource-based policy (or it could also be in both) to a user, IAM will consider it as an explicit Allow and the user will be allowed to access view the content of the object (if there’s no explicit Deny). This allows administrators to have flexibility in assigning permissions.

It’s not necessary to modify Alice’s identity policy if we want to give her access to the gadgets-for-agents bucket. She might be part of a group of many users with a common policy and the administrator doesn’t need to give permission to the bucket to everyone in the group.

By specifying Alice in the resource (bucket) policy, she will be able to read the bucket as required while other users in the group won’t.

6. Summary

IAM is the main service for Identity and Access Management in AWS.

The building blocks of IAM are the policies, which are JSON documents.

Two frequently used types of IAM policies are the identity- and resource-based policies.

Identity policies don’t have Principals because they are already attached to an identity (user, group or role). Resource policies are attached to services and they need to define the subject of the permission in the form of a Principal key.

Thanks for reading and see you next time.