The usecase
We need our HCP Terraform Workspace to deploy resources to Microsoft Azure without using secrets, tokens, passwords, or anything similar.
Challenging? Not really. We just need to configure OpenID Connect. Continue reading if you need details.
Prerequisites
Obviously, we need to obtain:
- the Azure subscription (with the Owner role access),
- the HCP Terraform Workspace,
- a GitLab (or any other supported by HCP Terraform VCS) project with the Terraform code. (However, the GitLab integration is slightly outside of the scope of this post.)
Let's pretend we have HCP Terraform workspace
It is crucial to know
- the name of the organization:
rokicool-tf
- the project:
dev-to
- the name of the workspace:
azure-automation-account-dev
We will use these identifiers later.
And imagine we have a new shiny Azure subscription:
We need to know the Azure subscription ID and the Tenant ID. If you are not sure if your subscription is located in the root management group or not, just open the Entra ID interface in the Azure Portal. The first thing you'll see will be the Tenant ID.
- Subscription ID
971307eb-329d-47a2-b3f2-d424f4da5461
- Tenant ID
86abb60f-b63e-475e-85dd-9fa6e1d9f754
Service Principal to represent HCP Terraform Workspace
Our HCP Terraform Workspace should have identity to access the Azure subscription to deploy/destroy resources.
Let's create one.
Azure portal, Entra ID, App Registrations, + New Registration...
Entering it's name... sp-azure-automation-account-deployer-tfc
And here it is:
The only significant part is...
- The Client ID
348c0fdc-b20f-4fe7-a79a-872068ff22fd
Give it a role!
The identity cannot do much (access Entra ID with read permissions) by default. You need to assign it a role on the necessary scope.
The details about the possible role and the correct scope are far beyond this post. So, let's say we want to give it Contributor on the scope of subscription.
Federated Credentials for the Service Principal
Everything before this point was a preparation. Now the magic comes!
HashiCorp provides a very comprehensive document Use dynamic credentials with the Azure provider which explains a lot. Especially Configure Microsoft Entra ID Application to Trust a Generic Issuer section.
However, it's outdated a little! We are going to use one flexible federated credential instead of two static ones (as the official document suggests).
First, we need to build a string that is called Subject identifier
. The template is
organization:<my-org-name>:project:<my-project-name>:workspace:<my-workspace-name>:run_phase:plan
In our example, the string will look like this:
organization:rokicool-tf:project:dev-to:workspace:azure-automation-account-dev:run_phase:plan
and...
organization:rokicool-tf:project:dev-to:workspace:azure-automation-account-dev:run_phase:apply
... for the second federated identity credentials.
But!
We are going to use Claims matching expression instead of the Explicit subject identifier!
Therefore, our string will look like this:
claims['sub'] matches 'organization:rokicool-tf:project:dev-to:workspace:azure-automation-account-dev:run_phase:*'
Do you see? It is an expression, and the "*" symbol matches both plan
and apply
phases!
The rest of the fields are described in the mentioned document:
- Federated credential scenario: Must be set to
Other issuer
- Issuer: The address of HCP Terraform (e.g.,
https://app.terraform.io
) - Name: A name for the federated credential, such as `tfc-azure-automation-account-dev'
- Audience:
api://AzureADTokenExchange
by default.
Let's put them in the correct place.
Portal - Entra ID - App registrations - search for you sp - Manage/Certificates & secrets - Federated credentials - +Add credential
Here is what you should see:
Believe me, I am tired too! But bear with me for one more step!
HCP Terraform Workspace Variables
The Azure and Entra ID sides are ready. The next thing is to define several variables for your HCP Terraform workspace to inform Terraform Cloud that you want it using OIDC.
But before doing this, I need to mention another caveat that HashiCorp mentions in their documentation.
Here is the quote:
Make sure that you’re passing values for the subscription_id and tenant_id arguments into the provider configuration block or setting the ARM_SUBSCRIPTION_ID and ARM_TENANT_ID variables in your workspace.
Make sure that you’re not setting values for client_id, use_oidc, or oidc_token in the provider or setting any of ARM_CLIENT_ID, ARM_USE_OIDC, ARM_OIDC_TOKEN.
So, simply speaking, your provider
block should look like this:
provider "azurerm" {
features {}tenant_id = var.tenant_id
subscription_id = var.subscription_id
}
(Unfortunately, dev.to stopped supporting my code block
, so I had to use quotes above.)
If it is, we are ready to set up the variables!
Name | Type | Value | Meaning |
---|---|---|---|
TFC_AZURE_PROVIDER_AUTH |
env |
true |
Enable OIDC authentication |
TFC_AZURE_RUN_CLIENT_ID |
env |
348c0fdc-b20f-4fe7-a79a-872068ff22fd |
The Client ID of the Service Principal you created earlier |
tenant_id |
terraform |
86abb60f-b63e-475e-85dd-9fa6e1d9f754 |
Entra ID Tenant ID, which you use |
subscription_id |
terraform |
971307eb-329d-47a2-b3f2-d424f4da5461 |
ID of the Azure subscription you use |
Here is how it looks within HCP Terraform Workspace interface:
And... Congrats! You have done it!
Now every push to your GitLab dev-tfc branch will initiate an HCP Terraform Workspace pipeline run, which will definitely deploy your resources.
And an unexpectedly nice thing... you will see an additional stage in your GitLab pipeline that will show the status of the HCP Terraform pipeline run.
What? You did not set up the VCS GitLab integration? Sorry, bro. Next time!
Results
That is how success looks on the HCP Terraform side:
And here is the resource in Azure:
Useful documents
Use dynamic credentials with the Azure provider
Flexible federated identity credentials (preview)
About identities and the services. For those with harmful intentions.
I am absolutely sure that knowledge of the IDs of Tenant, Subscription, and even Service Principal will not help to get access to this infrastructure.
Despite that, I usually delete the identities before publishing my post. So, don't bother.
Top comments (0)