Why are we moving from Azure Service Principal secrets to Federated Identity for GitLab CI/CD?

Storing Azure Service Principal (SP) secrets inside GitLab CI/CD pipelines was a common practice, particularly when you’re just getting started with a POC (Proof of Concept) or MVP. However, it’s no longer the most secure or efficient method as projects scale. The issues associated with managing Service Principal credentials in this way are significant and open up several vulnerabilities. It’s time to shift to a more secure approach — using Federated Identity credentials with GitLab CI/CD pipelines for Azure deployments.

There are several challenges when relying on static credentials, which include:

Credential Expiry and Manual Rotation

Service Principal secrets are static credentials that have an expiration date. When a Service Principal secret expires, the pipeline breaks until someone manually updates the secret. If the secret expires and isn’t updated on time, your CI/CD pipeline will fail. This results in downtime and deployment delays.

In addition, even if the secret is updated, there's always the risk of misconfiguration or human error during the update process. A simple mistake in copying or updating the secret can cause jobs to fail and disrupt the entire pipeline.

Federated Identity eliminates this risk by using dynamic, time-limited access tokens instead of static secrets. These tokens are automatically generated and rotated, removing the need for manual updates. They expire automatically after the job completes, meaning there's no need to manage or track expiration dates.

Key Leaks and Security Risks

Storing static Service Principal secrets in GitLab poses another serious security risk: key leaks. These credentials can accidentally be exposed in pipeline logs, version control, or even through misconfigurations. If a secret is exposed, anyone with access to the logs or repository can use it to access your Azure resources, leading to potential data breaches and unauthorized changes.

With Federated Identity, this problem is solved. GitLab doesn’t store any credentials. Instead, GitLab uses Federated Identity credentials to authenticate itself with Azure. GitLab generates an OIDC token for each pipeline job, which Azure trusts. Azure issues a time-limited access token, valid only for the job's duration. This means there’s nothing to expose, and no secrets are stored in the pipeline.

Manual Rotation Risks

Manually rotating Service Principal secrets is error-prone and creates extra overhead. Each time a secret is updated, someone has to remember to update it in GitLab’s CI/CD configuration. Missing this step leads to broken pipelines and manual intervention, which adds unnecessary complexity to the deployment process.

In short, with Federated Identity, GitLab requests an identity token automatically, and Azure issues an access token without requiring any secrets to be stored or manually rotated. The automated token management ensures that the process is seamless and error-free, reducing the chance of credential-related failures.

The More Secure Alternative: Federated Identity

Federated Identity is a more secure and efficient approach to managing credentials. Instead of relying on static Service Principal secrets, Federated Identity allows GitLab CI/CD jobs to authenticate via an identity token provided by Azure. This token is validated by Azure and used to issue a time-limited access token that allows the job to interact with Azure resources.

This eliminates the need for storing static credentials and managing their lifecycle. It provides a secure, automated way to authenticate and authorize GitLab CI/CD jobs for Azure deployments, without the risks associated with static credentials.

Key Benefits of Federated Identity for GitLab CI/CD

Here are the core benefits of using Federated Identity with GitLab CI/CD instead of Service Principal secrets:

  • No secrets in pipelines: Since the authentication uses dynamic tokens, there’s no need to store any credentials in GitLab.
  • Automatic token rotation: The tokens are automatically generated and expired, eliminating the need for manual credential management.
  • Increased security: Tokens are short-lived and scoped to the specific job, so even if a token were exposed, it would be useless once the job ends.
  • Simplified compliance: With no static secrets to manage, it’s easier to comply with security policies and audits.

Moving from Azure Service Principal secrets to Federated Identity for GitLab CI/CD deployments is a crucial step toward improving security and simplifying the management of Azure credentials. The risks associated with static credentials — such as expiry, manual rotation, and key leaks — are eliminated by Federated Identity, providing a modern, automated, and much more secure approach to managing authentication for Azure resources.

Understanding How Azure Federated Identity Works with GitLab OIDC Tokens

Now that we’ve established why Federated Identity is the modern and secure approach to managing Azure authentication in GitLab CI/CD pipelines, let’s break down how the Federated Identity process actually works with GitLab and Azure. Understanding this flow is key to appreciating the full benefits of the integration.

What is a Federated Identity Credential in Azure Entra ID?

