Introduction

Traditionally, perimeter security was about what tools, devices, and procedures can be placed around a network to prevent bad things from going in or out. In a cloud platform, there’s an additional layer of controls that specify the access between services, resources, machines, and people that are defined via software. In Amazon Web Services (AWS), this is handled by Identity and Access Management (IAM). While AWS IAM is a service unto itself with its own resources and resource types, it’s also the central governing model of access to all other AWS resources.

DivvyCloud by Rapid7 has spent the better part of a year building a product that ingests AWS IAM data to present it in a useful way to our customers. During product development, we learned about the many parts of this complex system: its patterns, its intricacies, its gotchas, and its shortfalls. This guide is a collection of data points that we’ve found as compelling evidence that AWS IAM is the most complex service that AWS offers. Unfortunately, AWS does not provide a developer-friendly way to ingest all of the IAM information across their service offerings and the documentation that is available is somewhat inconsistent, so a big thanks goes out to the folks behind the Policy Sentry tool, which made collecting the figures for this guide much simpler.

Policy Evaluation

Every AWS API request is evaluated by IAM in a 21 step process that starts with an assumption that the request for access should be denied and flows through 5 different types of policy evaluations — Service Control Policies (SCPs), Resource Policies, Permission Boundary Policies, Session Policies, and Identity Policies — to determine whether the request meets the required criteria to allow the desired behavior.

Services and Resources

Since debuting in 2006 with 3 services, AWS has added an additional 245 services. That’s an average of 17 new services every year. But the number of AWS services don’t tell the whole story of the complexity in IAM. For each service, there can be multiple resource types — take EC2 for example. There are instances, VPCs, load balancers, EBS Volumes, and many more. Across all 248 services, there are 819 resource types. Eight percent of the services hold almost 40 percent of the resource types, with EC2 (52 resources) and SageMaker (27 resources) at the top of the list.

Lights, Camera, Action(s)!

Of course, you can’t do much with a resource without an allowable action. When used in a policy, an action allows you to define access to an AWS API. Some sample actions for the S3 service are:

  • s3:ListBucket,
  • s3:GetBucketLocation, and
  • s3:PutObject.

The breakdown of those known actions to categories is as follows:

CategoryCount
Write3,952
Read1,986
Listing1,411
Tagging311
Permission Management299

Across all AWS services and resources, there are almost 8,000 actions. The large number of actions available is also a good measure of the flexible and granular control that AWS gives the user. Typically, you provide an Amazon Resource Name (ARN) for actions in statements, but not all actions let you define an ARN. There are many that only support a wildcard (*) character. In fact, there are 2,985 actions in the documentation that are not associated with a resource, meaning that you can not restrict them based on an ARN. While a large portion of those actions that do not support ARNs are Describe/List related, many are not. Some have resource IDs as required inputs in the API calls that correspond to the actions, which indicates they could possibly support ARN restrictions in the future.

IAM Policies

There are five types of policies (SCPs, Resource Policies, Permission Boundaries, Session Policies, Identity Policies) that can be associated with organizations, principals, and resources. Policies are a collection of statements that define actions that can be performed on specified resources and are evaluated when a principal makes a request to a resource. Statements have multiple elements, including: Effect, Principal, Action, Resource, and Condition. There are some elements that are mutually exclusive as well, meaning you cannot use both in the same statement: NotPrincipal(Principal), NotAction(Action), and NotResource(Resource).

In a resource policy, there are seven different types of principals that can be defined. Of those principal types, three can have identity policies attached.

Policies can have one or more statements. The actions and effects are scoped to individual statements. This is useful when you have specific, conditionally-based scenarios for certain actions, but general intent for others. In the policy evaluation logic, it is ultimately the entire combinatorial effect of all the condition, resource, and principal elements on a specific action that determine your outcome.

Conditionals

Policies are not as simple as saying that a principal has s3:Listbucket access to a bucket named “foobar” because that access can be caveated with a conditional. Conditionals in IAM policies can be extremely useful to security administrators but can introduce a level of dynamicity, which makes it time consuming for humans to evaluate. Across all services and resource types, there are 449 unique Conditional Context Keys. These are the keys that are used to validate the conditional statement (PrincipalName, for example). Of those 449 keys, 31 of them are Global Conditional Context Keys, meaning that they can be used with any resource type, leaving 421 Conditional Context Keys that are service specific across 60 services.

Almost 80 percent of the 421 service-specific Conditional Context Keys are used by just 20 percent of the services that support them. EC2 leads the way with 66 keys, followed by S3 with 38. This is to be expected, as EC2 and S3 are two of the oldest and most used AWS services and the number of keys has grown with those services over time.

Control Mechanisms

