Skip to main content

Access AWS from HCP Terraform with OIDC federation

Securely access AWS from HCP Terraform using OIDC federation, eliminating the need to use access keys.

Storing access keys in HCP Terraform poses a security risk. While HCP Terraform secures sensitive credentials as write-only variables, you must audit the usage of long-lived access keys to detect if they are compromised. Not only is leaking the access key a risk, but many organizations have a policy to block the creation of such access keys.

Fortunately, in many cases, you can authenticate with more secure alternatives to access keys. One such alternative is AWS IAM OIDC federation, which uses identity and access management (IAM) to grant external identities (such as HCP Terraform) the ability to assume an IAM role.

HCP Terraform’s dynamic provider credentials allow Terraform runs to assume an IAM role through native OpenID Connect (OIDC) integration and obtain temporary security credentials for each run. These AWS credentials allow you to call AWS APIs that the IAM role has access to at runtime. These credentials are usable for only one hour by default, so their usefulness to an attacker is limited.

This brief tutorial will show you how to set up an OIDC provider and access AWS from HCP Terraform using dynamic provider credentials and OIDC federation.

»Tutorial

For this tutorial, you will use HCP Terraform to provision an OIDC provider that establishes a trust relationship between HCP Terraform and your AWS account. This setup allows HCP Terraform to assume an IAM role at runtime and pass the obtained temporary security credentials to the AWS Terraform provider to run terraform plan or apply.

To set up an OIDC provider, the below steps assume that you already have a method available to authenticate to your AWS account.

»Set up the OIDC provider

To set up the HCP Terraform OIDC provider for OIDC federation in AWS, use the following example configuration:

data "tls_certificate" "provider" {
  url = "https://app.terraform.io"
}
 
resource "aws_iam_openid_connect_provider" "hcp_terraform" {
  url = "https://app.terraform.io"
 
  client_id_list = [
    "aws.workload.identity", # Default audience in HCP Terraform for AWS.
  ]
 
  thumbprint_list = [
    data.tls_certificate.provider.certificates[0].sha1_fingerprint,
  ]
}

Once the HCP Terraform OIDC provider is created, create an ‘example’ IAM role that HCP Terraform will assume at runtime:

data "aws_iam_policy_document" "example_oidc_assume_role_policy" {
  statement {
    effect = "Allow"
 
    actions = ["sts:AssumeRoleWithWebIdentity"]
 
    principals {
      type        = "Federated"
      identifiers = [aws_iam_openid_connect_provider.hcp_terraform.arn]
    }
 
    condition {
      test     = "StringEquals"
      variable = "app.terraform.io:aud"
      values   = ["aws.workload.identity"]
    }
 
    condition {
      test     = "StringLike"
      variable = "app.terraform.io:sub"
      values   = ["organization:ORG_NAME:project:PROJECT_NAME:workspace:WORKSPACE_NAME:run_phase:*"]
    }
  }
}
 
resource "aws_iam_role" "example" {
  name               = "example"
  assume_role_policy = data.aws_iam_policy_document.example_oidc_assume_role_policy.json
}

The IAM role defined above currently includes only an assume_role_policy and lacks additional permissions. Depending on your requirements, you may need to add more permissions to the role to allow it to create and manage resources, such as S3 buckets, or EC2 instances.

In the aws_iam_policy_document, define a condition that evaluates the OIDC subject claim for HCP Terraform organization, project, workspace, and run phase. The subject claim in the example searches for specific organization, project, and workspace. However, you can make the claim more flexible by using wildcards (*), such as organization:ORG_NAME:project:PROJECT_NAME:workspace:*:run_phase:*.

This claim allows for matching of all workspaces and run phases within a specific HCP Terraform project and organization, which can be helpful in scenarios like using HCP Terraform’s no-code modules to provide self-service infrastructure, where workspace names may not be known in advance.

Note that wildcards in OIDC subject claims can simplify access policies but introduce potential security risks. To balance flexibility and security, use wildcards carefully. While you can scope claims down to a specific HCP Terraform workspace or run phase for maximum security, wildcards can be used selectively to replace certain values, offering a compromise between granularity and convenience.

You can add additional permissions to an IAM role by using the aws_iam_policy_document data source and the aws_iam_policy resource. See the example below:

data "aws_iam_policy" "s3_full_access" {
  arn = "arn:aws:iam::aws:policy/AmazonS3FullAccess"
}
 