A Federated Identity Credential is a mechanism within Azure Entra ID (formerly Azure AD) that allows external identity providers — in this case, GitLab — to authenticate and authorize access to Azure resources without the need for shared secrets or long-term credentials.

When an identity provider like GitLab is trusted by Azure, Azure Entra ID creates a Federated Identity Credential that allows the identity provider to issue time-limited tokens. These tokens grant access to Azure resources based on predefined roles and permissions. Instead of relying on a static Service Principal secret, GitLab acts as the identity provider, allowing Azure to issue tokens dynamically when needed.

How GitLab Generates an OIDC Token During Each CI/CD Job

When a pipeline job starts in GitLab CI/CD, the GitLab Runner automatically generates an OpenID Connect (OIDC) token. This token is used to authenticate the GitLab job to Azure.

Here’s how it works:

  1. The GitLab Runner generates an OIDC token at the start of the job.
  2. This token contains critical information such as the issuer, audience, and subject, which are necessary for Azure to validate the identity of the requesting job.
  3. The token is passed to Azure, where it is validated against the trust relationship established in Azure Entra ID between GitLab and Azure.
  4. If the token is valid, Azure issues an access token that the job can use to interact with Azure resources.

This entire process occurs automatically without the need for any credentials or secret management, making it seamless and secure.

How Azure Validates the GitLab Token and Issues a Time-Limited Access Token

When Azure receives the OIDC token from GitLab, it performs a series of steps to ensure the token is valid and can be trusted:

  1. Issuer: Azure checks that the token has been issued by a trusted identity provider — in this case, GitLab. This is determined by the Issuer field in the token.
  2. Audience: Azure verifies that the token is intended for its resources. The Audience claim in the token ensures that the token is not being misused for unauthorized purposes.
  3. Subject Claim: Azure also validates the Subject claim, which identifies the user or service represented by the token. This ensures that the correct GitLab job is being authenticated.

Once these checks are successful, Azure issues a time-limited access token. This token grants the GitLab job permission to perform specific actions on Azure resources based on the role-based access control (RBAC) set up in Azure.

Key OIDC Token Elements

Let’s take a closer look at the key elements in the OIDC token:

  • Issuer: This identifies who issued the token — in this case, GitLab. Azure checks that the issuer matches the expected identity provider.
  • Audience: The Audience claim specifies who the token is meant for — Azure in this case. This ensures that the token can only be used to access Azure resources.
  • Subject: The Subject claim identifies the entity that the token represents — typically the GitLab Runner or the CI/CD job itself.

These claims form the basis of the trust model between GitLab and Azure, ensuring that only authorized jobs and users can access Azure resources.

Trust Flow Diagram: GitLab → Azure

Here’s a simple flow to visualize how the trust process works:

GitLab Runner → GitLab OIDC Token → Azure App Registration → Azure Access Token → Azure APIs

  1. GitLab Runner generates an OIDC token.
  2. The OIDC token is sent to Azure, where it is validated by the Azure App Registration that represents GitLab as an identity provider.
  3. If the token is valid, Azure issues an access token that the GitLab job can use to interact with Azure APIs.
  4. This access token is time-limited and scoped to the resources specified, ensuring that access is strictly controlled.

By integrating Federated Identity with GitLab CI/CD, you get a streamlined, secure process for authenticating to Azure without needing to store or manage credentials. The OIDC token generated by GitLab for each CI/CD job ensures that the authentication is dynamic, secure, and temporary. Azure verifies the token, issues a time-limited access token, and grants the job the required permissions to interact with Azure resources.

This method is far more secure and efficient compared to traditional Service Principal secrets, ensuring smoother, more secure deployments in your CI/CD pipeline.

Configuring Azure to Trust GitLab as an External Identity Provider

To enable GitLab to authenticate to Azure using Federated Identity, we need to configure Azure to trust GitLab as an external identity provider. This allows GitLab to authenticate CI/CD jobs without relying on static secrets.

Step 1: Create a New Azure App Registration for GitLab

In the Azure Portal, we need to create a new Azure App Registration to represent GitLab.

  1. Navigate to Azure Active Directory.
  2. Click on App registrations and select New registration.
  3. Enter a name for the application (e.g., "GitLab OIDC Integration").
  4. Set Supported account types to Accounts in this organizational directory only (single tenant).
  5. After the registration, copy the Application (client) ID and Directory (tenant) ID for use in GitLab configuration.

Step 2: Assign the Required Permissions

