Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
185 changes: 185 additions & 0 deletions docs/azrepos-wif.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
# Azure Workload Identity Federation

Git Credential Manager supports [Workload Identity Federation][wif] for
authentication with Azure Repos. This document provides an overview of Workload
Identity Federation and how to use it with GCM.

## Overview

Workload Identity Federation allows a workload (such as a CI/CD pipeline, VM, or
container) to exchange a token from an external identity provider for a Microsoft
Entra ID access token — without needing to manage secrets like client secrets or
certificates.

This is especially useful in scenarios where:

- You want to avoid storing long-lived secrets.
- Your workload already has an identity token from another provider (e.g., GitHub
Actions OIDC, a Managed Identity, or a custom identity provider).
- You want to follow the principle of least privilege with short-lived,
automatically rotated credentials.

You can read more about Workload Identity Federation in the
[Microsoft Entra documentation][wif].

## How it works

When configured, GCM obtains a client assertion (a token from the external
identity provider) and exchanges it with Microsoft Entra ID for an access token
scoped to Azure DevOps. The exact mechanism for obtaining the client assertion
depends on the federation scenario you choose.

## Scenarios

GCM supports three federation scenarios:

### Generic

Use this scenario when you have a pre-obtained client assertion token from any
external identity provider. You provide the assertion directly and GCM exchanges
it for an access token.

**Required settings:**

Setting|Git Configuration|Environment Variable
-|-|-
Scenario|[`credential.azreposWorkloadFederation`][gcm-wif-config]|[`GCM_AZREPOS_WIF`][gcm-wif-env]
Client ID|[`credential.azreposWorkloadFederationClientId`][gcm-wif-clientid-config]|[`GCM_AZREPOS_WIF_CLIENTID`][gcm-wif-clientid-env]
Tenant ID|[`credential.azreposWorkloadFederationTenantId`][gcm-wif-tenantid-config]|[`GCM_AZREPOS_WIF_TENANTID`][gcm-wif-tenantid-env]
Assertion|[`credential.azreposWorkloadFederationAssertion`][gcm-wif-assertion-config]|[`GCM_AZREPOS_WIF_ASSERTION`][gcm-wif-assertion-env]

**Optional settings:**

Setting|Git Configuration|Environment Variable
-|-|-
Audience|[`credential.azreposWorkloadFederationAudience`][gcm-wif-audience-config]|[`GCM_AZREPOS_WIF_AUDIENCE`][gcm-wif-audience-env]

#### Example

```shell
git config --global credential.azreposWorkloadFederation generic
git config --global credential.azreposWorkloadFederationClientId "11111111-1111-1111-1111-111111111111"
git config --global credential.azreposWorkloadFederationTenantId "22222222-2222-2222-2222-222222222222"
git config --global credential.azreposWorkloadFederationAssertion "eyJhbGci..."
```

### Managed Identity

Use this scenario when your workload runs on an Azure resource that has a
[Managed Identity][az-mi] assigned. GCM will first request a token from the
Managed Identity for the configured audience, then exchange that token for an
Azure DevOps access token.

This is useful for Azure VMs, App Services, or other Azure resources that have a
Managed Identity but need to authenticate as a specific app registration with
a federated credential trust.

**Required settings:**

Setting|Git Configuration|Environment Variable
-|-|-
Scenario|[`credential.azreposWorkloadFederation`][gcm-wif-config]|[`GCM_AZREPOS_WIF`][gcm-wif-env]
Client ID|[`credential.azreposWorkloadFederationClientId`][gcm-wif-clientid-config]|[`GCM_AZREPOS_WIF_CLIENTID`][gcm-wif-clientid-env]
Tenant ID|[`credential.azreposWorkloadFederationTenantId`][gcm-wif-tenantid-config]|[`GCM_AZREPOS_WIF_TENANTID`][gcm-wif-tenantid-env]
Managed Identity|[`credential.azreposWorkloadFederationManagedIdentity`][gcm-wif-mi-config]|[`GCM_AZREPOS_WIF_MANAGEDIDENTITY`][gcm-wif-mi-env]

**Optional settings:**

Setting|Git Configuration|Environment Variable
-|-|-
Audience|[`credential.azreposWorkloadFederationAudience`][gcm-wif-audience-config]|[`GCM_AZREPOS_WIF_AUDIENCE`][gcm-wif-audience-env]

