Using static, long-term credentials to access AWS Cloud through Terraform Cloud is not considered a best practice. Instead, let’s explore a better solution: leveraging short-lived, dynamic credentials for enhanced security.
What we have:
Currently, the Terraform Cloud Workspace is configured using an Access Key and a Secret Access Key.
You can use HCP Terraform’s native OpenID Connect integration with Vault to get dynamic credentials for the Vault provider in your HCP Terraform runs. Configuring the integration requires the following steps:
- Configure Vault: Set up a trust configuration between Vault and HCP Terraform. Then, you must create Vault roles and policies for your HCP Terraform workspaces.
- Configure AWS secrets engine: Enable and configure AWS secrets engine.
- Configure HCP Terraform: Add environment variables to the HCP Terraform workspaces where you want to use Dynamic Credentials.
Once you complete the setup, HCP Terraform automatically authenticates to Vault during each run. The Vault provider authentication is valid for the length of the plan or apply. Vault does not revoke authentication until the run is complete.
Configure Vault
Export variables to access Vault Dedicated:
export VAULT_TOKEN=hvs.***
export VAULT_ADDR=https://vault-cluster-public-vault-***.z1.hashicorp.cloud:8200
export VAULT_NAMESPACE=admin
Enable the JWT Auth Backend
Run the following command to enable the JWT auth backend in Vault:
vault auth enable jwt
Configure Trust with HCP Terraform
You must configure Vault to trust HCP Terraform’s identity tokens and verify them using HCP Terraform’s public key. The following command configures the jwt
auth backend in Vault to trust HCP Terraform as an OIDC identity provider:
vault write auth/jwt/config \
oidc_discovery_url="https://app.terraform.io" \
bound_issuer="https://app.terraform.io"
The oidc_discovery_url
and bound_issuer
should both be the root address of HCP Terraform, including the scheme and without a trailing slash.
Create a Vault Policy
You must create a Vault policy that controls what paths and secrets your HCP Terraform workspace can access in Vault. Create a file called tfc-policy.hcl with the following content:
# Allow tokens to query themselves
path "auth/token/lookup-self" {
capabilities = ["read"]
}
# Allow tokens to renew themselves
path "auth/token/renew-self" {
capabilities = ["update"]
}
# Allow tokens to revoke themselves
path "auth/token/revoke-self" {
capabilities = ["update"]
}
# Configure the actual secrets the token should have access to
path "secret/*" {
capabilities = ["read"]
}
#It is needed to access our role created below
path "aws/creds/my-role" {
capabilities = ["read"]
}
Then, create the policy in Vault:
vault policy write tfc-policy tfc-policy.hcl
Create a JWT Auth Role
Create a Vault role that HCP Terraform can use when authenticating to Vault.
Vault offers a lot of flexibility in determining how to map roles and permissions in Vault to workspaces in HCP Terraform. You can have one role for each workspace, one role for a group of workspaces, or one role for all workspaces in an organization. You can also configure different roles for the plan and apply phases of a run.
Note: If you set your user_claim
to be per workspace, then Vault ties the entity it creates to that workspace’s name. If you rename the workspace tied to your user_claim
, Vault will create an additional identity object. To avoid this, update the alias name in Vault to your new workspace name before you update it in HCP Terraform.
The following example creates a role called tfc-role
. The role is mapped to a single workspace and HCP Terraform can use it for both plan and apply runs.
Create a file called vault-jwt-auth-role.json
with the following content:
{
"policies": ["tfc-policy"],
"bound_audiences": ["vault.workload.identity"],
"bound_claims_type": "glob",
"bound_claims": {
"sub":
"organization:VovandosDevelopment:project:Main_Development:workspace:hcp-terraform-ec2:run_phase:*"
},
"user_claim": "terraform_full_workspace",
"role_type": "jwt",
"token_ttl": "20m"
}
Then run the following command to create a role named tfc-role
with this configuration in Vault:
vault write auth/jwt/role/tfc-role @vault-jwt-auth-role.json
Token TTLs
We recommend setting token_ttl to a relatively short value. HCP Terraform can renew the token periodically until the plan or apply is complete, then revoke it to prevent it from being used further.
Configure AWS secrets engine
The AWS secrets engine generates AWS access credentials dynamically based on IAM policies.
Setup
1. Enable the AWS secrets engine:
$ vault secrets enable aws
Success! Enabled the aws secrets engine at: aws/
By default, the secrets engine will mount at the name of the engine. To enable the secrets engine at a different path, use the -path
argument.
2. Configure the credentials that Vault uses to communicate with AWS to generate the IAM credentials:
vault write aws/config/root \
access_key=*** \
secret_key=*** \
region=us-west-2
Internally, Vault will connect to AWS using these credentials which were created previously in AWS:
Configure HCP Terraform
Workspace variables should be updated from static AWS access keys, as demonstrated earlier in the post, to specific environment variables.
When a Workspace Run is initiated, Terraform Cloud interacts with Vault, which then generates temporary credentials valid for the duration of the current Run.
Conclusion
By integrating Terraform Cloud with Vault to generate short-lived, dynamic credentials, you significantly enhance the security and flexibility of your infrastructure workflows. This approach eliminates the risks associated with static, long-term access keys while ensuring that your Terraform runs are both secure and efficient.
Dynamic credentials not only align with best practices but also simplify credential management, reducing the likelihood of unauthorized access or credential leakage. Adopting this setup helps create a more robust and automated infrastructure-as-code pipeline, empowering teams to focus on innovation instead of security gaps.
Leave a Reply