So far, we’ve covered IAM policies that have the potential for variables, lists, dictionaries, and operators. There are also two control mechanisms for looping through values to support a Conditional Statement in a policy: ForAnyValue, ForAllValues. Both of these can support one or more Conditional Context Keys with a list of values to iterate. Here’s a fun example of ForAnyValue:

"Condition": {
   "StringEquals": {
     "aws:RequestedRegion": "us-east-1"  
   },
   "ForAnyValue:StringNotLike": {
     "aws:PrincipalArn": [
       "arn:aws:iam::*:role/S3_ReadOnly"
     ],
     "aws:PrincipalAccount": [
       "123456789012",
       "123456789123",
     ],
     "aws:PrincipalOrgPaths": [
       "o-abc/r-def/ou-ghijklmnop/*"
     ]
   }
 }

This condition will be evaluated as true if:

  • The RequestRegion is us-east-1 AND
    • The principal making the request does not have an ARN that matches arn:aws:iam::*:role/S3_ReadOnly OR
    • The Principal account is not 123456789012 or 123456789123 OR
    • The PrincipalOrgPath does not match o-abc/r-def/ou-ghijklmnop/*

ARN’t You Glad I Didn’t Say Banana?

An ARN is a naming convention to uniquely identify an AWS resource. When writing a policy, you must use the ARN to specify the resource that is associated with the statement.

At a glance, the components of an ARN seem relatively simple:
arn:partition:service:region:account-id:resource-id

But there are actually two more ARN types that don’t meet that pattern:
arn:partition:service:region:account-id:resource-type/resource-id
arn:partition:service:region:account-id:resource-type:resource-id


But how does that account for ARNs like this?
arn:partition:sagemaker:region:account-id:app/${DomainId}/${UserProfileName}/${AppType}/${AppName}

It turns out, there’s a lot of variation that comes in after the account-id string in the ARN. To make that more clear, let’s split an ARN up in two parts. Everything up to the account-id string (base ARN) and everything afterwards (Resource Path).

Let’s take this ARN for example:
arn:partition:service:region:account-id:resource-type/resource-id

That breaks down into the following parts.:

Base ARNResource Path
arn:partition:service:region:account-idresource-type/resource-id

Base ARN Patterns

If we use this method to evaluate all Base ARN types across all AWS Resource types, we find that 664
resource types (82 percent) use:
arn:partition:service:region:account-id

There are slight variants of that ARN pattern:

  • Region is not part of the ARN (41 resource types)
  • Account is not part of the ARN (19 resource types)
  • Region and Account are not part of the ARN (13 resource types)

There are outliers like Organizations service policies that have no account ID:
arn:${Partition}:organizations::aws:policy/${PolicyType}/p-${PolicyId}

Resource Patterns

So let’s look at the other side of the ARN, the Resource Path. With resource paths, there is more variance in how they are defined.

The most common Resource Path patterns across resource types are:

FIXED/VARIABLE460
FIXED:VARIABLE71
FIXED/VARIABLE/FIXED/VARIABLE45
FIXED/VARIABLE/VARIABLE39

These account for approximately 83 percent of all Resource Path patterns.

Twenty-one Resource types have Resource Path patterns that are unique to that resource (not used anywhere else).

Greengrass is a service that stands out by constructing ARNs differently than all others. It stands out because the service name “greengrass” is both parts of the ARN. Here is an example of one such ARN:
arn:${Partition}:greengrass:${Region}:${Account}:/greengrass/bulk/deployments/${BulkDeploymentId}

The execute-api-general resource from the API Gateway service has a lot of variance in its ARN. In fact, the entire Resource Path from the ARN is entirely variable:
arn:${Partition}:execute-api:${Region}:${Account}:${ApiId}/${Stage}/${Method}/${ApiSpecificResourcePath}

While that may not be complex on their own, it is important to point out that construction of ARNs can vary from service to service, so it’s important to know how each service uses ARNs.

Conclusion

Hopefully this guide has shed some light on the breadth, depth, flexibility, and overall complexity of AWS IAM. AWS IAM provides many different ways to define who and what can access your cloud resources. Request a demo of DivvyCloud by Rapid7’s Cloud IAM Governance module or read our white paper, Gaining Control Over Cloud IAM Chaos, to better understand the access between your cloud principals and resources.

About the Author

James Martin has nine years of experience working with Amazon Web Services as both a practitioner and leader in organizations of all shapes and sizes. Currently, he is a Senior Engineering Manager for Rapid7’s Cloud Security Practice.

Similar resources that you may also enjoy

Blog

The Future of Cloud-Native Security is Here!

The 2020 Cloud Security Executive Summit, which focused on… 

View all Blog Posts
Blog

Feature Release 20.6

We are pleased to announce DivvyCloud by Rapid7 release… 

View all Blog Posts