Terraform
Workload Identity
Dynamic Provider Credentials are powered by Terraform Workload Identity, which allows HCP Terraform to present information about a Terraform workload to an external system – like its workspace, organization, or whether it’s a plan or apply – and allows other external systems to verify that the information is accurate.
You can think of it like an identity card for your Terraform runs: one that comes with a way for another system to easily verify whether the card is genuine. If the other system can confirm that the ID card is legitimate, it can trust the information the card contains and use it to decide whether to let that Terraform workload in the door.
The “identity card” in this analogy is a workload identity token: a JSON Web Token (JWT) that contains information about a plan or apply, is signed by HCP Terraform’s private key, and expires at the end of the plan or apply timeout. Other systems can use HCP Terraform’s public key to verify that a token that claims to be from HCP Terraform is genuine and has not been tampered with.
This workflow is built on the OpenID Connect protocol, a trusted standard for verifying identity across different systems.
Token Specification
Workload identity tokens contain useful metadata in their payloads, known as claims. This is the equivalent of the name and date of birth on an identity card. Once a cloud platform verifies a token using HCP Terraform’s public key, it can look at the claims in the identity token to either match it to the correct permissions or reject it.
You don’t need to understand the full token specification and what every claim means in order to use dynamic credentials, but it’s useful for debugging.
Token Structure
The following example shows a decoded HCP Terraform workload identity token:
Header
{
"typ": "JWT",
"alg": "RS256",
"kid": "j-fFp9evPJAzV5I2_58HY5UvdCK6Q4LLB1rnPOUfQAk"
}
Payload
{
"jti": "1192426d-b525-4fde-9d42-f238be437bbd",
"iss": "https://app.terraform.io",
"aud": "my-example-audience",
"iat": 1650486122,
"nbf": 1650486117,
"exp": 1650486422,
"sub": "organization:my-org:project:Default Project:workspace:my-workspace:run_phase:apply",
"terraform_organization_id": "org-GRNbCjYNpBB6NEH9",
"terraform_organization_name": "my-org",
"terraform_project_id": "prj-vegSA59s1XPwMr2t",
"terraform_project_name": "Default Project",
"terraform_workspace_id": "ws-mbsd5E3Ktt5Rg2Xm",
"terraform_workspace_name": "my-workspace",
"terraform_full_workspace": "organization:my-org:project:Default Project:workspace:my-workspace",
"terraform_run_id": "run-X3n1AUXNGWbfECsJ",
"terraform_run_phase": "apply"
}
This payload includes a number of standard claims defined in the OIDC spec as well as a number of custom claims for further customization.
Standard Claims
Claim | Value |
---|---|
jti (JWT ID) | A unique identifier for each JWT. |
iss (issuer) | Full URL of HCP Terraform or the Terraform Enterprise instance which signed the JWT. |
iat (issued at) | Unix Timestamp when the JWT was issued. May be required by certain relying parties. |
nbf (not before) | Unix Timestamp when the JWT can start being used. This will be the same as iat for tokens issued by HCP Terraform, but may be required by certain relying parties. |
aud (audience) | Intended audience for the JWT. For example, aws.workload.identity for AWS. This can be customized. |
exp (expiration) | Unix Timestamp based on the timeout of the run phase that it was issued for. This will follow the plan and apply timeouts set at the organization and site admin level. |
sub (subject) | Fully qualified path to a workspace, followed by the run phase. For example: organization:my-organization-name:project:Default Project:workspace:my-workspace-name:run_phase:apply |
Custom Claims
Claim | Value |
---|---|
terraform_organization_id (organization ID) | ID of the HCP Terraform organization performing the run. |
terraform_organization_name (organization name) | Human-readable name of the HCP Terraform organization performing the run. Note that organization names can be changed. |
terraform_project_id (project ID) | ID of the HCP Terraform project performing the run. |
terraform_project_name (project name) | Human-readable name of the HCP Terraform project performing the run. Note that project names can be changed. The default project name is Default Project . |
terraform_workspace_id (workspace ID) | ID of the HCP Terraform workspace performing the run. |
terraform_workspace_name (workspace name) | Human-readable name of the HCP Terraform workspace performing the run. Note that workspace names can be changed. |
terraform_full_workspace (fully qualified workspace) | Fully qualified path to a workspace. For example: organization:my-organization-name:project:my-project-name:workspace:my-workspace-name |
terraform_run_id (run ID) | ID of the run that the token was generated for. This is intended to aid in traceability and logging. |
terraform_run_phase (run phase) | The phase of the run this token was issued for. For example, plan or apply |
Configuring Trust with your Cloud Platform
When configuring the trust relationship between HCP Terraform and your cloud platform, you’ll set up conditions to validate the contents of the identity token provided by HCP Terraform against your roles and policies.
At the minimum, you should match against the following claims:
aud
- the audience value of the token. This ensures that, for example, a workload identity token intended for AWS can’t be used to authenticate to Vault.sub
- the subject value, which includes the organization and workspace performing the run. If you don’t match against at least the organization name, any organization or workspace on HCP Terraform will be able to access your cloud resources!
You can match on as many claims as you want, depending on your cloud platform.