Skip to content

Instantly share code, notes, and snippets.

@richeney
Last active January 22, 2024 05:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save richeney/ecfb6c87b662ac982b01767d3065ebaf to your computer and use it in GitHub Desktop.
Save richeney/ecfb6c87b662ac982b01767d3065ebaf to your computer and use it in GitHub Desktop.
Terraform Cloud

Using Terraform Cloud with Vault and OIDC

Requires jo

sudo apt update && sudo apt install jo -y

Create an example repo

https:/github.com/richenmey/terraform-cloud-example

Steps

Terraform Cloud https://app.terraform.io/session

Create an organization (azurecitadel)

Structure

  • Terraform Cloud
  • Organisation
  • Projects (Default Project)
  • Workspaces

Log in using the CLI

terraform login

Follow the prompts.

Screenshot.

Create a service principal

az ad sp create-for-rbac --name "terraform-cloud" --role Contributor --scope "/subscriptions/$(az account show --query id -otsv)"

Save the output.

Federate

audience api://AzureADTokenExchange

hostname app.terraform.io

issuer https://app.terraform.io

organization azurecitadel

project "Default Project"

workspace terraform-cloud-example

appId az ad sp list --filter "displayname eq 'terraform-cloud'" --query [0].appId -otsv

object-id az ad sp list --filter "displayname eq 'terraform-cloud'" --query [0].id -otsv

display_name terraform-cloud-example-plan terraform-cloud-example-apply

subject "organization:${organization}:project:${project}:workspace:${workspace}:run_phase:plan" "organization:${organization}:project:${project}:workspace:${workspace}:run_phase:apply"

e.g.

"organization:azurecitadel:project:Default Project:workspace:terraform-cloud-example:run_phase:plan" "organization:azurecitadel:project:Default Project:workspace:terraform-cloud-example:run_phase:apply"

Need both for the plan and apply steps, in cse you want to use different service principals with different roles.

organization="azurecitadel"
project="Default Project"
workspace="terraform-cloud-example"
desc="Terraform Cloud to Azure"
subid="organization:${organization}:project:${project}:workspace:${workspace}"
iss="https://app.terraform.io"
aud="api://AzureADTokenExchange"
appObjectId=$(az ad sp list --filter "displayname eq 'terraform-cloud'" --query [0].id -otsv)
planJson=$(jo name="$workspace-plan"\
  issuer=$iss \
  subject="$subid:run_phase:plan" \
  description="$desc (terraform plan)" \
  audiences=$(jo -a $aud))

applyJson=$(jo name="$workspace-apply"\
  issuer=$iss \
  subject="$subid:run_phase:apply" \
  description="$desc (terraform apply)" \
  audiences=$(jo -a $aud))
{
  "name":"${REPO_NAME}-pull-request",
  "issuer":"https://token.actions.githubusercontent.com",
  "subject":"repo:${REPO_OWNER}/${REPO_NAME}:refs:refs/heads/main",
  "description":"${REPO_OWNER} PR",
  "audiences":["api://AzureADTokenExchange"],
}
az rest --method POST \
        --uri https://graph.microsoft.com/beta/applications/${APP_OBJ_ID}/federatedIdentityCredentials \
        --headers Content-Type='application/json' \
        --body @body.json
az rest --method POST \
        --uri https://graph.microsoft.com/beta/applications/${APP_OBJ_ID}/federatedIdentityCredentials \
        --headers Content-Type='application/json' \
        --body @body.json

Variable set

Organization Settings | Variable sets

Apply to all workspaces (can be more selective later) Environment variables

appId=$(az ad sp list --filter "displayname eq 'terraform-cloud'" --query [0].appId -otsv)

Variable Value
TFC_AZURE_PROVIDER_AUTH true
TFC_AZURE_RUN_CLIENT_ID appId
ARM_TENANT_ID
ARM_SUBSCRIPTION_ID
ARM_CLIENT_ID appId

az account show --query tenantId -otsv az account show --query id -otsv az ad sp list --filter "displayname eq 'terraform-cloud'" --query [0].appId -otsv

Create a new workspace

terraform-cloud-example (same name for the project)

Add the cloud block in

terraform init

terraform init

This will initialise for CLI driven runs. There are other

Grab this output again with aha

Initializing Terraform Cloud...

Initializing provider plugins...
- Finding hashicorp/azurerm versions matching "~> 3.45.0"...
- Installing hashicorp/azurerm v3.45.0...
- Installed hashicorp/azurerm v3.45.0 (signed by HashiCorp)

Terraform has created a lock file .terraform.lock.hcl to record the provider
selections it made above. Include this file in your version control repository
so that Terraform can guarantee to make the same selections by default when
you run "terraform init" in the future.

Terraform Cloud has been successfully initialized!

You may now begin working with Terraform Cloud. Try running "terraform plan" to
see any changes that are required for your infrastructure.

If you ever set or change modules or Terraform Settings, run "terraform init"
again to reinitialize your working directory.

References

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment