If we had to name the most critical service to understand when it comes to AWS security, it would have to be IAM (Identity and Access Management).

IAM controls the access and permissions to your users, services, data, and applications across all of your AWS accounts. Badly managed AWS IAM can lead to anything from a minor security breach to multi-million dollar breaches.

As an example, I’ve demonstrated how an improper IAM policy with low-level privileges can be exploited to gain admin-level privileges and hijack an AWS account.

Since it’s such an important service to understand and properly configure, how can we go about learning how to use it? While there are many concepts of IAM we need to understand, for this post, let’s focus on IAM policies and how to write them.

What better way to do that than with a cheat sheet?

By the way, this cheat sheet is straight from our Introduction to AWS Security course.

Downloadable image-based cheat sheet

Anatomy of IAM Policies in AWS

AWS IAM

Example IAM Policy

IAM policy elements and their meaning
IAM policy elements and their meaningVersion This defines the version of the policy language, not the version of the managed policy itself. 2012-10-17 is the latest and should be used to access all features. Statement The policy statement where you add what’s allowed or denied using Effects, Actions, and Resources. Effect Allow: Allows the specified action(s) against the specified resource(s), subject to other applicable policies. Deny: Explicitly denies the specified action(s) against the specified resource(s). Useful to overrule allow statements. Implicit deny: By default, IAM assumes actions aren’t allowed. Without an applicable allow, the request is implicitly denied. This is not an Effect value. Action The action(s) to be allowed or denied. This can be a single action or an array of actions. Resource This is the resource(s) for which the effect and action(s) will be applied. For example, it can be EC2 resources, S3 resources, roles, users, etc. ARN: Amazon Resource Name (unique identifier). Condition Specific conditions for when a policy is in effect. This is optional and it can take in a number of different condition operators, condition keys, and condition values. Condition example This example denies the listed actions when none of the requested tag keys matches Production. It checks tag names, not values, and also applies when no tag keys are provided. Condition operator: ForAllValues:StringNotLike Condition key: aws:TagKeys Condition value: ProductionIAM policy · JSON{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "s3:GetObject", "s3:PutObject", "s3:DeleteObject" ], "Resource": "arn:aws:s3:::example-bucket/*" }, { "Effect": "Allow", "Action": "ec2:StartInstances", "Resource": "arn:aws:ec2:region:account-id:instance/instance-id" }, { "Effect": "Allow", "Action": "ec2:DescribeInstances", "Resource": "*" }, { "Sid": "RunInstancesRestrictions1", "Effect": "Deny", "Action": [ "ec2:CreateVolume", "ec2:RunInstances" ], "Resource": [ "arn:aws:ec2:*:*:volume/*", "arn:aws:ec2:*:*:instance/*" ], "Condition": { "ForAllValues:StringNotLike": { "aws:TagKeys": "Production" } } } ]}VersionThis defines the versionof the policy language,not the version of themanaged policy itself.2012-10-17 is the latestand should be used toaccess all features.StatementThe policy statement whereyou add what’s allowed ordenied using Effects,Actions, and Resources.EffectAllowAllows the specifiedaction(s) against thespecified resource(s),subject to otherapplicable policies.DenyExplicitly denies thespecified action(s)against the specifiedresource(s). Useful tooverrule allow statements.Implicit denyBy default, IAM assumesactions aren’t allowed.Without an applicableallow, the request isimplicitly denied. This isnot an Effect value.ActionThe action(s) to beallowed or denied. Thiscan be a single action oran array of actions.ResourceThis is the resource(s)for which the effect andaction(s) will be applied.For example, it can be EC2resources, S3 resources,roles, users, etc.ARNAmazon Resource Name(unique identifier).ConditionSpecific conditions forwhen a policy is ineffect. This is optionaland it can take in anumber of differentcondition operators,condition keys, andcondition values.Condition exampleThis example denies the listed actions when none of therequested tag keys matches Production. It checks tagnames, not values, and also applies when no tag keys areprovided.Condition operatorForAllValues:StringNotLikeCondition keyaws:TagKeysCondition valueProduction
IAM policy elements and their meaning

Drag the background to pan. Use the controls to zoom or fit the full diagram. Press Escape to close.

Use this cheat sheet with AI

Copy a ready-to-use prompt into your preferred AI assistant.

Preview prompt

Let’s break this down a bit more.

Evaluating the example IAM policy

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:GetObject",
                "s3:PutObject",
                "s3:DeleteObject"
            ],
            "Resource": "arn:aws:s3:::example-bucket/*"
        },
        {
            "Effect": "Allow",
            "Action": "ec2:StartInstances",
            "Resource": "arn:aws:ec2:region:account-id:instance/instance-id"
        },
        {
            "Effect": "Allow",
            "Action": "ec2:DescribeInstances",
            "Resource": "*"
        },
        {
            "Sid": "RunInstancesRestrictions1",
            "Effect": "Deny",
            "Action": [
                "ec2:CreateVolume",
                "ec2:RunInstances"
            ],
            "Resource": [
                "arn:aws:ec2:*:*:volume/*",
                "arn:aws:ec2:*:*:instance/*"
            ],
            "Condition": {
                "ForAllValues:StringNotLike": {
                    "aws:TagKeys": "Production"
                }
            }
        },
    ]
}
  • Version – this refers to the version of the policy element, not the policy version itself. It defines the version of the policy language. 2012-10-17 is the latest version and should be used to access the latest features
  • Statement – this is the policy statement itself, and where you add what’s allowed or denied using Effects, Actions, and Resources
  • Effect: “Allow” – this allows the specified action(s) against the specified resource(s) 
  • Effect: “ Deny” – this is an explicit deny which denies the specified action(s) against the specified resource(s)
  • No effect (implicit deny) – By default, AWS IAM assumes actions aren’t allowed for security reasons. This means that if you don’t specify an allow statement, it will be implicitly denied. This is very different from Explicit denies (“Effect”: “Deny”) which overrules any Allow
  • Action – The action to be allowed or denied. This can a single action or an array of actions
  • Condition – Specific conditions for when a policy is in effect. This is an optional element and it can take it a number of different condition operators (in this example: ForAllValues:StringNotLike, condition keys (in this example: aws:TagKeys, and condition values (in this example, Production)
  • Resource – This is the resource(s) for which the effect and action(s) will be applied. For example, it can be ec2 resources, s3 resources, roles, users, etc…
  • While not shown in this basic example, there are also more advanced options, such as to use variables (ie: ${aws:username}), for better filtering and specificity, especially in Condition elements

Example Scenario: Cross-Account Roles

Let’s assume a scenario where we want to grant permission to a service and user in AWS account A to perform some actions in our AWS account B, such as viewing some of our CloudWatch logs for certain logs groups. We will need to create:

  • Role A in account A, which will be attached to the service and will be allowed to assume the role in account B
  • Role B in account B, which will allow Role A from account A to assume it, and the permissions it has (view CloudWatch logs) 

Account A – AssumeRole Policy

This is what allows users or services in Account A to assume the role (RoleB) in Account B, and should be attached to RoleA

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": "sts:AssumeRole",
            "Resource": "arn:aws:iam::111111111111:role/RoleB"
        }
    ]
}

Account B – Trust Relationship Policy

Then in account B, we need to create a policy attached to RoleB

This is what allows the user from Account A to assume this role because we’ve explicitly stated that they are trusted. This is attached to RoleB

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::222222222222:role/RoleA"
            },
            "Action": "sts:AssumeRole"
        }
    ]
}

Account B – Permissions Policies

This is the policy/policies used to dictate what users or services can do once they’ve assumed the role in Account B. In our example, view CloudWatch logs. This will be attached to RoleB.

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "logs:GetLogEvents",
                "logs:FilterLogEvents",
                "logs:DescribeLogStreams"
            ],
            "Resource": [
                "arn:aws:logs::111111111111:log-group:log-group-name-1:*",
                "arn:aws:logs::111111111111:log-group:log-group-name-2:*"
            ]
        }
    ]
}

Summary/Overview and Additional Info

  • Account B is our “destination”
  • Account A is our “source”
  • Meaning that we want users or resources in Account A to be able to assume the role in the Account B
  • Once a user or resource assumes the role in Account B, they temporarily renounce their permissions and assume the new permissions based on the role’s policies in Account B.
    • For example, if the user has administrative privileges in Account A but they assume the role in Account B and that role only has very narrow/specific permissions, they will not have administrative privileges in Account B and they will have to re-assume the role in Account A to regain their admin privileges in Account A
  • While assuming Role B, Role A will be able to view the desired logs in Account B

More cheat sheets

If you’d like to grab more AWS security cheat sheets, you can check them out here.

If you’d like to get started with learning AWS Security, check out our Introduction to AWS Security course.