Integrating Yor with AWS IAM for better access control

Managing who has access to what and in what context within your cloud environment is an age-old challenge that AWS Identity and Access Management (IAM) tries to solve. You can use roles to delegate access to users who don’t normally have access to your AWS resources.

But access by role is not always the best way to manage permissions and access across your cloud environment. Attributes (or tags) can make that easier by providing context such as environment, team, data classification, and others. 

Managing access by tag can be a challenge to maintain—especially when infrastructure as code (IaC) is in the mix. In order to make attribute-based access control (ABAC) work, tags need to be added consistently and enforced in both build-time and runtime.

In this blog, we will show you how to automate this process using IAM policies and Yor auto-tagging. Using tag-based conditions on IAM policies can better determine who can access what based on the attributes users and resources have in their tags. Shifting the permission granting process to version control and CI processes creates transparency and collaboration capabilities with regard to access management. 

We’ll use an example below to: 

  • Define who on your team should have access to top-secret data
  • Define what resources are classified as top secret
  • Enforce that only the  members can access those resources

Using IAM for attribute-based access control (ABAC)

AWS IAM policies are built of an array of statements, where each statement has elements such as:

  • Action. Generally represents CRUD operations.
  • Resource. Represents the accessed asset.
  • Principal. Represents the person making the request.
  • Effect. Determines whether the action is “allowed” or “denied.”
  • Condition. Determines if the action takes effect under specific circumstances.

With AWS IAM conditions, you can control what the principal (i.e., the person making the request) is allowed to do based on the tags that are attached to that person’s IAM user or role.

For example, you can write an IAM policy to “allow” an action only under one condition: the tags team_ownership and classification on the principal and the resource being accessed must match one another.

{
    "Version": "2012-10-17",
    "Statement": {
        "Effect": "Allow",
        "Action": [
            "ec2:startInstances",
            "ec2:stopInstances"
        ],
        "Resource": "*",
        "Condition":
{"StringEquals":
{"ec2:ResourceTag/team_ownership": "${aws:PrincipalTag/team_ownership}"}
},
{"StringEquals":
{"ec2:ResourceTag/environment": "${aws:PrincipalTag/environment}"}
}
    }
}

This policy allows us to segregate resources between different teams and classifications, and grant more autonomy to each team to act on resources they own.

For example, if the application development team (named “SRE”) is mapped to the team_ownership tag, they can only start and stop instances on EC2 resources that have the tag team_ownership=”SRE” team and that belong to the same classification as the user (e.g.,  public, secret or top secret classifications) in the classification tag.

Enforcing resource tagging upon creation

Using conditions, you can also force users to tag resources upon creation. Inspired by an example in AWS docs, we can create the following IAM policy that requires the tags classification and team_ownership to exist for the instance to run:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
          "ec2:RunInstances"
      ],
      "Resource": [
          "arn:aws:ec2:region:account:instance/*"
      ],
      "Condition": {
          "ForAllValues:StringEquals": {
              "aws:TagKeys": ["classification","team_ownership"]
          }
       }
    },
    {
      "Effect": "Allow",
      "Action": [
          "ec2:CreateTags"
      ],
      "Resource": "arn:aws:ec2:region:account:*/*",
      "Condition": {
          "StringEquals": {
              "ec2:CreateAction" : "RunInstances"
          }
       }
    }
  ]
}

Enabling ABAC permissions using automated tagging

Enforcing permission limitations on the running production environment is important for access control. We can shorten discovery and collaboration by managing attribute-based access control (ABAC) on our infrastructure code. ABAC will only work if we use tags consistently on our resources and users that are managed in Terraform, CloudFormation or other IaC frameworks.

For example, have a look at the following Yor configuration…

name: Validate IaCname: Validate IaC

on:
 # Triggers the workflow on push or pull request events but only for the main branch
 push:
   branches: [ main, master ]
 pull_request:
   branches: [ main, master ]

jobs:
 yor_checkov:
   runs-on: ubuntu-latest
   steps:
     - uses: actions/checkout@v2
       name: Checkout repo
       with:
         fetch-depth: 0
         ref: ${{ github.head_ref }}
     - name: Run yor action
       uses: bridgecrewio/yor-action@main

       with:
         config_file: tag_groups.yaml
       env:
         DATA_CLASSIFICATION: “top secret”

Yor configuration files consists of a list of tag groups, where each tag group can contain tags with default values, conditional values, or values that rely on environment variables.

For example, we can group team members into their respective `team_ownership` groups and set the `classification` from the value injected in our CI pipeline previously:

tag_groups:
  - name: ownership # map infrastructure to owner or owning team
    tags:
      - name: classification
        value:
          default: ${env:DATA_CLASSIFICATION} # data classification of the deployed infrastructure
      - name: team_ownership
        value:
          default: application_engineering # application_engineering are the default owning team of cloud resources
          matches:
            - security_engineering:
                tags:
                  git_modifiers: # security engineering team member's github handles
                    - rotemavni
                    - tronxd
                    - nimrodkor
            - platform_engineering:
                tags:
                  git_modifiers: # platform engineering team member's github handles
                    - milkana
                    - nofar
            - sre:
                tags:
                  git_modifiers:
                    - schosterbarak

Resources like the EC2 in the example mentioned above can have the Yor tags, including team_ownership, persisted to its Terraform or CloudFormation code:

modify E2 instance

Yor has persisted permissions in IaC. We now know which user would have access to what resources and version control it in our GitHub repository – enabling transparency, collaboration, tests, and approval processes, just like any other configuration in the cloud. 

Now that we have runtime tag enforcement, build-time auto-tagging, and an IAM policy that controls access, we can programmatically use ABAC.

To get started with Yor, check out our Yor docs and join our Codified Security Slack channel.

If you found this post helpful, you’ll probably like these other Yor blog posts: