Understanding AWS IAM: Policies
Tags: aws, iam, cloud, security
Published: 2023-05-23 12:07:30

The previous installment in this series talked about basic permissions. Now something is needed to bring these permissions into a usable form: policies. IAM policies are essentially where the policy JSON giving (or denying) permissions goes to. While there are more advanced ones, this guide will deal with the four ones that most users will deal with.

## Main Policy Types

The main policy type that most users will deal with are:

- Managed Policies: AWS managed for common use cases
- Customer Policies: Custom policies that can be shared 
- Inline Policies: Policies bound to a single IAM entity
- Resource Policies: Policies set on the resource level to manage access

### Managed Policies

Managed policies are handled via AWS. Permissions can be somewhat more restrictive than just giving admin access but still not as strict as permissions tailored to specific job roles. These are meant to be general use, which isn't possible if they have to take into consideration every customer's permissions needs. Consider this similar to having ISO or HIPAA standards apply to a datacenter facility.

As an example, this is the [AmazonEC2ContainerRegistryReadOnly managed policy](https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AmazonEC2ContainerRegistryReadOnly.html) at time of writing:

```json
{
  "Version" : "2012-10-17",
  "Statement" : [
    {
      "Effect" : "Allow",
      "Action" : [
        "ecr:GetAuthorizationToken",
        "ecr:BatchCheckLayerAvailability",
        "ecr:GetDownloadUrlForLayer",
        "ecr:GetRepositoryPolicy",
        "ecr:DescribeRepositories",
        "ecr:ListImages",
        "ecr:DescribeImages",
        "ecr:BatchGetImage",
        "ecr:GetLifecyclePolicy",
        "ecr:GetLifecyclePolicyPreview",
        "ecr:ListTagsForResource",
        "ecr:DescribeImageScanFindings"
      ],
      "Resource" : "*"
    }
  ]
}
```

For users only needing to read container images from ECR (CI writes container images, user reads) this will do a decent enough job. What's mainly the issue is that the "Resource" is not restricted. For a developer playground this may not be a big deal, but it might matter for compliance heavy accounts. It's also important to note that due to AWS managing these policies, how they work can change (they generally give notice on health dashboard and blogs). For example, the SSM managed policy [used to give access to S3](https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AmazonEC2RoleforSSM.html). [Now it's very minimal](https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AmazonSSMManagedInstanceCore.html) and the user is tasked with providing S3 access outside of this.

### Customer Policies

Customer policies are instead handled by the AWS customer themselves (be it an individual or organization). This is a more best practice way of handling permissions as it allows the company with complete knowledge of what their employees should be doing to create an explicit set of permissions. Customer policies can also be broken up into modular parts and then combined later. This is similar to a company requiring a specific ID format to access all facilities. 

As an example, take the above AWS managed policy. After checking it over there were several permissions someone simply download an image didn't need, and the developer only needs to access a repository specifically for their project. After some changes were made:

```json
{
  "Version" : "2012-10-17",
  "Statement" : [
    {
      "Effect" : "Allow",
      "Action" : [
        "ecr:GetAuthorizationToken",
        "ecr:BatchCheckLayerAvailability",
        "ecr:GetDownloadUrlForLayer",
        "ecr:ListImages",
        "ecr:DescribeImages",
        "ecr:BatchGetImage",
      ],
      "Resource" : "arn:aws:ecr:us-west-2:012345678910:repository/developer_project"
    }
  ]
}
```

Not only does this lower the amount of permissions, but it also tags it against a specific resource giving more fine grained control.

### Inline Policies

Inline policies are a 1:1 mapping of permissions to an IAM entity. These are generally meant for cases which are too specific to apply to a modular style customer policy. If you find yourself giving permissions inline more than once it might be better to pull some or all of it into a customer policy and re-use that. An example of an inline policy would be if a datacenter was used for visitor purposes which had a lounge area and visitor escort policy.

There really isn't a specific example to give here as inline policies have much the same layout as customer policies. The main difference usage wise is that an inline policy is strictly mapped to the IAM identity that holds it. If the identity is deleted the policy is gone. This can be useful in situations where you don't want a policy being re-used for compliance purposes. In general though customer policies are more modular and help reduce operations burden.

### Resource Policies

Resource policies are applied to an AWS resource instead of an IAM entity. For example, S3 buckets have their own policies. It's similar to needing login information for a specific server in a data center. While you may have enough access to get physically to the server, you won't be able to log in to the system unless you authenticate to it properly. Server racks could also have locks on them that only the appropriate authorized employee with the key can access.

These policies are extremely useful when specific resources are higher risk than normal usage. For example, an S3 bucket containing personally identifiable information or health care data. Trying to manage that through normal IAM entities is error prone, so it's more reliable to do it at the resource level. As an example:

```json
{
    "Version": "2012-10-17",
    "Statement": [
        {,
            "Effect": "Allow",
            "Principal": "*",
            "Action": [
                "s3:GetObject"
             ],
            "Resource": "arn:aws:s3:::developer_bucket/*",
            "Condition": {
                "IpAddress": {
                    "aws:SourceIp": [
                        "172.16.0.0/16"
                    ]
                }
            }
        }
    ]
}
```

This restricts an s3 call to an IP address, say a VPN endpoint. The result would be ensuring that a user is on a corporate VPN before accessing the bucket. AWS documentation has [useful examples](https://docs.aws.amazon.com/AmazonS3/latest/userguide/example-bucket-policies.html) for many services which have resource level permissions if you need help with a specific use case.

## IAM Access Analyzer Policy Generation

For those starting out it can be difficult to know exactly what to restrict. Thankfully AWS created a tool called IAM Access Analyzer which can be used to [generate policy JSON](https://docs.aws.amazon.com/IAM/latest/UserGuide/access-analyzer-policy-generation.html) based on CloudTrail log data. You can start out with an AWS managed policy and then use the policy generator feature to figure out how to fine grain adjust permissions. Note that this requires [CloudTrail logging](https://docs.aws.amazon.com/awscloudtrail/latest/userguide/cloudtrail-user-guide.html) to be enabled which has its own set of costs. 

## Conclusion

AWS policies are the central way on how permissions are mapped to IAM entities and select AWS resources. Compliance, threat models, maintainability, and user needs should be taken into consideration when deciding which policy type to use. Be sure to check out the AWS documentation for services as it often contains standard use case policies for various services. IAM Access Analyzer can also be used to give an idea on how services are actually be accessed for a specific account.