Managing User Permissions in Terraform with Role-Based Access Control (RBAC)

Managing User Permissions in Terraform with Role-Based Access Control (RBAC) blog post

Managing User Permissions in Terraform with Role-Based Access Control (RBAC)

When you have an infrastructure running applications in production using Terraform’s IaC setup, any breaking change to the platforms impacts business and is considered a Priority 1 incident. To mitigate this, teams ensure that less experienced infrastructure engineers or application teams do not directly change the platform. This is done using RBAC, which restricts them from running terraform apply, and only an experienced DevOps engineer can merge such changes, ensuring that there are no breaking changes pushed to prod.

This blog post will focus on RBAC (Role-Based Access Control), how RBAC is applied in Terraform, use cases, and various access control methods that help keep your infrastructure secure and compliant. Additionally, we will look at how RBAC can be used in Terraform with advanced tools such as Terrateam.

Sign up for Terrateam to explore its advanced infrastructure management capabilities.

What is RBAC (Role-Based Access Control)?

In mid-to-large organizations, security is one of the most important areas of focus for infrastructure teams. Since there are so many team members who are working in different roles, teams, and departments, it is vital to ensure that your infrastructure is protected with restricted access controls.

One such methodology that helps teams establish security measures to protect their infrastructure from being accessed by unauthorized members is Role-Based Access Control. RBAC controls individual access, what operations they can perform, and under what conditions these permissions might come into play.

You might be part of an infrastructure team that uses Terraform to deploy infrastructure. Now, you want to ensure that the deployments are done by the responsible DevOps engineers rather than frontend or backend engineers who are less experienced with infrastructure code.

This requires implementing strict access controls at the deployment level, which means you must restrict access to those who can run Terraform commands. For example, there is an application team with its own infra team using a platform to deploy its infrastructure, and you, as part of the platform team, would like to allow them to propose and review their changes only in a branch or PR (Pull Request).

Without RBAC in place, the application team might directly run Terraform operations, such as terraform apply or terraform destroy, and make changes to the production infrastructure. If the change is associated with IP permissions to the EKS cluster, this might lead to a data breach or security issue.

If you have RBAC in place, which allows the application infra team to only run validate, init, and plan, to see what changes will be pushed to the infrastructure. Once they run the terraform plan command as part of their workflow when they raise a PR, they can validate what changes their commit will make in the current infrastructure. Since you do not want them to make any changes that might affect your whole infrastructure unless they are reviewed properly by the platform team, they can raise a PR, see the changes, and then wait for the platform team to merge and apply them. Even if they try to run apply, they will get an output with unauthorized user access or review required by the platform team, signaling that they do not have the required permissions.

Let’s look at a representation of one such scenario.

The infographic represents how RBAC assigns specific permissions to different roles.

  • Auditors (application developers or junior infra dev) can only review configurations.
  • Infrastructure developers can propose and apply changes to the infrastructure.
  • Infrastructure leads have full control, including the ability to plan, apply, and destroy resources.

This approach ensures access is limited to each person’s role, helping maintain a secure and stable infrastructure.

RBAC is just one of the many ways you can implement access control. Let’s see some other ways it can be implemented.

What are the different types of Access Control?

While implementing access controls, it is important to understand how they relate to your use case. Each one of them has its own pros and cons. Depending on your level of implementation and team size, you might want to consider one over the other or a mix of them. Now, let’s discuss some of these access control methodologies:

Discretionary Access Control (DAC)

DACs are very specific to the owners, where the infrastructure owner or creator controls the access permissions for other users. Here, each repository or environment owner independently manages the permissions, providing more flexibility for individual Terraform code. For example, if your team does not want to rely on the central Devops team to provide permission to one of the Terraform repositories to the junior infra dev who just joined the team since it is used to manage secrets, the Tech Lead or DevSecOps Lead can manage the access permissions to the repositories within their organization. Or else, there’s a repository that is shared among several teams to allow application teams to control their own deployed infrastructure. It can be simply managed by the platform team Architect, who can quickly provide access to the shared resources or files, allowing them to run Terraform operations, such as plan, apply or destroy.

Mandatory Access Control (MAC)

MACs are used to enforce strict and centrally managed access permissions. In this case, there’s a CISO or DevSecOps team that is solely responsible for setting and enforcing access permissions across environments. This ensures the environment is highly secure, where multiple team members cannot modify permissions. These permissions allow team members, developers, or infrastructure engineers to perform certain Terraform actions in the environment based on what permissions they have, such as to plan, apply, or destroy. It aligns well with highly sensitive and compliance-driven industries, such as finance, healthcare, and government. For example, for the healthcare organization to protect the patient’s data and reports, it is important to ensure that only a restricted set of people has permission to read or write any changes to the production. A dedicated individual or team responsible for the permissions is helpful in such scenarios, as they are the only ones implementing access restrictions, reducing the possibility of data leaks, compliance violations, and security breaches.

Attribute-Based Access Control (ABAC)

ABAC allows you to implement much more granular, context-aware permissions based on a range of attributes, such as user properties (team, environment, or job role), and the environment in which they want to make changes. This type of access control dynamically evaluates these attributes to determine permissions, allowing for flexible access that adapts to changing conditions. For example, an ABAC policy might permit access if a user is part of the external or internal team. This approach aligns well with dynamic and multi-tenant environments, where ABAC can utilize values, such as their Git ID, organization, or team name, to manage access at scale. Now, team members whose ID is external can run only the terraform plan and terraform apply in the dev environment, while the ones with internal IDs can plan, apply, and destroy in production. By automating permissions, ABAC minimizes the need to manually identify an individual access permission, offering efficient and scalable access management.

Role-Based Access Control (RBAC)

RBAC structures access control by assigning permissions to predefined roles based on job functions or responsibilities. In this approach, each user plays a certain role in their team, like “DevOps” or “Developer”. Each has a specific set of permissions tailored to their responsibilities, streamlining access management. For example, an Infra Engineer in a team might allow full access across environments with permissions to plan, deploy, and destroy the infrastructure as per the needs, while a Developer might be limited to read-only access to the production environment with terraform plan and terraform state show permissions.

RBAC is well-suited for team-based environments, especially in enterprise settings where predictable, role-based access is essential. In a DevOps context, for example, it’s common to grant deployment permissions to DevOps engineers while restricting production access for developers, ensuring a clear separation of duties based on role. This approach helps simplify permission management, especially in cloud deployments where any misconfigured deployment can cause application downtime or infrastructure outage.

Use Cases for RBAC in Terraform

As we explore the various applications of RBAC (Role-Based Access Control) in Terraform, let’s see how it benefits organizations:

  • Development and Production Environment Segmentation: Many tech companies use RBAC to clearly define access between development and production environments. For instance, developers can have full access in development but only read-only access in production, allowing them to review and troubleshoot configurations without making changes. This approach minimizes risk while enabling efficient issue resolution.

  • Checks and Balances in Regulated Industries: Companies in regulated sectors, such as financial services, use RBAC to establish clear roles and responsibilities for infrastructure access. This approach helps ensure that different teams can oversee infrastructure configurations and validate adherence to industry standards and internal policies without risking unauthorized changes.

  • Ensuring Compliance with Access Policies: Organizations that need to comply with regulations, such as GDPR or ISO standards, use RBAC to enforce strict access controls. This ensures that only authorized individuals can access or modify specific resources, helping to meet compliance requirements related to data protection and operational security. By defining roles with precise permissions, teams can demonstrate adherence to access control policies during audits, minimizing the risk of violations and potential fines.

These real-world scenarios illustrate how RBAC helps organizations manage access securely, maintain control over critical infrastructure, and meet governance and compliance requirements.

Managing RBAC in GitHub Actions with OPA

In this section, we’ll provide a step-by-step approach to implementing RBAC policies within GitHub Actions. Using OPA and Conftest, we’ll enforce RBAC to run the terraform plan command, allowing only authorized users to initiate the plan.

Firstly, we will define the Rego policy, which specifies which users can perform the Terraform plan action. This policy will be saved as policy/github/rbac.rego:

package github.rbac
default allow_plan = false
allowed_users = {"Cipher-08"}
allow_plan {
input.github.actor == user
allowed_users[user]
}

