Terraform
Configure dynamic credentials for Azure in module testing
You can use HCP Terraform's native OpenID Connect integration with Microsoft Azure to get dynamic, short-lived credentials for module test runs. This approach uses Azure AD federated identity credentials to authenticate without storing static service principal secrets.
Requirements
You need the following to configure dynamic credentials for Azure in module testing:
- An Azure subscription with permissions to create and configure Azure AD applications
- An HCP Terraform organization with module testing enabled
- A private registry module with testing configured
- Permissions in HCP Terraform to modify registry module test settings
- The
azCLI (optional, for command-line configuration)
Configure Azure
Register an Azure AD application
Create an Azure AD application that will represent your module tests:
- Sign in to the Azure Portal and navigate to Azure Active Directory
- Click App registrations in the left menu
- Click New registration
- Enter a name (e.g.,
terraform-module-tests) - For Supported account types, select Accounts in this organizational directory only
- Leave Redirect URI blank
- Click Register
Using the Azure CLI:
az ad app create --display-name "terraform-module-tests"
Note the Application (client) ID from the app's overview page. You'll need this for HCP Terraform configuration.
Create a service principal
Create a service principal for the application:
- In your app registration, note the Application (client) ID
- Navigate to Azure Active Directory > Enterprise applications
- Find your application and note the Object ID (this is the service principal's object ID)
Alternatively, create the service principal using the Azure CLI:
az ad sp create --id <APPLICATION_CLIENT_ID>
Replace <APPLICATION_CLIENT_ID> with your application's client ID.
Add federated identity credentials
Configure federated identity credentials to trust HCP Terraform's OIDC tokens:
- In your app registration, navigate to Certificates & secrets
- Click the Federated credentials tab
- Click Add credential
- Select Other issuer as the federated credential scenario
- Enter the following details:
- Issuer:
https://app.terraform.io(orhttps://<TFE_HOSTNAME>for Terraform Enterprise) - Subject identifier: Enter a pattern that matches your module tests, for example:
- For all modules:
organization:my-org:module:*:operation:test_run - For specific module:
organization:my-org:module:terraform-azurerm-network:operation:test_run
- For all modules:
- Audience:
azure.workload.identity - Name: Enter a descriptive name (e.g.,
terraform-module-tests)
- Issuer:
- Click Add
Using the Azure CLI:
az ad app federated-credential create \
--id <APPLICATION_CLIENT_ID> \
--parameters '{
"name": "terraform-module-tests",
"issuer": "https://app.terraform.io",
"subject": "organization:my-org:module:*:operation:test_run",
"audiences": ["azure.workload.identity"]
}'
Important: The subject identifier must match the format of HCP Terraform's subject claim for module tests: organization:{ORGANIZATION_NAME}:module:{MODULE_NAME}:operation:test_run. Use wildcards (*) to match multiple modules.
Multiple federated credentials for granular control
You can create multiple federated credentials with different subject patterns to provide granular access:
Allow specific module:
{
"name": "vpc-module-tests",
"issuer": "https://app.terraform.io",
"subject": "organization:my-org:module:terraform-azurerm-network:operation:test_run",
"audiences": ["azure.workload.identity"]
}
Allow all Azure modules:
{
"name": "azurerm-module-tests",
"issuer": "https://app.terraform.io",
"subject": "organization:my-org:module:terraform-azurerm-*:operation:test_run",
"audiences": ["azure.workload.identity"]
}
Assign permissions
Grant the service principal appropriate permissions for your tests:
- Navigate to the Azure resource or scope you want to grant access to (subscription, resource group, or resource)
- Click Access control (IAM)
- Click Add > Add role assignment
- Select an appropriate role (see permissions recommendations)
- Click Next
- For Assign access to, select User, group, or service principal
- Click Select members and search for your application name
- Select your application and click Select
- Click Review + assign
Using the Azure CLI (for subscription-level access):
az role assignment create \
--assignee <SERVICE_PRINCIPAL_OBJECT_ID> \
--role "Contributor" \
--scope "/subscriptions/<SUBSCRIPTION_ID>"
Replace <SERVICE_PRINCIPAL_OBJECT_ID> with your service principal's object ID and <SUBSCRIPTION_ID> with your Azure subscription ID.
Configure HCP Terraform
After configuring Azure, configure your registry module's test configuration to use dynamic credentials.
Gather required information
You'll need:
- Tenant ID: Found in Azure Active Directory > Overview
- Client ID: The Application (client) ID from your app registration
- Subscription ID: Found in Subscriptions in the Azure Portal
To get these values using the Azure CLI:
# Get tenant ID
az account show --query tenantId --output tsv
# Get subscription ID
az account show --query id --output tsv
# Client ID is from your app registration (noted earlier)
Configure through the UI
- Navigate to your private registry module in HCP Terraform
- Click Tests in the module navigation
- Click Configuration or Settings
- In the Dynamic Credentials section, toggle Enable dynamic credentials
- Select Azure as the provider
- Enter the Tenant ID
- Enter the Client ID (Application ID)
- Enter the Subscription ID
- (Optional) Set a custom audience if you configured a different audience in your federated credentials
- Click Save configuration
Configure through the API
You can also configure dynamic credentials using the Test Configuration API:
curl \
--header "Authorization: Bearer $TOKEN" \
--header "Content-Type: application/vnd.api+json" \
--request PATCH \
--data @payload.json \
https://app.terraform.io/api/v2/registry-modules/:registry_name/:namespace/:name/:provider/test-configuration
With the following payload.json:
{
"data": {
"type": "test-configurations",
"attributes": {
"oidc-enabled": true,
"oidc-provider": "azure",
"oidc-configuration": {
"tenant-id": "00000000-0000-0000-0000-000000000000",
"client-id": "11111111-1111-1111-1111-111111111111",
"subscription-id": "22222222-2222-2222-2222-222222222222",
"audience": "azure.workload.identity"
}
}
}
}
Environment variables
When you configure dynamic credentials for Azure, HCP Terraform automatically sets the following environment variables in your module test runs:
| Variable | Description | Example Value |
|---|---|---|
TFC_AZURE_PROVIDER_AUTH | Signals the Azure provider to use OIDC authentication | true |
TFC_AZURE_RUN_CLIENT_ID | The Azure AD application (client) ID | 11111111-1111-1111-1111-111111111111 |
TFC_AZURE_RUN_TENANT_ID | The Azure AD tenant ID | 00000000-0000-0000-0000-000000000000 |
TFC_AZURE_RUN_SUBSCRIPTION_ID | The Azure subscription ID | 22222222-2222-2222-2222-222222222222 |
TFC_AZURE_WORKLOAD_IDENTITY_AUDIENCE | The audience claim for OIDC tokens | azure.workload.identity |
TFC_OIDC_ISSUER_URL | The OIDC issuer URL | https://app.terraform.io |
TFC_OIDC_AUDIENCE | The OIDC audience | azure.workload.identity |
The Azure Terraform provider (azurerm version 3.85.0 and later) automatically uses these environment variables to authenticate with Azure. You don't need to configure the provider block explicitly.
Permissions recommendations
The permissions you grant to your service principal depend on what your module tests need to do. Follow the principle of least privilege.
Read-only testing
For modules that only need to validate configurations without creating resources, use the Reader role:
az role assignment create \
--assignee <SERVICE_PRINCIPAL_OBJECT_ID> \
--role "Reader" \
--scope "/subscriptions/<SUBSCRIPTION_ID>"
Resource creation for testing
For modules that create test resources, consider these built-in roles:
Network resources:
az role assignment create \
--assignee <SERVICE_PRINCIPAL_OBJECT_ID> \
--role "Network Contributor" \
--scope "/subscriptions/<SUBSCRIPTION_ID>/resourceGroups/<RESOURCE_GROUP>"
Compute resources:
az role assignment create \
--assignee <SERVICE_PRINCIPAL_OBJECT_ID> \
--role "Virtual Machine Contributor" \
--scope "/subscriptions/<SUBSCRIPTION_ID>/resourceGroups/<RESOURCE_GROUP>"
Storage resources:
az role assignment create \
--assignee <SERVICE_PRINCIPAL_OBJECT_ID> \
--role "Storage Account Contributor" \
--scope "/subscriptions/<SUBSCRIPTION_ID>/resourceGroups/<RESOURCE_GROUP>"
Custom roles for specific permissions
For more granular control, create a custom role with only the required permissions:
az role definition create --role-definition '{
"Name": "Module Test Role",
"Description": "Custom role for module testing",
"Actions": [
"Microsoft.Network/virtualNetworks/read",
"Microsoft.Network/virtualNetworks/write",
"Microsoft.Network/virtualNetworks/delete",
"Microsoft.Compute/virtualMachines/read"
],
"AssignableScopes": ["/subscriptions/<SUBSCRIPTION_ID>"]
}'
az role assignment create \
--assignee <SERVICE_PRINCIPAL_OBJECT_ID> \
--role "Module Test Role" \
--scope "/subscriptions/<SUBSCRIPTION_ID>"
Tip: Scope role assignments to specific resource groups used for testing, rather than the entire subscription. This limits the blast radius if credentials are compromised.
Verify the configuration
After configuring both Azure and HCP Terraform, verify the setup by running a test:
- Navigate to your module in HCP Terraform
- Go to the Tests tab
- Click Start Test Run or trigger a test through your VCS
- Monitor the test run logs for successful authentication
If authentication succeeds, you'll see log output indicating the Azure provider authenticated using the OIDC token. If it fails, check the troubleshooting section.
Troubleshooting
Error: "No valid credential sources found"
This error indicates the Azure provider cannot find credentials. Check:
- The Azure provider (azurerm) version is 3.85.0 or later
- Dynamic credentials are enabled in the test configuration
- The tenant ID, client ID, and subscription ID are correct
- The
TFC_AZURE_PROVIDER_AUTHenvironment variable is set totrue
Error: "AADSTS70021: No matching federated identity record found"
The federated identity credential doesn't match the token's subject claim. Verify:
- The subject identifier in the federated credential matches your organization name and module name format
- The organization name in the subject matches your HCP Terraform organization
- Wildcards are used correctly (e.g.,
organization:my-org:module:*:operation:test_run) - The issuer URL matches exactly (no trailing slash)
To debug, check the token's subject claim format. For module tests, it should be:
organization:my-org:module:terraform-azurerm-network:operation:test_run
Error: "AADSTS50107: The requested federation realm object does not exist"
The federated credential issuer doesn't match. Check:
- The issuer is
https://app.terraform.io(for HCP Terraform) without a trailing slash - For Terraform Enterprise, the issuer matches your TFE hostname exactly
- The issuer uses
https://, nothttp://
Error: "AADSTS700025: Invalid audience"
The token's audience doesn't match the federated credential. Verify:
- The audience in the federated credential is
azure.workload.identity - The test configuration specifies the same audience
- Custom audiences match on both sides
Error: "Authorization failed" or "insufficient privileges"
The service principal lacks necessary permissions. Check:
- The service principal has appropriate role assignments
- Role assignments are at the correct scope (subscription, resource group, or resource)
- Custom role definitions include all required actions
- Azure policies aren't blocking the service principal
- The subscription is not disabled or in a restricted state
Debugging federated credentials
To verify your federated credential configuration:
- Navigate to Azure Active Directory > App registrations
- Select your application
- Go to Certificates & secrets > Federated credentials
- Review each credential's issuer, subject, and audience
You can also use the Azure CLI:
az ad app federated-credential list --id <APPLICATION_CLIENT_ID>
View authentication logs
Enable and review Azure AD sign-in logs:
- Navigate to Azure Active Directory > Sign-in logs
- Filter by your application name
- Review failed authentication attempts for details
- Check the failure reason and additional details
Next steps
- Learn about dynamic credentials for module testing
- Configure dynamic credentials for other providers:
- Review workload identity token specifications
- Set up policy enforcement to require OIDC for tests