What are the elements of an IAM policy?

IAM is an essential AWS service in securing cloud infrastructure. It's often misused and its role in securing platforms and applications is often underestimated. In this post I'll provide a brief overview of the structure of IAM policies.

Identity Access Management (IAM) is one of the most important services to secure applications in any infrastructure built in AWS.

It determines who can access what and what they can do with that service. It can restrict access from unwanted users and it has an important role in federation as well.

IAM is a global service and as such, settings are available in all regions. For example, if I have permission by IAM to create a CloudFormation stack, I can create it in all regions.

1. Policy types

The document that declares the permissions is called a policy.

Policies are JSON documents, and they can look like this:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": [
          "logs:*"
      ],
      "Effect": "Allow",
      "Resource": "*"
    }
  ]
}

The above policy gives a user full access to CloudWatch Logs.

We can create policies ourselves but we can also use managed policies, which are already defined by AWS and are ready to use.

Policies can be grouped in multiple ways and one of them is to separate them as resource policies and user policies.

1.1. Resource policies

Resource policies are usually attached to a resource or service.

For example, an S3 bucket policy (defining permissions on a particular bucket) is a resource policy.

The following bucket policy is attached to a bucket which has website hosting enabled:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": "*",
      "Action": [
        "s3:GetObject"
      ],
      "Resource": [
        "arn:aws:s3:::mybucket/*"
      ]
    }
  ]
}

If we compare this policy to the one above, there is a key difference: It has a Principal property, which defines who is allowed to perform the action on the resource. More on that below.

1.2. User policies

User policies are related to an authenticated user. They don’t have the Principal property, because it wouldn’t make any sense. The user profile (it can be a role as well) already determines who the Principal is.

2. Policy elements

Policies have a few common properties. These properties can be found in the Statement array. Statement - as the name implies - states what the policy is about.

Optionally, a Version property can also be defined in the JSON file, which locks the version of the policy in case AWS changes it (hardly ever happens).

2.1. Effect

Effect states if the access to the resource is Allow (i.e. allowed) or Deny (i.e. denied).

By default, the value is Deny, so the access to the resource is implicitly denied, similarly to security group rules. If the Allow value is not explicitly defined, the access will be denied.

The explicit Deny can be used to override a former Allow value.

2.2. Principal

Principal refers to the entity that is allowed or denied to have access to the resource.

In the bucket policy above, the * refers to everyone in the world and even beyond. This makes sense in the case of a website, because we want everyone to view our website, so we use the wildcard character as the Principal.

In other cases we want to limit the access to a resource. It’s not really a good idea to give everyone at the company permission to delete buckets containing critical pieces of information. For reasons like this, Principal allows us to specify the account or the user as well:

"Principal": {
  "AWS": [
    "arn:aws:iam::123456789123:user/user.one",
    "arn:aws:iam::123456789123:user/user.two"
  ]
}

2.3. Resource

Resource refers to the service the permission is given for.

For example, an administrator can have access to every service, in this case we can use the * wildcard character:

"Resource": "*"

But life is not fair, and not everyone can be administrator and have access to everything.

In the S3 bucket example above, it would be very dangerous to allow everyone in the world ("Principal": "*") to gain access to other resources, so we have to limit it to the relevant bucket:

"Resource": [
  "arn:aws:s3:::mybucket/*"
]

Again, we can list the resources in an array, because it’s possible to give access to more than one resource in the same policy.

2.4. Action

Action defines what is allowed or denied on the specified resource. Action values can sometimes be hard to interpret and a bit of experience in AWS comes definitely handy when it comes to defining actions.

Action values consist of two parts: the namespace of the service and the actual action that is allowed or denied.

The namespace is usually the name of the service, like logs (for CloudWatch Logs), ec2 or s3.

The action part refers to the operation that can be done on the service, for example GetObject in the case of an S3 bucket, or SendMessage to an SQS queue.

Similarly to Resource, it’s also possible to list multiple actions in an array.

If everything is allowed or denied for a service, the * character can be used:

"Action": "s3:*"

2.5. Condition - optional

Conditions allow us to specify conditions for the policy. When these conditions are met, the rules in the policy will be in effect.

By using Conditions, we can create more advanced policies. Several operators can be used to design conditions, which will be the topic of another post.

3. Summary

IAM policies are one of the most important security tools in the AWS toolset.

Policies are JSON documents with some compulsory and optional properties. Although one might take some time to understand IAM policies, the structure of the policies is logical, and developers can eventually become skilled enough to write their own custom policies.

Thanks for reading and see you next time.