The Managed Identity value accepts the same formats as
[`credential.azreposManagedIdentity`][gcm-mi-config]:

Value|Description
-|-
`system`|System-Assigned Managed Identity
`[guid]`|User-Assigned Managed Identity with the specified client ID
`id://[guid]`|User-Assigned Managed Identity with the specified client ID
`resource://[guid]`|User-Assigned Managed Identity for the associated resource

#### Example

```shell
git config --global credential.azreposWorkloadFederation managedidentity
git config --global credential.azreposWorkloadFederationClientId "11111111-1111-1111-1111-111111111111"
git config --global credential.azreposWorkloadFederationTenantId "22222222-2222-2222-2222-222222222222"
git config --global credential.azreposWorkloadFederationManagedIdentity system
```

### GitHub Actions

Use this scenario when your workload runs in a GitHub Actions workflow. GCM will
automatically obtain an OIDC token from the GitHub Actions runtime and exchange
it for an Azure DevOps access token.

This scenario uses the `ACTIONS_ID_TOKEN_REQUEST_URL` and
`ACTIONS_ID_TOKEN_REQUEST_TOKEN` environment variables that GitHub Actions
automatically provides when a workflow has the `id-token: write` permission.

**Required settings:**

Setting|Git Configuration|Environment Variable
-|-|-
Scenario|[`credential.azreposWorkloadFederation`][gcm-wif-config]|[`GCM_AZREPOS_WIF`][gcm-wif-env]
Client ID|[`credential.azreposWorkloadFederationClientId`][gcm-wif-clientid-config]|[`GCM_AZREPOS_WIF_CLIENTID`][gcm-wif-clientid-env]
Tenant ID|[`credential.azreposWorkloadFederationTenantId`][gcm-wif-tenantid-config]|[`GCM_AZREPOS_WIF_TENANTID`][gcm-wif-tenantid-env]

**Optional settings:**

Setting|Git Configuration|Environment Variable
-|-|-
Audience|[`credential.azreposWorkloadFederationAudience`][gcm-wif-audience-config]|[`GCM_AZREPOS_WIF_AUDIENCE`][gcm-wif-audience-env]

No additional GCM settings are required — the GitHub Actions OIDC environment
variables are read automatically.

#### Prerequisites

1. An app registration in Microsoft Entra ID with a federated credential
configured to trust your GitHub repository.
2. The app registration must have the necessary permissions to access Azure
DevOps.
3. Your GitHub Actions workflow must have the `id-token: write` permission.

#### Example workflow

```yaml
permissions:
id-token: write
contents: read

steps:
- uses: actions/checkout@v4
env:
GCM_AZREPOS_WIF: githubactions
GCM_AZREPOS_WIF_CLIENTID: "11111111-1111-1111-1111-111111111111"
GCM_AZREPOS_WIF_TENANTID: "22222222-2222-2222-2222-222222222222"
```

## Audience

All scenarios accept an optional audience setting that controls the audience
claim in the federated token request. The default value is
`api://AzureADTokenExchange`, which is the standard audience for Microsoft Entra
ID workload identity federation.

You only need to change this if your federated credential trust is configured
with a custom audience.

[az-mi]: https://learn.microsoft.com/en-us/entra/identity/managed-identities-azure-resources/overview
[wif]: https://learn.microsoft.com/en-us/entra/workload-id/workload-identity-federation
[gcm-mi-config]: https://gh.io/gcm/config#credentialazreposmanagedidentity
[gcm-wif-config]: https://gh.io/gcm/config#credentialazreposworkloadfederation
[gcm-wif-clientid-config]: https://gh.io/gcm/config#credentialazreposworkloadfederationclientid
[gcm-wif-tenantid-config]: https://gh.io/gcm/config#credentialazreposworkloadfederationtenantid
[gcm-wif-audience-config]: https://gh.io/gcm/config#credentialazreposworkloadfederationaudience
[gcm-wif-assertion-config]: https://gh.io/gcm/config#credentialazreposworkloadfederationassertion
[gcm-wif-mi-config]: https://gh.io/gcm/config#credentialazreposworkloadfederationmanagedidentity
[gcm-wif-env]: https://gh.io/gcm/env#GCM_AZREPOS_WIF
[gcm-wif-clientid-env]: https://gh.io/gcm/env#GCM_AZREPOS_WIF_CLIENTID
[gcm-wif-tenantid-env]: https://gh.io/gcm/env#GCM_AZREPOS_WIF_TENANTID
[gcm-wif-audience-env]: https://gh.io/gcm/env#GCM_AZREPOS_WIF_AUDIENCE
[gcm-wif-assertion-env]: https://gh.io/gcm/env#GCM_AZREPOS_WIF_ASSERTION
[gcm-wif-mi-env]: https://gh.io/gcm/env#GCM_AZREPOS_WIF_MANAGEDIDENTITY
146 changes: 146 additions & 0 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -884,6 +884,138 @@ git config --global credential.azreposManagedIdentity "id://11111111-1111-1111-1

