You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
terraform/website/docs/language/stacks/deploy/authenticate.mdx

315 lines
14 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

---
page_title: Authenticate a Stack
description: Learn how to set up OIDC authentication or use the store block to authenticate Stacks with their providers.
---
⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️
> [!IMPORTANT]
> **Documentation Update:** Product documentation previously located in `/website` has moved to the [`hashicorp/web-unified-docs`](https://github.com/hashicorp/web-unified-docs) repository, where all product documentation is now centralized. Please make contributions directly to `web-unified-docs`, since changes to `/website` in this repository will not appear on developer.hashicorp.com.
⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️
# Authenticate a Stack
You can authenticate a Stack in two ways: by using OIDC to dynamically authenticate with the built-in `identity_token` block or by accessing existing authentication credentials with the `store` block. We recommend authenticating your Stack with OIDC because using static credentials to authenticate providers presents a security risk, even if you rotate your credentials regularly.
## Authenticate with OIDC
[OpenID Connect](https://openid.net/connect/) (OIDC) is an identity layer on top of the OAuth 2.0 protocol. You can use HCP Terraforms [Workload identity](/terraform/cloud-docs/workspaces/dynamic-provider-credentials/workload-identity-tokens) tokens, built on the OpenID Connect protocol, to securely connect and authenticate your Stacks with cloud providers.
-> **Hands on**: Walk through setting up OIDC for a Stack in the [Deploy a Stack with HCP Terraform](/terraform/tutorials/cloud/stacks-deploy) tutorial.
Stacks have a built-in `identity_token` block that creates workload identity tokens, also known as JWT tokens. You can use these tokens to authenticate Stacks with Terraform providers securely.
This guide covers how to set up OIDC for Stacks using the `identity_token` block.
### Overview
The details of Stack authentication differ based on which cloud provider you are setting up, but the basic steps remain the same:
1. Set up the trust configuration between your cloud provider and HCP Terraform, which usually includes creating roles and policies for your cloud provider.
1. Add an `identity_token` block to your Stacks deployment file using the audience and roles you created in the previous step.
Your deployments can reference the value of the `identity_token` block to pass the trust relationship role to your Stacks operations.
### Configure trust configuration
In this example, you will set up an example trust policy with AWS. For examples of setting up trust policies with other providers, refer to our [repository of example configurations](https://github.com/hashicorp-guides/terraform-stacks-identity-tokens/tree/main).
We recommend using Terraform to create and configure the trust relationship and permissions for the cloud provider you want to authenticate with. Using the following Terraform configuration, [create a new workspace](/terraform/cloud-docs/workspaces/create) and configure the `aws_region`, `tf_organization`, `tf_project,` and `tf_stack` variables for your specific set up.
```hcl
# main.tf
variable "aws_region" {
type = string
description = "The AWS region to create the role in."
}
variable "tf_organization" {
type = string
description = "The name of the organization that this workspace and Stack live in."
}
variable "tf_project" {
type = string
description = "The name of the project that this workspace and Stack live in."
}
variable "tf_stack" {
type = string
description = "The name of the Stack you will you use this token in."
}
provider "aws" {
region = var.aws_region
}
resource "aws_iam_openid_connect_provider" "stacks_openid_provider" {
url = "https://app.terraform.io"
client_id_list = ["aws.workload.identity"]
# This is the thumbprint of https://app.terraform.io as of 2024/08/07
# Refer to "Adjust access of trust" to learn how to update this thumbprint
thumbprint_list = ["9e99a48a9960b14926bb7f3b02e22da2b0ab7280"]
}
resource "aws_iam_role" "stacks_role" {
name = "stacks-${var.tf_organization}-${var.tf_project}-${var.tf_stack}"
assume_role_policy = data.aws_iam_policy_document.stacks_role_policy.json
}
data "aws_iam_policy_document" "stacks_role_policy" {
statement {
effect = "Allow"
principals {
type = "Federated"
identifiers = [aws_iam_openid_connect_provider.stacks_openid_provider.arn]
}
actions = ["sts:AssumeRoleWithWebIdentity"]
condition {
test = "StringEquals"
variable = "app.terraform.io:aud"
values = ["aws.workload.identity"]
}
condition {
test = "StringLike"
variable = "app.terraform.io:sub"
# This value dictates which HCP Terraform organizations, projects,
# and stacks can assume the new role you are creating.
#
# You can widen access to an entire organization or project by
# tweaking the value below. You can also restrict access to specific
# deployments or operations. Refer to Configure trust for more information.
values = ["organization:${var.tf_organization}:project:${var.tf_project}:stack:${var.tf_stack}:*"]
}
}
}
# Now, you give the new role access to things you want to manage in your Stack.
#
# The policies below are too broad for a production use case, but you set them
# broadly for now to ensure this Stacks can do anything during development and
# testing. In practice, only give your Stack access to what it needs to manage.
resource "aws_iam_role_policy_attachment" "iam" {
role = aws_iam_role.stacks_role.name
policy_arn = "arn:aws:iam::aws:policy/IAMFullAccess"
}
resource "aws_iam_role_policy_attachment" "sudo" {
role = aws_iam_role.stacks_role.name
policy_arn = "arn:aws:iam::aws:policy/PowerUserAccess"
}
# Your workspace returns this output role, which you use to configure your
# deployments.
output "role_arn" {
value = aws_iam_role.stacks_role.arn
}
```
After setting up your workspace in HCP Terraform, perform a plan and apply operation. HCP Terraform will create your OpenID provider, policy, and role before outputting your new roles ARN with the `role_arn` output. Copy your new AWS ARN role because this is the value you use to configure your cloud provider with your Stack and HCP Terraform.
#### Adjust access of trust
Workload identity tokens contain useful metadata in their payloads, known as claims. Once a cloud platform verifies a token using HCP Terraforms public key, it can look at the identity token's claims to match it to the correct permissions or reject it.
You do not need to understand the full token specification or what every claim means, but you can use the claims to adjust your trust relationship.
Workload identity tokens commonly reference the following claims.
| Claim | Explanation |
| :---- | :---- |
| `jti` (JWT ID) | A unique identifier for each token, which is a UUID. |
| `iss` (issuer) | Full URL of the HCP Terraform instance that signed the token. For example, “https://app.terraform.io”. |
| `iat` (issued at) | Unix timestamp when the token was issued. May be required by certain relying parties. |
| `nbf` (not before) | Unix Timestamp when the token can start being used. Should be the same as `iat` for your purposes and may be required by certain relying parties. |
| `aud` (audience) | Intended audience for the token. For example, “api://AzureADTokenExchange” for Azure. |
| `exp` (expiration) | Unix timestamp based on the timeout of the operation phase that it was issued for. |
| `sub` (subject) | Fully qualified path to a Stack deployment, followed by the operation type:<br/>`organization:<organization_name>:project:<project_name>:stack:<stack_name>:deployment:my-deployment-name:operation:<operation_type>`<br/><br/>For example:<br/>`organization:My_Org:project:My_Project:stack:My_Stack:deployment:staging:operation:apply` |
You can further customize your tokens permissions using the following custom claims.
| Claim | Explanation |
| :---- | :---- |
| `terraform_operation` ("run phase") | The Terraform operation this token was issued for. For example, “plan” or “apply”. |
| `terraform_stack_deployment_name` | Name of the deployment that the operation is for. |
| `terraform_stack_id` (stack ID) | External ID of the Stack that the operation is for. |
| `terraform_stack_name` (stack name) | Name of the Stack that the operation is for. |
| `terraform_project_id` (project ID) | External ID of the project that the operation is taking place in. Useful if you want to use the same role across Stacks in a given project. |
| `terraform_project_name` (project name) | Name of the project that the operation is taking place in. |
| `terraform_organization_id` (organization ID) | External ID of the HCP Terraform organization that the operation is taking place in. Useful if you are in a large company that may have more than one organization or if you want to use the same role across your entire organization. |
| `terraform_organization_name` (organization name) | Name of the HCP Terraform organization that the operation is taking place in. |
| `terraform_plan_id` (plan ID) | External ID of the plan that this token is being used for creating or applying. This might be used to track down where a token has been leaked from or to block a specific token if it has been leaked. |
You can also update your configuration to use the current thumbprint for HCP Terraform by running the following command and removing the colons from the value it returns.
```shell-session
$ echo | openssl s_client -showcerts -servername app.terraform.io -connect app.terraform.io:443 2>/dev/null | openssl x509 -fingerprint -noout -sha1
sha1 Fingerprint=FD:88:23:AE:FB:96:13:28:A1:34:70:6D:C8:57:5A:17:0F:0B:B3:7C
```
### Configure HCP Terraform
Stacks use the [`identity_token` block](/terraform/language/stacks/reference/tfdeploy#identity_token-block-configuration) to define a JSON Web Token (JWT) for a specific deployment. This token enables OIDC-based authentication, allowing your Stack deployments to securely connect to cloud providers like AWS, Azure, and GCP.
When you define the `identity_token` block, you specify its audience. For example, the example Stack deployment configuration defines an `identity_token` block specifying the AWS audience.
```hcl
identity_token "aws" {
audience = ["aws.workload.identity"]
}
```
Once defined, you can reference an identity token in a deployment's input variables and reference that token in a providers configuration.
You also need to add your trust relationship, your role ARN, to configure your token with the trust relationship to authenticate AWS resources.
```hcl
# deployments.tfdeploy.hcl
identity_token "aws" {
audience = ["aws.workload.identity"]
}
deployment "development" {
inputs = {
role_arn = "<YOUR_ROLE_ARN>"
identity_token = identity_token.aws.jwt
}
}
```
Now, the deployments are authenticated with AWS and can pass the trust configuration to your Stacks providers for authentication.
```hcl
# variables.tfstack.hcl
variable "role_arn" {
type = string
}
variable "identity_token" {
type = string
ephemeral = true
}
# providers.tfstack.hcl
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.7.0"
}
}
provider "aws" "this" {
config {
region = var.region
assume_role_with_web_identity {
role_arn = var.aws_role
web_identity_token = var.aws_token
}
}
}
```
With this setup, each of your deployments pass the ARN of your trust relationship role and a JWT token generated by AWS each time you plan or apply your Stack. Each of your deployments uses their own role, configured with the specific permissions you require.
For more examples of setting up OIDC with different providers, refer to our [repository of example configurations](https://github.com/hashicorp-guides/terraform-stacks-identity-tokens/tree/main).
## Authenticate with existing credentials
You can use the `store` block to define key-value secrets in your deployment configuration and then access those values in your deployments.
You can use the `store` block to access credentials stored in an [HCP Terraform variable set](/terraform/cloud-docs/workspaces/variables/managing-variables#variable-sets). This example uses a `store` block with a variable set to access credentials stored in HCP Terraform. For more information about using `store` blocks, refer to the [Deployment configuration reference](/terraform/language/stacks/reference/tfdeploy).
Before writing any configuration, ensure your Stack can access the variable set you are targeting by allowing your project to access the set or making the set globally available.
Next, add a `store` block to your deployment configuration file to access your variable set. Once defined, your deployments can access your variable sets values.
```hcl
# deployments.tfdeploy.hcl
# Source environment secrets from your HCP Terraform variable set
store "varset" "tokens" {
id = "varset-<variables-set-id>"
category = "env"
}
# Access your variable set's value using your store and pass them into your
# deployment's inputs.
deployment "test" {
inputs = {
access_key = store.varset.tokens.AWS_ACCESS_KEY_ID
secret_key = store.varset.tokens.AWS_SECRET_ACCESS_KEY
session_token = store.varset.tokens.AWS_SESSION_TOKEN
}
}
```
For example, if your `test` deployment can use your `store` to access your variable sets keys, and therefore, your variable sets AWS provider credentials.
Your `test` deployment can define your AWS credentials as `inputs`, allowing your `providers` to access those credentials.
```hcl
# providers.tfstack.hcl
variable "access_key" {
description = "AWS access key"
type = string
ephemeral = true
}
variable "secret_key" {
description = "AWS sensitive secret key."
type = string
sensitive = true
ephemeral = true
}
variable "session_token" {
description = "AWS session token."
type = string
sensitive = true
ephemeral = true
}
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.7.0"
}
}
provider "aws" "this" {
config {
access_key = var.access_key
secret_key = var.secret_key
token = var.session_token
}
}
```
This example allows your `aws.this` provider to authenticate to AWS using the credentials from a variable set stored in HCP Terraform. For more information about using `store` blocks, refer to the [Deployment configuration reference](/terraform/language/stacks/reference/tfdeploy).