Once the App Registration is created, we need to assign the minimum required permissions for GitLab to interact with Azure resources.

  1. Go to the App Registration you created.
  2. Under API permissions, click Add a permission.
  3. Select Azure Resource Manager (ARM) and assign the Contributor role to allow GitLab to deploy resources.
  4. This ensures GitLab will have access only to the necessary resource groups or subscriptions. Optionally, specify a more granular scope if needed.

Step 3: Configure Federated Identity Credentials

Next, we’ll set up the Federated Identity Credentials within Azure to establish a trust relationship between Azure and GitLab.

  1. Navigate to Azure Active Directory → Enterprise Applications.
  2. Select the GitLab App Registration and go to Federated Identity Credentials under Manage.
  3. Click on Add Credential to create a new Federated Identity Credential.
  4. In the Issuer URL field, enter the GitLab OIDC issuer URL (e.g., https://gitlab.com/oidc).
  5. Configure the Subject field to match GitLab’s job identity claims, which will be used to validate the identity of the job.
  6. Set the Audience to api://AzureADTokenExchange, which ensures the token is intended for Azure access.
  7. Save the Federated Identity Credential.

Step 4: Assign the App Registration a Limited Azure Role

After setting up the Federated Identity, we must assign the GitLab App Registration the appropriate role in Azure for resource access.

  1. In Azure Resource Manager, go to the Resource Group GitLab will be deploying to.
  2. Under Access control (IAM), click Add → Add role assignment.
  3. Select Contributor and assign the role to the GitLab App Registration for the desired resource group.
  4. This ensures that GitLab has only the necessary permissions to deploy resources to the specified group.

Setting Up GitLab CI/CD to Use Azure OIDC Credentials via Workload Identity Federation (WIF)

With Azure successfully configured to trust GitLab as an external identity provider via Federated Identity credentials, the next step is to integrate GitLab CI/CD with Azure using Workload Identity Federation (WIF). This enables GitLab pipelines to authenticate to Azure securely, without needing to store or rotate static credentials.

Step 1: Set Up GitLab Project-Level Variables

Before configuring the pipeline, we need to set up GitLab project-level variables to ensure the required Azure details are securely passed into the CI/CD pipeline.

GitLab Variables Setup:

  1. Go to your GitLab project.
  2. In the left sidebar, select Settings → CI / CD.
  3. Expand the Variables section and add the following variables:


    • ARM_CLIENT_ID: The Application (client) ID of the Azure App Registration you created earlier.
    • ARM_TENANT_ID: The Tenant ID of your Azure Active Directory.
    • ARM_SUBSCRIPTION_ID: The Subscription ID of the Azure account where the resources will be deployed.

These variables will be used in your pipeline to authenticate with Azure through Workload Identity Federation.

Step 2: Update the .gitlab-ci.yml File

Next, we need to modify the .gitlab-ci.yml file to request and use the OIDC token for authenticating GitLab CI/CD jobs to Azure. This is done using the GitLab CI_JOB_JWT_V2 variable, which provides the OIDC token for each CI/CD job.

Here’s how to configure the .gitlab-ci.yml file:

stages:
- init
- plan
- apply

# Azure Login and Initialization Stage
azure_login_and_init:
stage: init
tags:
- self-hosted
script:
- echo "Checking Azure CLI installation and session..."
- az account show || (echo "Azure login missing! Please run 'az login' manually." && exit 1)
- echo "Initializing Terraform..."
- terraform init

# Terraform Plan Stage
terraform_plan:
stage: plan
tags:
- self-hosted
script:
- echo "Planning Terraform changes..."
- terraform plan -out=tfplan

# Terraform Apply Stage
terraform_apply:
stage: apply
tags:
- self-hosted
when: manual
script:
- echo "Applying Terraform plan..."
- terraform apply tfplan

Key Elements in .gitlab-ci.yml:

  • az account show: This command ensures that the Azure CLI is authenticated using the Federated Identity credentials. If the job hasn't been authenticated, it will prompt for the authentication process.
  • terraform init: Initializes the Terraform project using the Azure provider.
  • terraform plan -out=tfplan: Prepares a plan for creating or modifying resources in Azure.
  • terraform apply tfplan: Applies the Terraform plan to deploy the resources to Azure.

Step 3: Use OIDC Token for Authentication

To authenticate with Azure using Workload Identity Federation, GitLab automatically generates an OIDC token for each pipeline job. Azure verifies this token and issues a time-limited access token to allow the pipeline to interact with Azure resources.

Azure CLI Login with OIDC Token:

The OIDC token (available as CI_JOB_JWT_V2) is automatically used by the Azure CLI for authentication. To ensure that Azure uses this token instead of static credentials, use the following command:

az login --service-principal --username $ARM_CLIENT_ID --tenant $ARM_TENANT_ID --federated-token $CI_JOB_JWT_V2

Here’s the breakdown:

  • --service-principal: This flag tells Azure that we are using an application (Service Principal) for authentication.
  • --username $ARM_CLIENT_ID: The Application (client) ID of the Azure App Registration.
  • --tenant $ARM_TENANT_ID: The Tenant ID of your Azure Active Directory.
  • --federated-token $CI_JOB_JWT_V2: The OIDC token passed from GitLab CI/CD to authenticate the job.

By using the OIDC token, Azure validates the job’s identity, issues a time-limited access token, and grants access to the Azure resources based on the permissions assigned to the GitLab App Registration.

Step 4: Configure Terraform to Use Azure OIDC Authentication

Now that GitLab is authenticated to Azure, we need to ensure that Terraform uses the generated access token for deploying resources to Azure.

In your Terraform configuration (main.tf), configure the Azure provider to automatically detect credentials from the environment variables:

terraform {
required_version = ">= 1.0.0"
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "~> 3.90.0"
}
}
}

