HCP Terraform Vault-backed dynamic credentials for the AWS provider
Author: Alex Soldatchenko
Managing AWS credentials securely and efficiently is a common challenge for organizations. Static credentials are hard to rotate, prone to leaks, often over-privileged, and difficult to manage at scale. These challenges increase the likelihood of security incidents, complicate compliance, and create operational overhead.
This guide explains how to use HashiCorp Vault with HCP Terraform to address these challenges. It provides a practical, step-by-step approach to generating short-lived, scoped AWS credentials dynamically and integrating them into Terraform workflows. Pre-built modules enable teams to implement this pattern efficiently without building everything from scratch.
In this guide, you complete the following steps:
- Configure Vault to manage AWS credentials dynamically using the AWS secrets engine.
- Set up HCP Terraform to authenticate securely with Vault via the JSON Web Token (JWT) authentication method.
- Onboard AWS accounts into Vault and configure roles and policies for scoped access.
- Use short-lived, scoped AWS credentials to provision and manage cloud resources with Terraform.
This guidance provides a secure, scalable, and efficient implementation of Vault-backed dynamic credentials for HCP Terraform.
Target audience
This guide is for platform teams and practitioners responsible for building and maintaining secure, automated cloud infrastructure. The intended audience includes:
Vault Platform Team: Teams managing Vault and its integration with HCP Terraform, ensuring secure and scalable credential management.
HCP Terraform and AWS Platform Team: Teams responsible for managing HCP Terraform workspaces, onboarding AWS accounts, and configuring credentials for infrastructure automation.
Prerequisites
We recommend you read the following documentation to familiarize yourself with these foundational concepts:
- Value of Vault-backed dynamic credentials
- Workload Identity Tokens
- Vault Configuration
- AWS Configuration for Vault-Backed Credentials
- Specifying Multiple Configurations
- AWS secrets engine with assumed_role type
To follow this guide, you need the following:
- A self-hosted Vault instance or an HCP Vault Dedicated instance.
- A self-hosted Terraform Enterprise instance or an HCP Terraform organization.
- Permissions to create the required resources in Vault and AWS. Refer to the README file in each module provided in this guide for a list of required permissions.
Background and best practices
This pattern addresses common challenges in managing AWS credentials, offering improved security, scalability, and operational efficiency. By integrating Vault-backed dynamic credentials with HCP Terraform, platform teams can focus on securely delivering infrastructure to consumers.
- Enhanced security: Eliminate static credentials with short-lived, scoped AWS credentials managed by Vault.
- Simplified management: Centralize and automate credential issuance, rotation, and revocation across multiple AWS accounts.
- Operational efficiency: Automatically generate dynamic credentials for Terraform workflows, reducing manual overhead.
- Scalability: Pre-built Terraform modules standardize the onboarding of AWS accounts, Terraform projects, and workspaces, reducing setup complexity as the environment grows.
- Compliance: Gain auditability from the Vault audit logs and enforce fine-grained access policies to meet regulatory requirements.
We recommend the following security, operational, and team best practices to best handle dynamic credentials.
Security best practices
- Ensure the policies for both the Vault AWS secrets engine roles and the AWS IAM vault service role grant only the permissions needed for Terraform to provision the required resources. Frequently review these policies to prevent privilege creep.
- Within Vault, ensure you scope the policy assigned to the role used by the Terraform JWT authentication backend to only access the AWS secrets backend role. Use separate roles and policies for additional access as needed
- Configure logging in Vault and AWS to monitor authentication requests, credential generation, and infrastructure changes. This provides traceability and helps detect potential misconfigurations or security issues.
- Restrict access to the JWT authentication backend and AWS secrets engine roles in Vault to prevent unauthorized access. Use role-based access control (RBAC) and enforce strong authentication for users managing Vault.
- Regularly rotate the credentials of the AWS IAM user in Vault based on your own internal compliance requirements to reduce the risk of credential compromise.
Operational best practices
- Ensure the expiration time of Vault-issued STS credentials aligns with the JWT token expiration configured for HCP Terraform. This prevents failures during Terraform runs caused by expired credentials.
- Design workflows to account for the ephemeral nature of STS credentials. Avoid long-running Terraform runs, or adjust the time-to-live (TTL) accordingly, to prevent running into credential expiration disrupting workflows.
- Use the pre-built modules provided with this guide to automate the onboarding of AWS accounts into Vault and the setup of roles and policies. This reduces manual effort and minimizes human error.
- Leverage the modular design of the codebase to standardize and scale your implementation across multiple AWS accounts and Terraform workspaces and/or projects.
People and process
A successful implementation of this pattern requires close collaboration between platform teams and an understanding of key roles and responsibilities. The following sections outline the key teams, their responsibilities, and process recommendations to ensure a smooth adoption.
The Vault platform team has the following responsibilities:
- Configure and maintain the Vault AWS secrets engine for dynamic credential generation.
- Set up and manage the JWT authentication backend to enable workload identity for HCP Terraform.
- Define and enforce security best practices for Vault policies and role configurations to maintain least privilege.
- Educate Terraform users how to properly configure AWS provider blocks to use injected dynamic credentials.
- Educate the Terraform platform team how to interpret Vault audit logs for monitoring and troubleshooting.
We recommend the Vault platform team follow these best practices:
- Regularly review and update Vault policies to align with current infrastructure and security needs.
- Implement automated testing for Vault configurations to detect potential misconfigurations before deployment.
- Establish a knowledge-sharing process to onboard new team members and educate downstream teams effectively.
The HCP Terraform and AWS platform team has the following responsibilities:
- Onboard AWS accounts into Vault by creating and configuring IAM roles, policies, and Vault secrets engine roles.
- Configure HCP Terraform workspaces or projects with workload identity and environment variables to support dynamic credential injection.
- Maintain consistency across multiple AWS accounts and workspaces using standardized variable sets and templates.
- Educate platform customers how to properly configure AWS provider blocks in Terraform to use dynamic credentials.
- Teach platform customers the best practices to manage Terraform workspaces, projects, and AWS multi-account setups.
We recommend the HCP Terraform and AWS platform team follow these best practices:
- Use pre-built Terraform modules and examples to streamline onboarding of AWS accounts and HCP Terraform workspaces.
- Conduct regular policy audits for AWS IAM roles and Vault secrets engine roles to maintain least privilege.
- Collaborate with the Vault platform team to ensure alignment on token expiration times and policy scopes.
To best implement these best practices, we recommend the following collaboration and communication improvements:
- Establish regular touchpoints between the Vault platform team and the HCP Terraform and AWS platform teams to review configurations, align on security practices, and address challenges.
- Use shared documentation, such as runbooks and onboarding guides, to reduce silos and streamline workflows.
- Encourage feedback loops from platform customers to identify areas for improvement in configuration, processes, and training materials.
- Ensure all teams understand their roles and how they contribute to the larger goal of secure, scalable credential management.
- Use automation to reduce manual effort, ensure consistency, and minimize errors during onboarding and configuration.
- Treat this pattern as a living system. Continuously refine configurations, policies, and processes based on operational feedback and evolving infrastructure needs.
Validated architecture
The architecture diagram below demonstrates how HCP Terraform integrates with Vault to dynamically inject short-lived AWS credentials into Terraform workflows.
The components interact as follows:
- Trust is established between HCP Terraform and Vault's JWT authentication backend. This allows HCP Terraform workspaces to authenticate securely using workload identity tokens.
- A JWT role is created on the Vault JWT auth backend. This role serves as the workload identity of the HCP Terraform workspace and has a Vault policy attached to permit access to the specific AWS Secrets Engine role that generates the STS credentials.
- An AWS Secrets Engine role is created in the Vault AWS Secrets Engine using the
assumed_role
type. This role includes a Vault-defined AWS IAM policy that determines the permissions of the generated STS credentials after Vault's AWS IAM user assumes the Vault service AWS IAM role. The total permissions are the intersection of the Vault policy and the AWS IAM role policies. - The JWT role is assigned to the HCP Terraform workspace or project using a variable set. This assignment allows a workspace or project to authenticate with Vault during a Terraform run.
- The AWS Secrets Engine role, along with other required environment variables, is also assigned to the workspace to enable dynamic credential injection.
- A user or system triggers a Terraform run in the HCP Terraform workspace.
- Terraform requests credentials from Vault using its JWT workload identity. Vault's AWS Secrets Engine then triggers an STS assumption using its AWS IAM user.
- Vault assumes the AWS IAM role in the target AWS account using its IAM user.
- Vault generates STS credentials based on the effective permissions defined by both the Vault AWS Secrets Engine role and the AWS IAM role.
- The generated STS credentials are scoped to the intersection of the permissions defined by the Vault AWS Secrets Engine role and the AWS IAM role.
- The STS credentials are injected into the HCP Terraform workspace and used by the AWS provider during the Terraform run.
- The Terraform run executes using the injected credentials to create and manage AWS resources in the target client account. AWS automatically cleans up the STS credentials once they expire.
The diagram below shows the sequence of requests between HCP Terraform or Terraform Enterprise, Vault, and AWS to dynamically generate credentials. You can find this diagram in the root README file.
Object planning considerations
This section serves as a guide to the codebase structure and its intended use. By familiarizing yourself with the repository and its examples, you'll be better equipped to implement the Vault-backed dynamic credentials pattern effectively.
Codebase overview
The repository provides pre-built modules and examples for provisioning, configuring, and consuming Vault-backed dynamic credentials. Below is a high-level view of its structure and purpose:
├── module-provisioning-examples
│ ├── 1. prerequisites
│ ├── 2. aws-account-onboarding
│ └── 3. tfe-project-workspace-onboarding
├── modules
│ ├── terraform-aws-vault-dynamic-secrets-prereqs
│ ├── terraform-tfe-vault-dynamic-creds-onboarding
│ ├── terraform-tfe-vault-dynamic-creds-variables
│ ├── terraform-vault-aws-account-onboarding
│ └── terraform-vault-jwt-tfe-identity
├── provider-usage-examples
│ ├── multi-aws-account-provider-configs
│ └── single-aws-account-provider-configs
Module provisioning examples
The module-provisioning-examples
directory contains codified templates demonstrating how to call and pass variables to the modules. These examples provide a step-by-step implementation of the pattern and should be followed in the correct order:
- Prerequisites sets up foundational resources by calling:
terraform-aws-vault-dynamic-secrets-prereqs
: Configures Vault AWS secrets engine, IAM user, and JWT authentication backend.
- AWS account onboarding onboards target AWS accounts into Vault by calling:
terraform-vault-aws-account-onboarding
: Onboards AWS accounts by creating IAM roles, Vault roles, and policies.
- HCP Terraform Project/Workspace onboarding configures HCP Terraform by calling:
terraform-tfe-vault-dynamic-creds-onboarding
: Integrates Vault with HCP Terraform, including workload identity and dynamic credential injection.terraform-tfe-vault-dynamic-creds-variables
: Manages HCP Terraform environment variables required for Vault integration.terraform-vault-jwt-tfe-identity
: Sets up JWT authentication for HCP Terraform to authenticate with Vault.
Each module includes a detailed README and an example
directory with sample configurations. Use these examples to understand how to use the modules.
Provider usage examples
The provider-usage-examples
directory is the final step for consumers of HCP Terraform. It demonstrates how end users can configure their Terraform code to leverage the injected dynamic credentials.
single-aws-account-provider-configs
: shows how to configure a default AWS provider and aliased providers within a single AWS account.multi-aws-account-provider-configs
: demonstrates how to configure AWS providers for multiple accounts using dynamic credentials.
These examples are for HCP Terraform customers who consume the pattern. Ensure platform teams educate users on these configurations to maximize adoption and proper use of dynamic credentials.
Checklist
Before you start implementing this pattern, use this checklist to ensure you have all the necessary resources and permissions to execute the steps effectively.
Repository and environment setup
Complete the following steps to prepare to deploy the modules:
- Clone the repository containing this pattern to your local machine.
- Create a dedicated local directory to organize your Terraform code. Use the examples in the
module-provisioning-examples
directory as starting points.
Confirm permissions in Vault
You must have the following permissions in your Vault instance:
- The ability to configure the AWS secrets engine.
- The ability to enable and configure the JWT authentication backend.
- Access to create and assign policies to AWS roles in Vault.
Confirm permissions in AWS
You must have the following permissions in your AWS accounts:
- Access to create IAM roles, policies, and users in the AWS accounts.
- Allow Vault to assume IAM roles in the target AWS accounts.
Prepare AWS accounts
We recommend that you maintain a separate AWS account to manage Vault IAM users and connect it to Vault to use the AWS secrets engine.
- Vault AWS Account: Hosts the Vault IAM user and AWS secrets engine configuration.
- Target AWS Accounts: Onboard one or more AWS accounts to be dynamic credential "ready" for Terraform runs.
Tip
While the pattern can work with two accounts, using three accounts enables a more thorough validation of multi-account functionality.
Configure HCP Terraform
You can either configure an individual workspace to consume dynamic credentials, or create a project to manage a collection of workspaces.
- Configure an HCP Terraform workspace to consume Vault-backed dynamic credentials.
- Configure an HCP Terraform project with one or more workspaces assigned under it.
Terraform setup
- Ensure access to a self-hosted Terraform Enterprise instance or an HCP Terraform organization.
- Configure the Terraform CLI and workspace environment to securely manage Terraform state when using remote backends.
Tooling
- Terraform CLI: We recommend that you use the latest version of the Terraform CLI.
- AWS CLI: Configured with appropriate credentials and access to the AWS accounts.
- Vault CLI: Used to test and verify Vault configuration.
Workflows
The deployment of this pattern follows a structured approach to ensure secure, scalable, and automated credential management.
- Provision Vault and AWS prerequisites to establish the foundation for dynamic credentials. The AWS secrets engine and JWT authentication backend are configured in Vault, and required IAM roles and policies are created in AWS. These components enable Vault to securely assume AWS IAM roles and generate short-lived STS credentials.
- Onboard AWS accounts into Vault to enable dynamic credential issuance. AWS IAM roles, policies, and Vault secrets engine roles are created to allow scoped access to resources. This ensures that AWS accounts are properly configured to support ephemeral credentials managed by Vault.
- Configure HCP Terraform workspaces to authenticate with Vault and retrieve dynamic credentials. Workload identity is enabled in Terraform workspaces, allowing them to request AWS credentials dynamically. Vault roles and policies are assigned to enforce least-privilege access and ensure credentials are scoped appropriately.
- Update Terraform AWS provider configurations to consume injected credentials. Terraform configurations are modified to use dynamic credentials instead of static IAM keys. This eliminates long-lived secrets while maintaining seamless ability to deploy AWS resources.
Deploy prerequisites
The Vault platform team configures the Vault AWS secrets engine and enables the HCP Terraform JWT authentication backend.
To enable Vault-backed dynamic credentials, you must first provision the foundational components. The key module for this step is terraform-aws-vault-dynamic-secrets-prereqs
, which establishes the necessary AWS and Vault configurations for secure credential management. This module is responsible for:
- Creating an AWS IAM user with the required permissions for Vault integration.
- Configuring the AWS secrets engine in Vault to generate short-lived credentials dynamically.
- Setting up JWT authentication in Vault to allow HCP Terraform to authenticate securely.
Reference the /module-provisioning-examples/1. prerequisites
directory for an example of how to call this module. Copy the example configuration and make the necessary adjustments based on your specific environment. You can see the full set of inputs in the /modules/terraform-aws-vault-dynamic-secrets-prereqs/example
directory.
Warning
This module provisions an AWS IAM user, IAM policies, Vault secrets engines, and authentication mounts. Deploy with least-privilege AWS and Vault credentials to minimize security risks.
The module takes the following inputs:
external_id = "01931d16-aa6e-7b2e-8678-f1757c144041"
aws_secrets_backend_tune_settings = {
default_lease_ttl_seconds = 3600
max_lease_ttl_seconds = 7200
}
jwt_backend_tune_settings = {
default_lease_ttl = "1h"
max_lease_ttl = "2h"
}
- The
external_id
value must remain consistent across all future steps. It is a critical security control that mitigates the confused deputy problem, ensuring that only the intended entity can assume an IAM role. - The default and max lease TTLs define how long AWS STS credentials and JWT tokens remain valid. Proper alignment is necessary to avoid credential expiration during Terraform runs.
AWS secrets engine TTLs
default_lease_ttl_seconds = 3600
(1 hour): The default duration for AWS credentials issued by Vault.max_lease_ttl_seconds = 7200
(2 hours): The maximum allowed duration before credentials expire.- Ensure that Terraform runs are not longer than the AWS credentials’ TTLs. Long-running executions may fail due to expired credentials.
JWT backend TTLs
default_lease_ttl = "1h"
: The default time-to-live for JWT tokens used by HCP Terraform.max_lease_ttl = "2h"
: The longest duration a token can remain valid.- JWT token expiration should align with the AWS secrets engine TTLs. If the JWT expires before AWS credentials, Terraform runs could lose access mid-execution.
The module provisions the following resources:
AWS resources
- An IAM user dedicated to Vault, used by the AWS secrets engine to assume roles.
- An IAM policy attached to the IAM user, granting permissions to assume specific AWS IAM roles in future steps.
- An IAM access key associated with the Vault IAM user. This key is securely stored in Vault and is never used directly.
Warning
The Vault AWS secrets engine provides the ability to rotate the access keys for the IAM user. This capability ensures the security and longevity of the IAM user credentials. For more information, refer to the documentation for configuring root credentials. We recommend enabling auto rotation.
Vault resources
The AWS secrets engine is available at the configured path (aws-tfc/
), allowing Vault to generate dynamic AWS credentials.
The JWT authentication backend is available at the configured path (jwt-tfc/
), allowing HCP Terraform to authenticate securely.
Onboard AWS accounts
The HCP Terraform and AWS platform teams configure Vault to manage dynamic credentials for onboarded AWS accounts by setting up IAM roles and AWS secrets engine roles.
With Vault and the AWS secrets engine configured, the next step is to onboard AWS accounts to support dynamic credentials. The terraform-vault-aws-account-onboarding
module is responsible for provisioning the required IAM roles, policies, and Vault AWS secrets engine roles. This module ensures that AWS accounts are properly configured for Vault to generate short-lived, scoped AWS credentials for Terraform runs. The module performs the following tasks:
- Creates an IAM role with a trust policy for the Vault service user, allowing Vault to assume the role.
- Configures the IAM role policy, which determines the maximum permissions granted to STS credentials issued by Vault. Supports built-in AWS policies or custom JSON policies for maximum flexibility.
- Defines
vault_aws_secret_backend_role
resources to enable Vault to issueassumed_role
credentials. - Supports multiple Vault roles using a
for_each
loop for flexible configuration, enabling the definition of various roles with different permissions.
Reference the /module-provisioning-examples/2. aws-account-onboarding/
directory for an example of how to call this module. Copy the example configuration and make the necessary adjustments based on your environment. You can see the full set of inputs in the /modules/terraform-vault-aws-account-onboarding/example
directory.
Some notable items from the provisioning example:
- The
terraform_remote_state
data source used to retrieve the IAM user ARN and AWS backend path created in the previous step. - Two instances of the
terraform-vault-aws-account-onboarding
module to onboard two AWS accounts. - Creation of Vault AWS roles using built-in AWS policies, such as
AmazonEC2FullAccess
, and custom JSON policies.
Warning
This module provisions IAM roles, policies, and Vault roles. Ensure you scope policies appropriately to prevent over-privileged access.
Make sure that the external_id
value matches the one used in the previous step. This ensures only the intended entity can assume the IAM roles. In addition to the external ID, there are other important inputs to consider:
vault_aws_service_role_config = {
aws_built_in_policy_name = "AdministratorAccess"
custom_policy_name = null
custom_policy_directory = null
}
The vault_aws_service_role_config
block defines the IAM role policy configuration for the Vault service role. It allows you to specify either a built-in AWS policy or a custom policy.
aws_built_in_policy_name
: The name of the built-in AWS policy to attach to the IAM role. If using a custom policy, set this tonull
.custom_policy_name
: The name of the custom policy without the.json
extension. Set this tonull
if not using a custom policy.custom_policy_directory
: The storage directory for the custom policy. Set this tonull
if not using a custom policy.
Tip
The policy applied using vault_aws_service_role_config
is the policy applied to the IAM role that Vault assumes. This policy should be the intersection of the permissions required by the Vault AWS secrets engine role and the AWS IAM role. This policy determines the maximum permissions granted to the STS credentials issued by Vault.
The module also supports the creation of multiple Vault AWS secrets engine roles using the for_each
loop. This feature allows you to define multiple roles with different permissions and configurations. Use built-in AWS policies or custom JSON policies to define the permissions granted to the generated STS credentials. Below are examples of how to define a role using a built-in AWS policy and a custom JSON policy.
Built-in AWS policy example:
vault_aws_role_configurations = {
ec2_instance_provisioner = {
name = "ec2-instance-provisioner"
tag_suffix = "EC2_PROV"
custom_policy_name = null
custom_policy_directory = null
aws_built_in_policy_name = "AmazonEC2FullAccess" # built-in policy name, set to null if not using built-in policy
default_sts_ttl = 3600
max_sts_ttl = 7200
}
}
Custom JSON policy example:
vault_aws_role_configurations = {
ec2_instance_provisioner = {
name = "ec2-instance-provisioner"
tag_suffix = "EC2_PROV"
custom_policy_name = "ec2-full-access" # trim the .json extension, i.e. ec2-full-access.json becomes ec2-full-access
custom_policy_directory = "policies"
aws_built_in_policy_name = null
default_sts_ttl = 3600
max_sts_ttl = 7200
}
}
Warning
AWS enforces a strict size limit on session policies. Ensure that the JSON policy passed during the AssumeRole call does not exceed 2048 characters. Policies exceeding this size result in a validation error during the AssumeRole call.
The module has intentionally structured outputs to provide the necessary information for the next steps. These outputs include the ARN of the IAM role, the ARN of the Vault service user, and the path to the AWS secrets engine in Vault. Subsequent steps use these outputs to configure HCP Terraform workspaces and inject dynamic credentials. Below is an example of the outputs provided by the module:
# Output example
output "vault_aws_roles_01" {
description = "The AWS role aliases to be used in the Terraform Cloud Workspace or Project environment variables to support dynamic credentials."
value = module.aws_vault_account_onboarding_01.vault_aws_roles
}
# Output structure
vault_aws_roles_01 = {
"123456789012_TFC_VAULT_BACKED_AWS_RUN_VAULT_ROLE_DB_ADMIN" = {
"aws_run_role_arn" = "arn:aws:iam::123456789012:role/vault-service-role"
"tag_suffix" = "123456789012_DB_ADMIN"
"vault_role" = "123456789012-dynamodb-admin"
}
"123456789012_TFC_VAULT_BACKED_AWS_RUN_VAULT_ROLE_EC2_PROV" = {
"aws_run_role_arn" = "arn:aws:iam::123456789012:role/vault-service-role"
"tag_suffix" = "123456789012_EC2_PROV"
"vault_role" = "123456789012-ec2-instance-provisioner"
}
"123456789012_TFC_VAULT_BACKED_AWS_RUN_VAULT_ROLE_S3_ADMIN" = {
"aws_run_role_arn" = "arn:aws:iam::123456789012:role/vault-service-role"
"tag_suffix" = "123456789012_S3_ADMIN"
"vault_role" = "123456789012-s3-full-access"
}
}
Provisioning this module creates the following resources:
AWS resources
- IAM vault service role that Vault assumes to generate STS credentials.
- IAM policy attached to the Vault service role, defining the maximum permissions granted to dynamically issued credentials.
- IAM trust policy on the vault service role, restricting assumptions to only the Vault IAM user and enforcing the external ID.
- Multiple IAM roles if configured, for different Terraform use cases, each with scoped permissions.
Tip
The IAM policy attached to the AWS IAM vault-service-role
role and the Vault AWS secrets engine role determine the permissions granted to the STS credentials issued by Vault. The applied policy is at the intersection of the Vault AWS secrets engine role and the AWS IAM role policies. These permissions cannot exceed the permissions granted by the AWS IAM vault-service-role
role.
Vault resources
- Vault AWS secrets engine roles such as
vault_aws_secret_backend_role
, mapping Vault roles to AWS IAM roles for dynamic credential issuance. - Dynamic credential scoping based on the
default_sts_ttl
andmax_sts_ttl
TTL configurations, ensuring short-lived, ephemeral credentials. - Multiple Vault AWS secrets engine roles if configured, allowing differentiated access per Terraform workspace or project.
The successful completion of this step establishes a secure mapping between Vault and AWS IAM, allowing Vault to generate short-lived, scoped credentials dynamically. The next step configures HCP Terraform workspaces to consume these credentials.
Configure HCP Terraform workspaces and projects for dynamic credentials
The HCP Terraform and AWS platform teams integrate HCP Terraform with Vault to dynamically inject short-lived AWS credentials into Terraform runs.
With AWS accounts onboarded and Vault AWS secrets engine roles configured, the next step is to configure HCP Terraform workspaces and projects to consume these credentials dynamically. This step ensures that Terraform runs authenticate securely without relying on static IAM credentials.
The terraform-tfe-vault-dynamic-creds-onboarding
module handles this integration by completing the following steps:
- Assigning the JWT role and Vault AWS secrets engine roles to the specified Terraform workspaces or projects.
- Configuring HCP Terraform workload identity, enabling the workspace to authenticate with Vault via JWT.
- Injecting dynamic credentials into Terraform runs, ensuring each run gets a short-lived, scoped AWS credential.
- Using variable sets for scalable and repeatable configuration.
Reference the /module-provisioning-examples/3. tfe-project-workspace-onboarding/
directory for an example of how to call this module. Copy the example configuration and adjust it based on your environment. You can see the full set of inputs in the /modules/terraform-tfe-vault-dynamic-creds-onboarding/example
directory.
Warning
Workspaces using Vault-backed credentials must not have static AWS IAM credentials stored in HCP Terraform environment variables. Remove any existing AWS provider variables, such as AWS_ACCESS_KEY_ID
and AWS_SECRET_ACCESS_KEY
, to prevent conflicts with dynamic credentials.
Some notable items from the provisioning example:
- The
terraform_remote_state
data source used to retrieve the Vault AWS secrets engine roles and IAM role ARNs created in the previous steps. - Two instances of the
terraform-tfe-vault-dynamic-creds-onboarding
module to configure a HCP Terraform workspace and project. - Applying a
default_aws_run_role
along withaws_role_aliases
. Defining onlyaws_role_aliases
requires explicit assignment of the provider in each module block.
The module allows you to configure the vault_jwt_token_ttl
. Make sure that the JWT token expiration aligns with the Vault AWS secrets engine TTLs as well as the STS credentials TTL. In addition to the JWT token TTL, there are other important inputs to consider:
tfe_project_name = null
tfe_workspace_name = "aws-acme-app-infra-dev"
The tfe_project_name
and tfe_workspace_name
inputs allow you to specify the HCP Terraform project and workspace to configure. This enables you to target specific workspaces for dynamic credential injection. Only a project or workspace is configurable per module call. Set the other to null
.
default_aws_run_role = {
aws_run_role_arn = "arn:aws:iam::123456789012:role/vault-service-role"
vault_role = "123456789012-s3-full-access"
}
The default_aws_run_role
block defines the default AWS role alias and Vault role that the Terraform workspace uses. The workspace uses this role when no specific alias applies to a provider block. Modules without an explicit provider assignment use this default role. It ensures that the workspace or project always has a default role to fall back on.
aws_role_aliases = {
TFC_VAULT_BACKED_AWS_RUN_VAULT_ROLE_EC2_PROV = {
aws_run_role_arn = "arn:aws:iam::123456789012:role/vault-service-role"
tag_suffix = "123456789012_EC2_PROV"
vault_role = "123456789012-ec2-instance-provisioner"
}
TFC_VAULT_BACKED_AWS_RUN_VAULT_ROLE_DB_ADMIN = {
aws_run_role_arn = "arn:aws:iam::123456789012:role/vault-service-role"
tag_suffix = "123456789012_DB_ADMIN"
vault_role = "123456789012-dynamodb-admin"
}
}
Keep in mind the output structure from the previous step when defining the aws_role_aliases
block. The aws_role_aliases
block maps the AWS role aliases to the Vault roles created in the previous step. Each alias corresponds to a specific AWS role and Vault role, allowing you to assign different roles to different provider blocks in your Terraform configuration. Use tag_suffix
to identify the role and inject the credentials into an aliased provider block.
aws_role_aliases = data.terraform_remote_state.vault_aws_dynamic_creds_prereqs.outputs.all_vault_aws_roles
A terraform_remote_state
data source retrieves the structured outputs from the previous step. This data source ensures that the correct assignment of AWS role aliases and Vault roles to the HCP Terraform workspace or project. The aws_role_aliases
input uses the output from the previous step, ensuring consistency and accuracy in the assignment of roles.
The module creates the following resources:
HCP Terraform configurations
- Workspaces configured for workload identity enabling authentication with Vault using JWT.
- Vault AWS secrets engine roles assigned to workspaces linking AWS permissions to Terraform runs.
- Environment variables injected via variable sets ensuring consistent authentication settings for Vault.
- Provider-specific role aliasing enabling workspaces to dynamically assume different AWS roles based on Terraform module configurations.
Vault resources
- JWT authentication mappings associating HCP Terraform workspaces and projects with the correct Vault JWT role.
- Vault policy assignments enforcing role-based access control for AWS secrets engine credential issuance.
The following table outlines the environment variables configured in the HCP Terraform workspace or project to enable Vault workload identity and dynamic credential injection. This configuration assumes a single AWS account setup with both a default default_aws_run_role
AWS run role and role-specific aws_role_aliases
aliases.
Key | Value | Category |
---|---|---|
TFC_DEFAULT_VAULT_BACKED_AWS_AUTH_TYPE | assumed_role | env |
TFC_DEFAULT_VAULT_BACKED_AWS_MOUNT_PATH | aws-tfc | env |
TFC_DEFAULT_VAULT_BACKED_AWS_RUN_ROLE_ARN | arn:aws:iam::123456789012:role/vault-service-role | env |
TFC_DEFAULT_VAULT_BACKED_AWS_RUN_VAULT_ROLE | 123456789012-s3-full-access | env |
TFC_VAULT_ADDR | https://vault-demo-01-public-vault-acbc4bf5.d7b4d80f.z1... | env |
TFC_VAULT_AUTH_PATH | jwt-tfc | env |
TFC_VAULT_BACKED_AWS_AUTH | true | env |
TFC_VAULT_BACKED_AWS_AUTH_123456789012_DB_ADMIN | true | env |
TFC_VAULT_BACKED_AWS_AUTH_123456789012_EC2_PROV | true | env |
TFC_VAULT_BACKED_AWS_RUN_ROLE_ARN_123456789012_DB_ADMIN | arn:aws:iam::123456789012:role/vault-service-role | env |
TFC_VAULT_BACKED_AWS_RUN_ROLE_ARN_123456789012_EC2_PROV | arn:aws:iam::123456789012:role/vault-service-role | env |
TFC_VAULT_BACKED_AWS_RUN_VAULT_ROLE_123456789012_DB_ADMIN | 123456789012-dynamodb-admin | env |
TFC_VAULT_BACKED_AWS_RUN_VAULT_ROLE_123456789012_EC2_PROV | 123456789012-ec2-instance-provisioner | env |
TFC_VAULT_NAMESPACE | admin | env |
TFC_VAULT_PROVIDER_AUTH | true | env |
TFC_VAULT_RUN_ROLE | aws-acme-app-infra-dev-role | env |
These configurations establish the final integration between HCP Terraform and Vault, allowing Terraform to securely consume ephemeral AWS credentials for infrastructure deployments. The next step demonstrates how to configure the AWS provider in Terraform to use dynamic credentials.
Using dynamic credentials in Terraform
The application developers, platform engineers, and site reliability engineers responsible for writing and maintaining Terraform infrastructure code configure the AWS provider in Terraform to consume Vault-injected dynamic credentials.
With HCP Terraform workspaces and Vault fully configured, the final step is to consume the dynamically injected AWS credentials in Terraform configurations.
The repository provides usage examples that demonstrate different ways to configure AWS providers to work with dynamic credentials:
- Single AWS Account: Configuring a default AWS provider and multiple aliased providers within a single AWS account.
- Multiple AWS Accounts: Managing AWS provider configurations across distinct AWS accounts, each assuming separate IAM roles.
These following examples are in the /provider-usage-examples/
directory:
This step guides you through:
- How Terraform automatically uses injected credentials without additional configuration.
- How to explicitly assign AWS roles to specific provider blocks for multi-role setups.
- Best practices for structuring AWS provider configurations for dynamic credentials.
By the end of this step, Terraform runs are fully integrated with Vault-backed ephemeral credentials.
The single-aws-account-provider-configs
example demonstrates how to configure a default AWS provider and multiple aliased providers within a single AWS account. This setup is ideal for workspaces that require different permissions for various resources. The example includes:
Definition of a required Terraform variable that HCP Terraform uses to inject the dynamic credentials.
variable "tfc_vault_backed_aws_dynamic_credentials" {
description = "Object containing Vault-backed AWS dynamic credentials configuration"
type = object({
default = object({
shared_credentials_file = string
})
aliases = map(object({
shared_credentials_file = string
}))
})
}
Configuration of the default AWS provider using the default_aws_run_role
:
provider "aws" {
region = "us-east-1"
shared_credentials_files = [var.tfc_vault_backed_aws_dynamic_credentials.default.shared_credentials_file]
}
Configuration of aliased AWS providers using the aws_role_aliases
:
provider "aws" {
region = "us-east-1"
alias = "dynamodb-admin"
shared_credentials_files = [var.tfc_vault_backed_aws_dynamic_credentials.aliases["123456789012_DB_ADMIN"].shared_credentials_file]
}
# dynamic tagged/aliased provider
provider "aws" {
region = "us-east-1"
alias = "ec2-provisioner"
shared_credentials_files = [var.tfc_vault_backed_aws_dynamic_credentials.aliases["123456789012_EC2_PROV"].shared_credentials_file]
}
The multi-aws-account-provider-configs
example demonstrates how to configure AWS providers across distinct AWS accounts, each assuming separate IAM roles. This setup is ideal for workspaces that require permissions across multiple AWS accounts. The example includes:
Configuration of multiple AWS providers for different AWS accounts:
//////////////////////////////////////////////////////////
// Provider configurations for Account ID: 123456789012 //
//////////////////////////////////////////////////////////
provider "aws" {
region = "us-east-1"
alias = "s3-admin-123456789012"
shared_credentials_files = [var.tfc_vault_backed_aws_dynamic_credentials.aliases["123456789012_S3_ADMIN"].shared_credentials_file]
}
# dynamic tagged/aliased provider
provider "aws" {
region = "us-east-1"
alias = "dynamodb-admin-123456789012"
shared_credentials_files = [var.tfc_vault_backed_aws_dynamic_credentials.aliases["123456789012_DB_ADMIN"].shared_credentials_file]
}
# dynamic tagged/aliased provider
provider "aws" {
region = "us-east-1"
alias = "ec2-provisioner-123456789012"
shared_credentials_files = [var.tfc_vault_backed_aws_dynamic_credentials.aliases["123456789012_EC2_PROV"].shared_credentials_file]
}
//////////////////////////////////////////////////////////
// Provider configurations for Account ID: 210987654321 //
//////////////////////////////////////////////////////////
# dynamic tagged/aliased provider
provider "aws" {
region = "us-east-1"
alias = "s3-admin-210987654321"
shared_credentials_files = [var.tfc_vault_backed_aws_dynamic_credentials.aliases["210987654321_S3_ADMIN"].shared_credentials_file]
}
# dynamic tagged/aliased provider
provider "aws" {
region = "us-east-1"
alias = "dynamodb-admin-210987654321"
shared_credentials_files = [var.tfc_vault_backed_aws_dynamic_credentials.aliases["210987654321_DB_ADMIN"].shared_credentials_file]
}
# dynamic tagged/aliased provider
provider "aws" {
region = "us-east-1"
alias = "ec2-provisioner-210987654321"
shared_credentials_files = [var.tfc_vault_backed_aws_dynamic_credentials.aliases["210987654321_EC2_PROV"].shared_credentials_file]
}
Conclusion
By following this guide, you have implemented a secure, automated, and scalable approach to managing AWS credentials in HCP Terraform using HashiCorp Vault. You have eliminated static IAM credentials and replaced them with short-lived, dynamically scoped AWS credentials that integrate seamlessly into Terraform workflows.
This achieves automated credential lifecycle management, covering credential issue, rotation, and revocation, dynamically without manual intervention. It centralizes access control by enforcing least privilege, ensuring correct scoping of credentials across AWS accounts and Terraform workspaces. The approach also enables seamless scaling, using Terraform modules to standardize AWS account and workspace onboarding, reducing setup complexity as infrastructure grows. By removing long-lived IAM credentials, it strengthens security and minimizes the risk of credential leaks or unauthorized access.
This saves you from having to manually create and distribute static AWS credentials, enforce least privilege on a per-user basis, and manage complex IAM key rotations across multiple Terraform workspaces. Instead, you now have an automated, secure, and repeatable pattern that scales effortlessly while maintaining strong security and compliance controls.