---

### credential.azreposWorkloadFederation

Use [Workload Identity Federation][wif] to authenticate with Azure Repos.

The value specifies the federation scenario to use for obtaining a client
assertion to exchange for an access token.

You must also set the following companion settings:

- [credential.azreposWorkloadFederationClientId][credential-azrepos-wif-clientid]
- [credential.azreposWorkloadFederationTenantId][credential-azrepos-wif-tenantid]

Depending on the scenario, additional settings may be required.

Value|Description
-|-
`generic`|Use a user-supplied client assertion ([credential.azreposWorkloadFederationAssertion][credential-azrepos-wif-assertion])
`managedidentity`|Use a [Managed Identity][managed-identity] to obtain the federated token ([credential.azreposWorkloadFederationManagedIdentity][credential-azrepos-wif-managedidentity])
`githubactions`|Automatically obtain an OIDC token from GitHub Actions

For more information about workload identity federation, see the
[conceptual documentation][azrepos-wif-doc] and the Azure DevOps
[documentation][azrepos-sp-mid].

#### Example

```shell
git config --global credential.azreposWorkloadFederation githubactions
```

**Also see: [GCM_AZREPOS_WIF][gcm-azrepos-wif]**

---

### credential.azreposWorkloadFederationClientId

The client ID of the app registration / service principal to request an access
token for when using [Workload Identity Federation][wif] with
[credential.azreposWorkloadFederation][credential-azrepos-wif].

#### Example

```shell
git config --global credential.azreposWorkloadFederationClientId "11111111-1111-1111-1111-111111111111"
```

**Also see: [GCM_AZREPOS_WIF_CLIENTID][gcm-azrepos-wif-clientid]**

---

### credential.azreposWorkloadFederationTenantId

The tenant ID of the app registration / service principal to request an access
token for when using [Workload Identity Federation][wif] with
[credential.azreposWorkloadFederation][credential-azrepos-wif].

#### Example

```shell
git config --global credential.azreposWorkloadFederationTenantId "22222222-2222-2222-2222-222222222222"
```

**Also see: [GCM_AZREPOS_WIF_TENANTID][gcm-azrepos-wif-tenantid]**

---

### credential.azreposWorkloadFederationAudience

The audience to use when requesting the federated token for
[Workload Identity Federation][wif] with
[credential.azreposWorkloadFederation][credential-azrepos-wif].

Defaults to `api://AzureADTokenExchange`.

#### Example

```shell
git config --global credential.azreposWorkloadFederationAudience "api://AzureADTokenExchange"
```

**Also see: [GCM_AZREPOS_WIF_AUDIENCE][gcm-azrepos-wif-audience]**

---

### credential.azreposWorkloadFederationAssertion

Specifies the client assertion token to use with the `generic`
[Workload Identity Federation][wif] scenario
([credential.azreposWorkloadFederation][credential-azrepos-wif]).

This setting is required when `credential.azreposWorkloadFederation` is set to
`generic`.

#### Example

```shell
git config --global credential.azreposWorkloadFederationAssertion "eyJhbGci..."
```

**Also see: [GCM_AZREPOS_WIF_ASSERTION][gcm-azrepos-wif-assertion]**

---

### credential.azreposWorkloadFederationManagedIdentity