provider "azurerm" {}

resource "azurerm_resource_group" "rg" {
name = "rg-terraform-demo"
location = "East US"
}

resource "azurerm_storage_account" "storage" {
name = "stterraformdemo01" # Must be globally unique
resource_group_name = azurerm_resource_group.rg.name
location = azurerm_resource_group.rg.location
account_tier = "Standard"
account_replication_type = "LRS"
}

This configuration allows Terraform to use the access token provided by Azure CLI (which was authenticated via the OIDC token).

Step 5: Run the GitLab Pipeline

Once the configuration is in place:

  1. Trigger the pipeline in GitLab.
  2. The GitLab Runner will generate the OIDC token for each job.
  3. Azure CLI will use this token to authenticate to Azure.
  4. Terraform will use the token to deploy resources to Azure, without needing any static credentials or secrets.

You should see the following steps in the pipeline logs:

Initialization of Terraform, which connects to Azure using the OIDC token.

Planning the Terraform changes.

Applying the Terraform plan to deploy Azure resources.

This process is fully automated, secure, and efficient. No secrets are stored in GitLab, and there’s no need for manual credential management.

By configuring GitLab CI/CD to use Azure Workload Identity Federation (WIF), GitLab jobs can securely authenticate to Azure without storing static Service Principal secrets. This approach uses OIDC tokens, which are time-limited and automatically managed, eliminating the risks associated with secret management. The setup ensures smoother, more secure deployments, with automated token generation and rotation, significantly improving both security and efficiency in your CI/CD pipeline.

Best Practices for Managing GitLab OIDC Federation Securely

As with any security configuration, implementing GitLab OIDC Federation securely requires thoughtful planning and adherence to best practices. While Federated Identity eliminates many of the risks associated with storing static credentials, it's still important to follow key security practices to ensure your authentication setup remains robust and compliant with security standards.

Scope Federated Access to the Minimum Necessary Resources

When configuring Federated Identity, it’s critical to limit access to only the resources necessary for the CI/CD pipeline. This is a core principle of the least privilege access model, which ensures that jobs only have access to the minimum required permissions.

By scoping federated access to specific resource groups or subscriptions, you reduce the risk of an attacker gaining access to more resources than necessary. Limiting the scope ensures that access is restricted to only the essential resources for deployment and reduces the attack surface.

Use GitLab’s Protected Environment Scopes for Sensitive Pipelines

For more sensitive deployments, use GitLab’s protected environment scopes to restrict access to critical pipelines. This adds an extra layer of protection to prevent unauthorized jobs from accessing sensitive environments.

By enabling protected environments in GitLab, only authorized users or jobs will be able to trigger pipelines for these environments, limiting the risk of unintended changes.

Monitor GitLab’s OIDC Usage Through Azure Sign-In Logs

One of the key advantages of Federated Identity is the ability to track and monitor access. Azure sign-in logs provide a valuable tool to audit the use of GitLab OIDC tokens and monitor which jobs are accessing Azure resources.