In this policy, allow_plan is set to true only if the GitHub user (github.actor) is part of the allowed_users list. This policy ensures that only specific, pre-approved users can initiate a terraform plan.

To make sure that the workflow can access necessary information, such as user data and permissions, you’ll need to configure a GitHub token (${{ secrets.GITHUB_TOKEN }}). This token must have permission to read user data and interact with the GitHub API for validation. As a security practice, it should be saved securely in the repository’s setting under Secrets.

Next, we create a GitHub Actions workflow file, .github/workflows/terraform-plan.yml, which runs a series of steps to validate the user’s permissions before proceeding with Terraform commands. Here’s the workflow setup:

name: Terraform Plan
on:
pull_request:
branches:
- main
jobs:
plan:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Install Conftest
run: |
wget https://github.com/open-policy-agent/conftest/releases/download/v0.34.0/conftest_0.34.0_Linux_x86_64.tar.gz
tar xzf conftest_0.34.0_Linux_x86_64.tar.gz
sudo mv conftest /usr/local/bin
- name: Install OPA
run: |
wget https://openpolicyagent.org/downloads/v0.40.0/opa_linux_amd64_static
chmod +x opa_linux_amd64_static
sudo mv opa_linux_amd64_static /usr/local/bin/opa
- name: Create Workflow Context File
run: |
echo '{"github": {"actor": "'${{ github.actor }}'"}}' > workflow_context.json
- name: Run OPA Policy Check
id: opa_check
run: |
result=$(opa eval --format=json --input workflow_context.json --data policy/github/rbac.rego "data.github.rbac.allow_plan")
allowed=$(echo $result | jq -r '.result[0].expressions[0].value')
if [ "$allowed" != "true" ]; then
echo "User is not authorized to run Terraform Plan."
exit 1
fi
- name: Run Conftest Policy Check
run: conftest test workflow_context.json --policy policy/github/rbac.rego
- name: Terraform Init and Plan
if: success()
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
run: |
terraform init
terraform plan

Let’s break down the steps in the above GitHub Actions workflow file:

  • Checkout Code: The workflow begins by checking out the repository code so that it has access to the necessary policy and configuration files in the repository.
  • Install Conftest and OPA: Conftest and OPA are installed to enable policy validation. Conftest will be used to validate our Rego policy while OPA evaluates the RBAC rules.
  • Create Workflow Context File: This step generates a JSON file called workflow_context.json, which includes information about the GitHub user (github.actor) initiating the pull request. This data is essential for the policy to determine if the user is authorized to perform a certain action or not.
  • Run OPA Policy Check: Using OPA, the workflow evaluates the rbac.rego policy against the context file to check if the user has permission to run the terraform plan. If the user is not authorized, the workflow exits with an error, and Terraform commands are not executed.
  • Run Conftest Policy Check: Conftest is used to test the policy against the workflow context, providing an additional layer of validation.
  • Terraform Init and Plan: If both OPA and Conftest checks pass, the workflow proceeds to initialize Terraform and execute the terraform plan command.

Next, create a new branch in your repository. In this branch, add a new file named main.tf, where you’ll write your Terraform configuration.

Once you’ve added your configuration, push the changes to your branch. Go to the ‘Actions’ tab in GitHub, where you’ll see the workflow running. The workflow will perform all the checks, including validating the user’s permissions using the OPA and Conftest policy checks. If the user specified in rbac.rego is authorized, the workflow will proceed, and the terraform plan will run successfully.

Now, to test unauthorized access, modify the rbac.rego file to change the allowed_users list, replacing the current user with a different username that isn’t authorized. Commit and push this change to the branch. Now, when the workflow runs again, it will fail the OPA policy check, showing an error message that the user is not authorized to run the terraform plan. As a result, the workflow will exit at this point, preventing the Terraform commands from running.

This setup demonstrates how you can use GitHub Actions, OPA, and Conftest to enforce RBAC policies, such as only authorized individuals can run the terraform plan command to view changes made to the infrastructure. With Terraform access control, you ensure that only pre-approved users can execute Terraform commands, securing infrastructure changes.

When larger teams are working with bigger and more complex projects, RBAC for Terraform is vital in ensuring that granular access restrictions are in place within the team while working with Terraform commands. Without an OPA policy, it becomes difficult to enforce such constraints, where you want to control who can view the Terraform state or deploy changes to the infrastructure. You can integrate OPA policies to enhance RBAC by validating specific users, roles, and permissions. This helps in achieving effective access control, which often involves intricate configurations that consume time and resources. Teams might not want to spend so much of their bandwidth on figuring out how to do this and ensuring it works as expected. With tools such as Terrateam, teams can easily onboard themselves and integrate RBAC access control in their workflows for Terraform actions.

Making RBAC Easier with Terrateam

Now, let’s see how Terrateam can simplify the RBAC setup for Terraform. Unlike the detailed setup required with GitHub Actions and OPA, where you need to define multiple configurations and permissions, Terrateam allows you to set up access controls with a minimal number of steps. Here, teams do not need to write complex logic, which saves them time, and workforce. Additionally, it provides a granular access control with a single config.yml file. This file filters the users to see if they have permission to run certain Terraform operations when they raise a PR to deploy any changes to the infrastructure repo. As an organization, teams can also control the number of approvals required to approve any changes before they are deployed in production.

You can easily set up Terrateam in your GitHub. Get started.

Now, with Terrateam, you can manage permissions directly in a configuration file, .terrateam/config.yml, which means you don’t need to rely on complex workflows. For example, instead of configuring checks with OPA and Conftest, you only need to define access policies like so:

access_control:
enabled: true
policies:
- tag_query: ''
plan: ['*']
apply: ['user:nitinteotia6548']

In this setup:

  • All users are allowed to run terraform plan command to view the proposed changes.
  • The permission to run the terraform apply is restricted to a specific user, making sure that only authorized individuals can execute infrastructure changes.

To see this in action, start by creating a new branch in your repository and add a main.tf file with your Terraform configuration. Once that’s done, open a pull request (PR) in your repository. Terrateam will automatically handle the permissions based on the access control setup.

When a user initiates terrateam plan, it will successfully execute, allowing them to see the planned changes.

However, if the same user tries to run the terrateam apply action, the operation will fail unless they are authorized.

In this case, only nitinteotia6548 has the required permission to apply changes. When nitinteotia6548 runs terrateam apply, the changes are deployed to the infrastructure.

In addition to setting permissions, Terrateam includes apply requirements to enforce checks before any apply operation is executed. For example, you can mandate a minimum number of approvals or ensure that all status checks have passed. This prevents any inexperienced developer from pushing any breaking changes to the infrastructure. Here’s how to configure it:

apply_requirements:
checks:
approved:
enabled: true
count: 2
merge_conflicts:
enabled: true
status_checks:
enabled: true
ignore_matching:
- "ci/.*"

This code enforces these conditions:

  • A minimum of 2 approvals are required before applying changes.
  • There should not be any merge conflicts.
  • All status checks must be successful before the operation proceeds.

These requirements provide additional safeguards, making sure that any infrastructure changes are made to the infrastructure and that they go through proper review before there’s any production issue or incident.

We saw that implementing access control without Terrateam, requires a lot of effort and is confusing when you need to manage granular permissions for each user or role. You can leverage Terrateam’s configuration file to implement RBAC, which allows for straightforward, granular control over who can run specific Terraform operations like plan and apply. By simply adding permissions in the .terrateam/config.yml file, you could easily assign roles and define access for specific users. There’s no need for lengthy workflows or complicated policy checks; Terrateam handles it all in an intuitive way.

Explore more exciting RBAC features with Terrateam.

Conclusion

In this blog, we explored how Role-Based Access Control (RBAC) helps secure infrastructure by controlling who can make changes to your infrastructure. We looked at how you can use OPA and conftest to implement RBAC in Terraform with your GitHub Actions workflows. As an organization, you can simplify the process of setting RBAC in Terraform using Terrateam by letting you set permissions easily with a single config file.

Infrastructure as Code. Optimized.

Ready to get started?

Experience powerful infrastructure orchestration, seamlessly integrated with GitHub.