resource "aws_iam_role_policy_attachment" "example_s3_full_access" {
  policy_arn = data.aws_iam_policy.s3_full_access.arn
  role       = aws_iam_role.example.name
}

»Using OIDC federation

When using OIDC federation, apart from the region argument, you don’t need to include any authentication configuration within the provider block. As long as you set up the correct environment variables in your workspace—specifically, set TFC_AWS_PROVIDER_AUTH to true and TFC_AWS_RUN_ROLE_ARN to the IAM role ARN that HCP Terraform should assume at runtime.

resource "tfe_variable" "tfc_aws_provider_auth" {
  key          = "TFC_AWS_PROVIDER_AUTH"
  value        = "true"
  category     = "env"
  workspace_id = tfe_workspace.example.id
}
 
resource "tfe_variable" "tfc_example_role_arn" {
  sensitive    = true
  key          = "TFC_AWS_RUN_ROLE_ARN"
  value        = aws_iam_role.example.arn
  category     = "env"
  workspace_id = tfe_workspace.example.id
}

HCP Terraform will automatically assume the IAM role and inject the temporary credentials for you, using the workspace environment variables, allowing you to focus on creating infrastructure.

»Implementing access management for your AWS organization

For improved security and scalability, we recommend implementing a pattern where one or more HCP Terraform workspaces inject the IAM role and OIDC provider ARNs into other workspaces using an HCP Terraform variable set. This enables the platform/cloud team to create HCP Terraform workspaces with pre-configured AWS authentication, scoped to a specific IAM role and permissions.

Whether you create an OIDC provider per AWS account, per environment, or use a single OIDC provider, providing pre-configured AWS authentication for teams’ HCP Terraform workspace is a win-win for both the platform/cloud team and the teams they enable to work autonomously.

Below is an example configuration that creates a variable set for a specific IAM role and sets two environment variables. HCP Terraform uses these environment variables to assume the IAM role and obtain temporary security credentials at runtime, injecting them into the provider to enable access to any AWS API allowed by the IAM role’s policies.

First, create the variable set:

resource "tfe_variable_set" "example" {
  name         = aws_iam_role.example.name
  description  = "OIDC federation configuration for ${aws_iam_role.example.arn}"
  organization = "XXXXXXXXXXXXXXX"
}

Next, set up the required environment variables and link them to the variable set:

resource "tfe_variable" "tfc_aws_provider_auth" {
  key             = "TFC_AWS_PROVIDER_AUTH"
  value           = "true"
  category        = "env"
  variable_set_id = tfe_variable_set.example.id
}
 
resource "tfe_variable" "tfc_example_role_arn" {
  sensitive       = true
  key             = "TFC_AWS_RUN_ROLE_ARN"
  value           = aws_iam_role.example.arn
  category        = "env"
  variable_set_id = tfe_variable_set.example.id
}

Finally, share the variable set with another HCP Terraform workspace. This ensures that the targeted workspace receives and uses the environment variables, allowing HCP Terraform to automatically assume the IAM role and inject the temporary security credentials:

resource "tfe_workspace_variable_set" "example" {
  variable_set_id = tfe_variable_set.example.id
  workspace_id    = "ws-XXXXXXXXXXXXXXX"
}

»Creating infrastructure from another workspace

Using the IAM role created earlier in this tutorial, which has been assigned S3 permissions, you can create a bucket right away within the workspace you’ve delegated access to without needing any additional configuration:

provider "aws" {
  region = "us-west-2"
}
 
resource "aws_s3_bucket" "example" {
  bucket = "example"
}

»Learn more about OIDC federation

For more on how to securely access AWS from HCP Terraform with OIDC federation, check out the Dynamic Credentials with the AWS Provider and OIDC federation documentation. Find a more complete example of configuring the AWS IAM OIDC identity provider on GitHub.

Sign up for the latest HashiCorp news

By submitting this form, you acknowledge and agree that HashiCorp will process your personal information in accordance with the Privacy Policy.

HashiCorp uses data collected by cookies and JavaScript libraries to improve your browsing experience, analyze site traffic, and increase the overall performance of our site. By using our website, you’re agreeing to our Privacy Policy and Cookie Policy.

The categories below outline which companies and tools we use for collecting data. To opt out of a category of data collection, set the toggle to “Off” and save your preferences.