Skip to content

Commit 7698262

Browse files
committed
wif: add documentation for WIF
Signed-off-by: Matthew John Cheetham <mjcheetham@outlook.com>
1 parent 7dec9e9 commit 7698262

File tree

3 files changed

+511
-0
lines changed

3 files changed

+511
-0
lines changed

docs/azrepos-wif.md

Lines changed: 185 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,185 @@
1+
# Azure Workload Identity Federation
2+
3+
Git Credential Manager supports [Workload Identity Federation][wif] for
4+
authentication with Azure Repos. This document provides an overview of Workload
5+
Identity Federation and how to use it with GCM.
6+
7+
## Overview
8+
9+
Workload Identity Federation allows a workload (such as a CI/CD pipeline, VM, or
10+
container) to exchange a token from an external identity provider for a Microsoft
11+
Entra ID access token — without needing to manage secrets like client secrets or
12+
certificates.
13+
14+
This is especially useful in scenarios where:
15+
16+
- You want to avoid storing long-lived secrets.
17+
- Your workload already has an identity token from another provider (e.g., GitHub
18+
Actions OIDC, a Managed Identity, or a custom identity provider).
19+
- You want to follow the principle of least privilege with short-lived,
20+
automatically rotated credentials.
21+
22+
You can read more about Workload Identity Federation in the
23+
[Microsoft Entra documentation][wif].
24+
25+
## How it works
26+
27+
When configured, GCM obtains a client assertion (a token from the external
28+
identity provider) and exchanges it with Microsoft Entra ID for an access token
29+
scoped to Azure DevOps. The exact mechanism for obtaining the client assertion
30+
depends on the federation scenario you choose.
31+
32+
## Scenarios
33+
34+
GCM supports three federation scenarios:
35+
36+
### Generic
37+
38+
Use this scenario when you have a pre-obtained client assertion token from any
39+
external identity provider. You provide the assertion directly and GCM exchanges
40+
it for an access token.
41+
42+
**Required settings:**
43+
44+
Setting|Git Configuration|Environment Variable
45+
-|-|-
46+
Scenario|[`credential.azreposWorkloadFederation`][gcm-wif-config]|[`GCM_AZREPOS_WIF`][gcm-wif-env]
47+
Client ID|[`credential.azreposWorkloadFederationClientId`][gcm-wif-clientid-config]|[`GCM_AZREPOS_WIF_CLIENTID`][gcm-wif-clientid-env]
48+
Tenant ID|[`credential.azreposWorkloadFederationTenantId`][gcm-wif-tenantid-config]|[`GCM_AZREPOS_WIF_TENANTID`][gcm-wif-tenantid-env]
49+
Assertion|[`credential.azreposWorkloadFederationAssertion`][gcm-wif-assertion-config]|[`GCM_AZREPOS_WIF_ASSERTION`][gcm-wif-assertion-env]
50+
51+
**Optional settings:**
52+
53+
Setting|Git Configuration|Environment Variable
54+
-|-|-
55+
Audience|[`credential.azreposWorkloadFederationAudience`][gcm-wif-audience-config]|[`GCM_AZREPOS_WIF_AUDIENCE`][gcm-wif-audience-env]
56+
57+
#### Example
58+
59+
```shell
60+
git config --global credential.azreposWorkloadFederation generic
61+
git config --global credential.azreposWorkloadFederationClientId "11111111-1111-1111-1111-111111111111"
62+
git config --global credential.azreposWorkloadFederationTenantId "22222222-2222-2222-2222-222222222222"
63+
git config --global credential.azreposWorkloadFederationAssertion "eyJhbGci..."
64+
```
65+
66+
### Managed Identity
67+
68+
Use this scenario when your workload runs on an Azure resource that has a
69+
[Managed Identity][az-mi] assigned. GCM will first request a token from the
70+
Managed Identity for the configured audience, then exchange that token for an
71+
Azure DevOps access token.
72+
73+
This is useful for Azure VMs, App Services, or other Azure resources that have a
74+
Managed Identity but need to authenticate as a specific app registration with
75+
a federated credential trust.
76+
77+
**Required settings:**
78+
79+
Setting|Git Configuration|Environment Variable
80+
-|-|-
81+
Scenario|[`credential.azreposWorkloadFederation`][gcm-wif-config]|[`GCM_AZREPOS_WIF`][gcm-wif-env]
82+
Client ID|[`credential.azreposWorkloadFederationClientId`][gcm-wif-clientid-config]|[`GCM_AZREPOS_WIF_CLIENTID`][gcm-wif-clientid-env]
83+
Tenant ID|[`credential.azreposWorkloadFederationTenantId`][gcm-wif-tenantid-config]|[`GCM_AZREPOS_WIF_TENANTID`][gcm-wif-tenantid-env]
84+
Managed Identity|[`credential.azreposWorkloadFederationManagedIdentity`][gcm-wif-mi-config]|[`GCM_AZREPOS_WIF_MANAGEDIDENTITY`][gcm-wif-mi-env]
85+
86+
**Optional settings:**
87+
88+
Setting|Git Configuration|Environment Variable
89+
-|-|-
90+
Audience|[`credential.azreposWorkloadFederationAudience`][gcm-wif-audience-config]|[`GCM_AZREPOS_WIF_AUDIENCE`][gcm-wif-audience-env]
91+
92+
The Managed Identity value accepts the same formats as
93+
[`credential.azreposManagedIdentity`][gcm-mi-config]:
94+
95+
Value|Description
96+
-|-
97+
`system`|System-Assigned Managed Identity
98+
`[guid]`|User-Assigned Managed Identity with the specified client ID
99+
`id://[guid]`|User-Assigned Managed Identity with the specified client ID
100+
`resource://[guid]`|User-Assigned Managed Identity for the associated resource
101+
102+
#### Example
103+
104+
```shell
105+
git config --global credential.azreposWorkloadFederation managedidentity
106+
git config --global credential.azreposWorkloadFederationClientId "11111111-1111-1111-1111-111111111111"
107+
git config --global credential.azreposWorkloadFederationTenantId "22222222-2222-2222-2222-222222222222"
108+
git config --global credential.azreposWorkloadFederationManagedIdentity system
109+
```
110+
111+
### GitHub Actions
112+
113+
Use this scenario when your workload runs in a GitHub Actions workflow. GCM will
114+
automatically obtain an OIDC token from the GitHub Actions runtime and exchange
115+
it for an Azure DevOps access token.
116+
117+
This scenario uses the `ACTIONS_ID_TOKEN_REQUEST_URL` and
118+
`ACTIONS_ID_TOKEN_REQUEST_TOKEN` environment variables that GitHub Actions
119+
automatically provides when a workflow has the `id-token: write` permission.
120+
121+
**Required settings:**
122+
123+
Setting|Git Configuration|Environment Variable
124+
-|-|-
125+
Scenario|[`credential.azreposWorkloadFederation`][gcm-wif-config]|[`GCM_AZREPOS_WIF`][gcm-wif-env]
126+
Client ID|[`credential.azreposWorkloadFederationClientId`][gcm-wif-clientid-config]|[`GCM_AZREPOS_WIF_CLIENTID`][gcm-wif-clientid-env]
127+
Tenant ID|[`credential.azreposWorkloadFederationTenantId`][gcm-wif-tenantid-config]|[`GCM_AZREPOS_WIF_TENANTID`][gcm-wif-tenantid-env]
128+
129+
**Optional settings:**
130+
131+
Setting|Git Configuration|Environment Variable
132+
-|-|-
133+
Audience|[`credential.azreposWorkloadFederationAudience`][gcm-wif-audience-config]|[`GCM_AZREPOS_WIF_AUDIENCE`][gcm-wif-audience-env]
134+
135+
No additional GCM settings are required — the GitHub Actions OIDC environment
136+
variables are read automatically.
137+
138+
#### Prerequisites
139+
140+
1. An app registration in Microsoft Entra ID with a federated credential
141+
configured to trust your GitHub repository.
142+
2. The app registration must have the necessary permissions to access Azure
143+
DevOps.
144+
3. Your GitHub Actions workflow must have the `id-token: write` permission.
145+
146+
#### Example workflow
147+
148+
```yaml
149+
permissions:
150+
id-token: write
151+
contents: read
152+
153+
steps:
154+
- uses: actions/checkout@v4
155+
env:
156+
GCM_AZREPOS_WIF: githubactions
157+
GCM_AZREPOS_WIF_CLIENTID: "11111111-1111-1111-1111-111111111111"
158+
GCM_AZREPOS_WIF_TENANTID: "22222222-2222-2222-2222-222222222222"
159+
```
160+
161+
## Audience
162+
163+
All scenarios accept an optional audience setting that controls the audience
164+
claim in the federated token request. The default value is
165+
`api://AzureADTokenExchange`, which is the standard audience for Microsoft Entra
166+
ID workload identity federation.
167+
168+
You only need to change this if your federated credential trust is configured
169+
with a custom audience.
170+
171+
[az-mi]: https://learn.microsoft.com/en-us/entra/identity/managed-identities-azure-resources/overview
172+
[wif]: https://learn.microsoft.com/en-us/entra/workload-id/workload-identity-federation
173+
[gcm-mi-config]: https://gh.io/gcm/config#credentialazreposmanagedidentity
174+
[gcm-wif-config]: https://gh.io/gcm/config#credentialazreposworkloadfederation
175+
[gcm-wif-clientid-config]: https://gh.io/gcm/config#credentialazreposworkloadfederationclientid
176+
[gcm-wif-tenantid-config]: https://gh.io/gcm/config#credentialazreposworkloadfederationtenantid
177+
[gcm-wif-audience-config]: https://gh.io/gcm/config#credentialazreposworkloadfederationaudience
178+
[gcm-wif-assertion-config]: https://gh.io/gcm/config#credentialazreposworkloadfederationassertion
179+
[gcm-wif-mi-config]: https://gh.io/gcm/config#credentialazreposworkloadfederationmanagedidentity
180+
[gcm-wif-env]: https://gh.io/gcm/env#GCM_AZREPOS_WIF
181+
[gcm-wif-clientid-env]: https://gh.io/gcm/env#GCM_AZREPOS_WIF_CLIENTID
182+
[gcm-wif-tenantid-env]: https://gh.io/gcm/env#GCM_AZREPOS_WIF_TENANTID
183+
[gcm-wif-audience-env]: https://gh.io/gcm/env#GCM_AZREPOS_WIF_AUDIENCE
184+
[gcm-wif-assertion-env]: https://gh.io/gcm/env#GCM_AZREPOS_WIF_ASSERTION
185+
[gcm-wif-mi-env]: https://gh.io/gcm/env#GCM_AZREPOS_WIF_MANAGEDIDENTITY