Specifies the [Managed Identity][managed-identity] to use to obtain a federated
token for the `managedidentity` [Workload Identity Federation][wif] scenario
([credential.azreposWorkloadFederation][credential-azrepos-wif]).

This setting is required when `credential.azreposWorkloadFederation` is set to
`managedidentity`.

The value accepts the same formats as
[credential.azreposManagedIdentity](#credentialazreposmanagedidentity).

Value|Description
-|-
`system`|System-Assigned Managed Identity
`[guid]`|User-Assigned Managed Identity with the specified client ID
`id://[guid]`|User-Assigned Managed Identity with the specified client ID
`resource://[guid]`|User-Assigned Managed Identity for the associated resource

#### Example

```shell
git config --global credential.azreposWorkloadFederationManagedIdentity system
```

**Also see: [GCM_AZREPOS_WIF_MANAGEDIDENTITY][gcm-azrepos-wif-managedidentity]**

---

### credential.azreposServicePrincipal

Specify the client and tenant IDs of a [service principal][service-principal]
Expand Down Expand Up @@ -1048,6 +1180,12 @@ Defaults to disabled.
[gcm-autodetect-timeout]: environment.md#GCM_AUTODETECT_TIMEOUT
[gcm-azrepos-credentialtype]: environment.md#GCM_AZREPOS_CREDENTIALTYPE
[gcm-azrepos-credentialmanagedidentity]: environment.md#GCM_AZREPOS_MANAGEDIDENTITY
[gcm-azrepos-wif]: environment.md#GCM_AZREPOS_WIF
[gcm-azrepos-wif-clientid]: environment.md#GCM_AZREPOS_WIF_CLIENTID
[gcm-azrepos-wif-tenantid]: environment.md#GCM_AZREPOS_WIF_TENANTID
[gcm-azrepos-wif-audience]: environment.md#GCM_AZREPOS_WIF_AUDIENCE
[gcm-azrepos-wif-assertion]: environment.md#GCM_AZREPOS_WIF_ASSERTION
[gcm-azrepos-wif-managedidentity]: environment.md#GCM_AZREPOS_WIF_MANAGEDIDENTITY
[gcm-bitbucket-always-refresh-credentials]: environment.md#GCM_BITBUCKET_ALWAYS_REFRESH_CREDENTIALS
[gcm-bitbucket-authmodes]: environment.md#GCM_BITBUCKET_AUTHMODES
[gcm-credential-cache-options]: environment.md#GCM_CREDENTIAL_CACHE_OPTIONS
Expand Down Expand Up @@ -1077,6 +1215,7 @@ Defaults to disabled.
[autodetect]: autodetect.md
[libsecret]: https://wiki.gnome.org/Projects/Libsecret
[managed-identity]: https://docs.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/overview
[wif]: https://learn.microsoft.com/en-us/entra/workload-id/workload-identity-federation
[provider-migrate]: migration.md#gcm_authority
[cache-options]: https://git-scm.com/docs/git-credential-cache#_options
[pass]: https://www.passwordstore.org/
Expand All @@ -1090,6 +1229,13 @@ Defaults to disabled.
[wam]: windows-broker.md
[service-principal]: https://docs.microsoft.com/en-us/azure/active-directory/develop/app-objects-and-service-principals
[azrepos-sp-mid]: https://learn.microsoft.com/en-us/azure/devops/integrate/get-started/authentication/service-principal-managed-identity
[azrepos-wif-doc]: azrepos-wif.md
[credential-azrepos-wif]: #credentialazreposworkloadfederation
[credential-azrepos-wif-clientid]: #credentialazreposworkloadfederationclientid
[credential-azrepos-wif-tenantid]: #credentialazreposworkloadfederationtenantid
[credential-azrepos-wif-audience]: #credentialazreposworkloadfederationaudience
[credential-azrepos-wif-assertion]: #credentialazreposworkloadfederationassertion
[credential-azrepos-wif-managedidentity]: #credentialazreposworkloadfederationmanagedidentity
[credential-azrepos-sp]: #credentialazreposserviceprincipal
[credential-azrepos-sp-secret]: #credentialazreposserviceprincipalsecret
[credential-azrepos-sp-cert-thumbprint]: #credentialazreposserviceprincipalcertificatethumbprint
Expand Down
Loading
Loading