Earlier this year I wrote a blog post where I explained how to set up flexible federated identity credentials for an application on Azure.
On November 18 2025, version 3.7.0 of the Azure AD (also known as Entra ID) provider for Terraform was released, including a new azuread_application_flexible_federated_identity_credential resource.
Apart from the new way of provisioning flexible federated identity credentials using the Azure AD provider for Terraform, you can also use the Microsoft Graph provider. The Microsoft Graph provider is similar to the Az API provider that directly targets the Azure API in a less abstracted way than the Azure RM provider. With the Microsoft Graph provider you can directly target the underlying Graph API.
In this blog post I want to go through these two alternatives (new resources in the Azure AD provider and using the Microsoft Graph provider). I will set these up in the context of HCP Terraform (as in my older blog post on this topic).
Using the Azure AD (Entra ID) provider#
I need to configure our Terraform code to use three providers:
- Azure AD (Entra ID) for creating an app registration, a service principal, and the flexible federated identity credentials.
- Azure RM for configuring RBAC permissions to my Azure subscription for the service principal.
- TFE (HCP Terraform) for configuring a workspace with the required variables for the authentication to work.
In my providers.tf file I add the following content:
terraform {
required_providers {
azuread = {
source = "hashicorp/azuread"
version = "3.7.0"
}
azurerm = {
source = "hashicorp/azurerm"
version = "4.53.0"
}
tfe = {
source = "hashicorp/tfe"
version = "0.71.0"
}
}
}
provider "azurerm" {
features {}
subscription_id = var.azure_subscription_id
}
provider "tfe" {
organization = var.hcp_terraform_organization
}
The two variables I have used to configure the Azure provider and TFE provider are configured in variables.tf:
variable "azure_subscription_id" {
type = string
description = "Azure subscription ID"
}
variable "hcp_terraform_organization" {
type = string
description = "HCP Terraform organization name"
}
I create an azure.tf file where I will place all Azure and Entra ID resources. I create an application with a service principal, and I give the service principal the Contributor role on my subscription:
resource "azuread_application" "hcp_terraform" {
display_name = "hcp-terraform-workspace"
}
resource "azuread_service_principal" "hcp_terraform" {
client_id = azuread_application.hcp_terraform.client_id
}
data "azurerm_subscription" "current" {}
resource "azurerm_role_assignment" "contributor" {
scope = data.azurerm_subscription.current.id
principal_id = azuread_service_principal.hcp_terraform.object_id
role_definition_name = "Contributor"
}
Before I add the flexible federated identity credential I need to configure the HCP Terraform resources. I create a tfe.tf file and add a project, a workspace, and a variable set with required variables:
data "tfe_organization" "current" {}
#---------------------------------------------------------------------
# PROJECT
#---------------------------------------------------------------------
resource "tfe_project" "default" {
name = "mattias-engineer-demo"
}
#---------------------------------------------------------------------
# WORKSPACE
#---------------------------------------------------------------------
resource "tfe_workspace" "default" {
name = "workspace-team-1"
project_id = tfe_project.default.id
}
#---------------------------------------------------------------------
# VARIABLE SET
#---------------------------------------------------------------------
resource "tfe_variable_set" "azure" {
name = "AZURE"
}
resource "tfe_workspace_variable_set" "azure" {
variable_set_id = tfe_variable_set.azure.id
workspace_id = tfe_workspace.default.id
}
resource "tfe_variable" "tfc_azure_provider_auth" {
key = "TFC_AZURE_PROVIDER_AUTH"
value = "true"
category = "env"
variable_set_id = tfe_variable_set.azure.id
}
resource "tfe_variable" "tfc_azure_run_client_id" {
key = "TFC_AZURE_RUN_CLIENT_ID"
value = azuread_service_principal.hcp_terraform.client_id
category = "env"
variable_set_id = tfe_variable_set.azure.id
}
resource "tfe_variable" "arm_subscription_id" {
key = "ARM_SUBSCRIPTION_ID"
value = data.azurerm_subscription.current.subscription_id
category = "env"
variable_set_id = tfe_variable_set.azure.id
}
resource "tfe_variable" "arm_tenant_id" {
key = "ARM_TENANT_ID"
value = data.azurerm_subscription.current.tenant_id
category = "env"
variable_set_id = tfe_variable_set.azure.id
}
The variables in the variables set are:
TFC_AZURE_PROVIDER_AUTHwith the valuetruetells HCP Terraform to use workload identity federation with Azure.TFC_AZURE_RUN_CLIENT_IDis the service principal client ID to use for authentication.ARM_SUBSCRIPTION_IDis the Azure subscription ID (could be set in the code instead)ARM_TENANT_IDis the Entra ID tenant ID where the service principal exists.
All of these variables are used for Azure RM provider configuration.
With the HCP Terraform resources in place I can configure the flexible federated identity credential resource in azure.tf:
# ... previous code omitted
locals {
sub = join(":", [
"organization",
data.tfe_organization.current.name,
"project",
tfe_project.default.name,
"workspace",
tfe_workspace.default.name,
"*"
])
}
resource "azuread_application_flexible_federated_identity_credential" "workspace" {
application_id = azuread_application.hcp_terraform.id
claims_matching_expression = "claims['sub'] matches '${local.sub}'"
display_name = "hcp-terraform-workspace"
description = "Provision resources from HCP Terraform"
audience = "api://AzureADTokenExchange"
issuer = "https://app.terraform.io"
}
I provision these resources (running through terraform init, terraform apply -auto-approve) and afterwards I can provision resources to Azure from the HCP Terraform workspace without using any explicit credentials.
Using the Microsoft Graph provider#
In this next example I will use the Microsoft Graph provider to set up the flexible federated identity credential.
Most of the code from the previous section is still valid for this variant. There are two changes I need to do:
The first change is to add the Microsoft Graph provider to the required_providers block:
terraform {
# ...
required_providers {
# ...
msgraph = {
source = "microsoft/msgraph"
version = "~> 0.2.0"
}
}
}
The next change is to add a msgraph_resource resource to set up the flexible federated identity credential:
resource "msgraph_resource" "flexibile_federated_identity_credential" {
url = "applications/${azuread_application.hcp_terraform.object_id}/federatedIdentityCredentials"
api_version = "beta"
body = {
name = "hcp-terraform-workspace"
issuer = "https://app.terraform.io"
audiences = ["api://AzureADTokenExchange"]
claimsMatchingExpression = {
value = "claims['sub'] matches '${local.sub}'"
languageVersion = 1
}
}
}
It is clear that this resource is very low-level compared to the azuread_application_flexible_federated_identity_credential resource from the Azure AD provider. The msgraph_resource resource closely follows the Microsoft Graph API definition of this resource.
With these changes in place I can once again provision these resources (running through terraform init, terraform apply -auto-approve) and afterwards I can provision resources to Azure from the HCP Terraform workspace without using any explicit credentials.
Summary#
Flexible federated identity credentials allows for the use of expressions when matching the sub claim in the OIDC flow. This has been supported on AWS since a long time back, so it is great that Azure is also introducing the same feature. As far as I know this is still in beta, but hopefully it will be in GA sometime soon.