docs/configuration.md

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -884,6 +884,138 @@ git config --global credential.azreposManagedIdentity "id://11111111-1111-1111-1
884884

885885
---
886886

887+
### credential.azreposWorkloadFederation
888+
889+
Use [Workload Identity Federation][wif] to authenticate with Azure Repos.
890+
891+
The value specifies the federation scenario to use for obtaining a client
892+
assertion to exchange for an access token.
893+
894+
You must also set the following companion settings:
895+
896+
- [credential.azreposWorkloadFederationClientId][credential-azrepos-wif-clientid]
897+
- [credential.azreposWorkloadFederationTenantId][credential-azrepos-wif-tenantid]
898+
899+
Depending on the scenario, additional settings may be required.
900+
901+
Value|Description
902+
-|-
903+
`generic`|Use a user-supplied client assertion ([credential.azreposWorkloadFederationAssertion][credential-azrepos-wif-assertion])
904+
`managedidentity`|Use a [Managed Identity][managed-identity] to obtain the federated token ([credential.azreposWorkloadFederationManagedIdentity][credential-azrepos-wif-managedidentity])
905+
`githubactions`|Automatically obtain an OIDC token from GitHub Actions
906+
907+
For more information about workload identity federation, see the
908+
[conceptual documentation][azrepos-wif-doc] and the Azure DevOps
909+
[documentation][azrepos-sp-mid].
910+
911+
#### Example
912+
913+
```shell
914+
git config --global credential.azreposWorkloadFederation githubactions
915+
```
916+
917+
**Also see: [GCM_AZREPOS_WIF][gcm-azrepos-wif]**
918+
919+
---
920+
921+
### credential.azreposWorkloadFederationClientId
922+
923+
The client ID of the app registration / service principal to request an access
924+
token for when using [Workload Identity Federation][wif] with
925+
[credential.azreposWorkloadFederation][credential-azrepos-wif].
926+
927+
#### Example
928+
929+
```shell
930+
git config --global credential.azreposWorkloadFederationClientId "11111111-1111-1111-1111-111111111111"
931+
```
932+
933+
**Also see: [GCM_AZREPOS_WIF_CLIENTID][gcm-azrepos-wif-clientid]**
934+
935+
---
936+
937+
### credential.azreposWorkloadFederationTenantId
938+
939+
The tenant ID of the app registration / service principal to request an access
940+
token for when using [Workload Identity Federation][wif] with
941+
[credential.azreposWorkloadFederation][credential-azrepos-wif].
942+
943+
#### Example
944+
945+
```shell
946+
git config --global credential.azreposWorkloadFederationTenantId "22222222-2222-2222-2222-222222222222"
947+
```
948+
949+
**Also see: [GCM_AZREPOS_WIF_TENANTID][gcm-azrepos-wif-tenantid]**
950+
951+
---
952+
953+
### credential.azreposWorkloadFederationAudience
954+
955+
The audience to use when requesting the federated token for
956+
[Workload Identity Federation][wif] with
957+
[credential.azreposWorkloadFederation][credential-azrepos-wif].
958+
959+
Defaults to `api://AzureADTokenExchange`.
960+
961+
#### Example
962+
963+
```shell
964+
git config --global credential.azreposWorkloadFederationAudience "api://AzureADTokenExchange"
965+
```
966+
967+
**Also see: [GCM_AZREPOS_WIF_AUDIENCE][gcm-azrepos-wif-audience]**
968+
969+
---
970+
971+
### credential.azreposWorkloadFederationAssertion
972+
973+
Specifies the client assertion token to use with the `generic`
974+
[Workload Identity Federation][wif] scenario
975+
([credential.azreposWorkloadFederation][credential-azrepos-wif]).
976+
977+
This setting is required when `credential.azreposWorkloadFederation` is set to
978+
`generic`.
979+
980+
#### Example
981+
982+
```shell
983+
git config --global credential.azreposWorkloadFederationAssertion "eyJhbGci..."
984+
```
985+
986+
**Also see: [GCM_AZREPOS_WIF_ASSERTION][gcm-azrepos-wif-assertion]**
987+
988+
---
989+
990+
### credential.azreposWorkloadFederationManagedIdentity
991+
992+
Specifies the [Managed Identity][managed-identity] to use to obtain a federated
993+
token for the `managedidentity` [Workload Identity Federation][wif] scenario
994+
([credential.azreposWorkloadFederation][credential-azrepos-wif]).
995+
996+
This setting is required when `credential.azreposWorkloadFederation` is set to
997+
`managedidentity`.
998+
999+
The value accepts the same formats as
1000+
[credential.azreposManagedIdentity](#credentialazreposmanagedidentity).
1001+
1002+
Value|Description
1003+
-|-
1004+
`system`|System-Assigned Managed Identity
1005+
`[guid]`|User-Assigned Managed Identity with the specified client ID
1006+
`id://[guid]`|User-Assigned Managed Identity with the specified client ID
1007+
`resource://[guid]`|User-Assigned Managed Identity for the associated resource
1008+
1009+
#### Example
1010+
1011+
```shell
1012+
git config --global credential.azreposWorkloadFederationManagedIdentity system
1013+
```
1014+
1015+
**Also see: [GCM_AZREPOS_WIF_MANAGEDIDENTITY][gcm-azrepos-wif-managedidentity]**
1016+
1017+
---
1018+
8871019
### credential.azreposServicePrincipal
8881020

8891021
Specify the client and tenant IDs of a [service principal][service-principal]
@@ -1048,6 +1180,12 @@ Defaults to disabled.
10481180
[gcm-autodetect-timeout]: environment.md#GCM_AUTODETECT_TIMEOUT
10491181
[gcm-azrepos-credentialtype]: environment.md#GCM_AZREPOS_CREDENTIALTYPE
10501182
[gcm-azrepos-credentialmanagedidentity]: environment.md#GCM_AZREPOS_MANAGEDIDENTITY
1183+
[gcm-azrepos-wif]: environment.md#GCM_AZREPOS_WIF
1184+
[gcm-azrepos-wif-clientid]: environment.md#GCM_AZREPOS_WIF_CLIENTID
1185+
[gcm-azrepos-wif-tenantid]: environment.md#GCM_AZREPOS_WIF_TENANTID
1186+
[gcm-azrepos-wif-audience]: environment.md#GCM_AZREPOS_WIF_AUDIENCE
1187+
[gcm-azrepos-wif-assertion]: environment.md#GCM_AZREPOS_WIF_ASSERTION
1188+
[gcm-azrepos-wif-managedidentity]: environment.md#GCM_AZREPOS_WIF_MANAGEDIDENTITY
10511189
[gcm-bitbucket-always-refresh-credentials]: environment.md#GCM_BITBUCKET_ALWAYS_REFRESH_CREDENTIALS
10521190
[gcm-bitbucket-authmodes]: environment.md#GCM_BITBUCKET_AUTHMODES
10531191
[gcm-credential-cache-options]: environment.md#GCM_CREDENTIAL_CACHE_OPTIONS
@@ -1077,6 +1215,7 @@ Defaults to disabled.
10771215
[autodetect]: autodetect.md
10781216
[libsecret]: https://wiki.gnome.org/Projects/Libsecret
10791217
[managed-identity]: https://docs.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/overview
1218+
[wif]: https://learn.microsoft.com/en-us/entra/workload-id/workload-identity-federation
10801219
[provider-migrate]: migration.md#gcm_authority
10811220
[cache-options]: https://git-scm.com/docs/git-credential-cache#_options
10821221
[pass]: https://www.passwordstore.org/
@@ -1090,6 +1229,13 @@ Defaults to disabled.
10901229
[wam]: windows-broker.md
10911230
[service-principal]: https://docs.microsoft.com/en-us/azure/active-directory/develop/app-objects-and-service-principals
10921231
[azrepos-sp-mid]: https://learn.microsoft.com/en-us/azure/devops/integrate/get-started/authentication/service-principal-managed-identity
1232+
[azrepos-wif-doc]: azrepos-wif.md
1233+
[credential-azrepos-wif]: #credentialazreposworkloadfederation
1234+
[credential-azrepos-wif-clientid]: #credentialazreposworkloadfederationclientid
1235+
[credential-azrepos-wif-tenantid]: #credentialazreposworkloadfederationtenantid
1236+
[credential-azrepos-wif-audience]: #credentialazreposworkloadfederationaudience
1237+
[credential-azrepos-wif-assertion]: #credentialazreposworkloadfederationassertion
1238+
[credential-azrepos-wif-managedidentity]: #credentialazreposworkloadfederationmanagedidentity
10931239
[credential-azrepos-sp]: #credentialazreposserviceprincipal
10941240
[credential-azrepos-sp-secret]: #credentialazreposserviceprincipalsecret
10951241
[credential-azrepos-sp-cert-thumbprint]: #credentialazreposserviceprincipalcertificatethumbprint

0 commit comments

Comments
 (0)