Monitoring Azure sign-in logs ensures that you have a traceable history of when and how GitLab jobs are accessing Azure resources. You can identify any unusual or unauthorized activities that could indicate potential security risks.

Avoid Using Blanket-Wide Wildcard Subject Claims

In your Federated Identity Credential setup, avoid using wildcard subject claims (e.g., trusting all GitLab pipelines without specifying any filtering). This can potentially open the door to unauthorized access if an attacker manages to inject a fake job.

Trusting all pipelines by default can expose Azure resources to unnecessary risks.

Tagging App Registrations and Federated Credentials for Auditing and Cleanup

As your organization’s cloud infrastructure grows, keeping track of App Registrations and Federated Credentials becomes crucial for auditability and maintenance.

Tagging your resources with clear and consistent labels allows for easy identification, management, and auditing. It also simplifies resource cleanup when credentials or configurations are no longer needed.

Following these best practices makes sure that your GitLab OIDC Federation setup with Azure remains secure, efficient, and compliant. Scoping federated access, periodically rotating Azure App Registrations, and using GitLab’s protected environments all contribute to a more secure and streamlined CI/CD pipeline.

Additionally, monitoring sign-in logs, avoiding wildcard subject claims, and maintaining proper tagging practices will further strengthen security and ensure compliance. By implementing these practices, organizations can mitigate the risks associated with credential management and maintain a more secure, automated CI/CD process.

Firefly Workspaces: Enhancing Your CI/CD Pipelines

Setting up Federated Identity for authentication in GitLab pipelines is a significant step forward for security. It removes the need to store credentials, ensuring that every authentication event is temporary and properly scoped. However, while this setup improves security, it also introduces complexity. Misconfigurations, such as incorrect roles, issuers, or missing permissions, can break a pipeline, making it difficult for DevOps teams to quickly identify and resolve issues.

While Federated Identity strengthens authentication, securing a CI/CD pipeline requires more than just identity federation. Pipelines also need continuous security enforcement, infrastructure visibility, and policy compliance. Even with Federated Identity in place, issues like misconfigurations, unintended changes, and overlooked security risks can still emerge. This is where Firefly steps in.

Firefly integrates directly into GitLab pipelines, enhancing Terraform workflows with real-time insights before any infrastructure changes are made. Rather than relying solely on terraform plan, Firefly visualizes the dependencies between infrastructure resources, helping teams understand exactly what will be created, modified, or destroyed before running terraform apply. This enhanced visibility reduces the risk of unexpected changes and ensures that the team makes informed decisions, leading to more stable deployments.

But Firefly goes beyond just visibility. It enforces security and policy compliance throughout the Terraform deployment process using shift-left security principles. By applying security checks early in the development lifecycle, Firefly enables teams to detect and address risks before they reach production. This proactive approach prevents surprises later in the process and ensures that infrastructure changes comply with both security and operational policies.

With Guardrails, Firefly introduces automated security and compliance checks directly into the CI/CD pipeline. These Guardrails act as pre-deployment checkpoints, ensuring that all Terraform deployments meet security requirements before they’re executed. Unlike traditional monitoring tools that merely alert teams after an issue has been detected, Firefly's Guardrails actively prevent misconfigurations and security vulnerabilities from reaching production.

However, just enforcing security isn't enough. In fast-paced DevOps environments, blocking a deployment due to policy violations can cause delays and slow down release cycles. Firefly solves this problem by offering AI-powered remediation, which helps teams resolve issues quickly and efficiently. When a Guardrail blocks a misconfiguration, Firefly uses AI to suggest actionable fixes. Instead of requiring engineers to manually investigate and troubleshoot, Firefly provides context-aware recommendations based on best practices. With just one click, teams can apply these AI-generated fixes, ensuring compliance without introducing delays in the deployment process.

Firefly ensures that your infrastructure remains secure and compliant without disrupting workflow efficiency. By preventing security incidents from happening in the first place, rather than reacting to them in production, teams can maintain smooth and secure deployments.

Firefly doesn't just enhance Terraform deployments - it transforms how security, compliance, and automation work together in modern DevOps pipelines. With full visibility into infrastructure changes, automated policy enforcement, and intelligent remediation, Firefly enables teams to scale confidently while maintaining a secure and efficient cloud environment.

To learn more about Firefly’s features, explore their docs and blogs, and try Firefly yourself to see how it enhances your DevOps workflows.