0
# Federated Identity Credentials
1
2
Federated identity credentials enable workload identity federation, allowing external identity providers (such as Kubernetes service accounts, GitHub Actions, or other OIDC providers) to obtain Azure tokens without storing long-lived secrets. This provides a more secure authentication mechanism for workloads running outside Azure.
3
4
## Parameter Constraints
5
6
**Resource Names:**
7
- `federated_identity_credential_resource_name`: 3-120 characters, pattern: `^[a-zA-Z0-9]{1}[a-zA-Z0-9-_]{2,119}$`
8
- `resource_group_name`: 1-90 characters, pattern: `^[a-zA-Z0-9._()\-]*[a-zA-Z0-9_()]$`
9
10
**Model Validation:**
11
- `issuer`: Must be HTTPS URL for the OIDC issuer
12
- `audiences`: Typically includes "api://AzureADTokenExchange"
13
- `subject`: External identity identifier specific to the OIDC provider
14
15
## Capabilities
16
17
### Create or Update Federated Credential
18
19
Creates or updates a federated identity credential for a user-assigned managed identity. This establishes trust between the Azure identity and an external identity provider through OIDC federation.
20
21
```python { .api }
22
def create_or_update(
23
resource_group_name: str,
24
resource_name: str,
25
federated_identity_credential_resource_name: str,
26
parameters: Union[FederatedIdentityCredential, IO[bytes]],
27
**kwargs
28
) -> FederatedIdentityCredential:
29
"""
30
Create or update a federated identity credential.
31
32
Parameters:
33
- resource_group_name (str): Name of the resource group
34
- resource_name (str): Name of the user-assigned identity
35
- federated_identity_credential_resource_name (str): Name of the federated credential
36
- parameters (Union[FederatedIdentityCredential, IO[bytes]]): Credential configuration parameters or raw JSON bytes
37
- **kwargs: Additional request options
38
39
Returns:
40
FederatedIdentityCredential: The created or updated credential
41
42
Raises:
43
ResourceNotFoundError: If the user-assigned identity does not exist
44
HttpResponseError: For validation or other API errors
45
"""
46
```
47
48
**Usage Examples:**
49
50
```python
51
from azure.mgmt.msi import ManagedServiceIdentityClient
52
from azure.identity import DefaultAzureCredential
53
54
client = ManagedServiceIdentityClient(
55
credential=DefaultAzureCredential(),
56
subscription_id="your-subscription-id"
57
)
58
59
# Create federated credential for Kubernetes workload identity
60
k8s_credential = client.federated_identity_credentials.create_or_update(
61
resource_group_name="myResourceGroup",
62
resource_name="myUserIdentity",
63
federated_identity_credential_resource_name="k8s-default-workload",
64
parameters={
65
"properties": {
66
"issuer": "https://oidc.prod-aks.azure.com/tenant-guid/issuer-guid",
67
"subject": "system:serviceaccount:default:workload-service-account",
68
"audiences": ["api://AzureADTokenExchange"]
69
}
70
}
71
)
72
73
print(f"Created Kubernetes federated credential: {k8s_credential.name}")
74
print(f"Issuer: {k8s_credential.issuer}")
75
print(f"Subject: {k8s_credential.subject}")
76
77
# Create federated credential for GitHub Actions
78
github_credential = client.federated_identity_credentials.create_or_update(
79
resource_group_name="myResourceGroup",
80
resource_name="myUserIdentity",
81
federated_identity_credential_resource_name="github-actions-main",
82
parameters={
83
"properties": {
84
"issuer": "https://token.actions.githubusercontent.com",
85
"subject": "repo:myorg/myrepo:ref:refs/heads/main",
86
"audiences": ["api://AzureADTokenExchange"]
87
}
88
}
89
)
90
91
# Create federated credential for external OIDC provider
92
external_credential = client.federated_identity_credentials.create_or_update(
93
resource_group_name="myResourceGroup",
94
resource_name="myUserIdentity",
95
federated_identity_credential_resource_name="external-oidc",
96
parameters={
97
"properties": {
98
"issuer": "https://auth.example.com",
99
"subject": "external-workload-123",
100
"audiences": ["api://AzureADTokenExchange", "custom-audience"]
101
}
102
}
103
)
104
```
105
106
### Retrieve Federated Credential
107
108
Retrieves an existing federated identity credential by name.
109
110
```python { .api }
111
def get(
112
resource_group_name: str,
113
resource_name: str,
114
federated_identity_credential_resource_name: str,
115
**kwargs
116
) -> FederatedIdentityCredential:
117
"""
118
Get a federated identity credential.
119
120
Parameters:
121
- resource_group_name (str): Name of the resource group
122
- resource_name (str): Name of the user-assigned identity
123
- federated_identity_credential_resource_name (str): Name of the federated credential
124
- **kwargs: Additional request options
125
126
Returns:
127
FederatedIdentityCredential: The requested credential
128
129
Raises:
130
ResourceNotFoundError: If credential does not exist
131
HttpResponseError: For other API errors
132
"""
133
```
134
135
**Usage Example:**
136
137
```python
138
try:
139
credential = client.federated_identity_credentials.get(
140
resource_group_name="myResourceGroup",
141
resource_name="myUserIdentity",
142
federated_identity_credential_resource_name="k8s-default-workload"
143
)
144
145
print(f"Credential found: {credential.name}")
146
print(f"Issuer: {credential.issuer}")
147
print(f"Subject: {credential.subject}")
148
print(f"Audiences: {credential.audiences}")
149
150
except ResourceNotFoundError:
151
print("Federated credential not found")
152
```
153
154
### Delete Federated Credential
155
156
Permanently deletes a federated identity credential, removing the trust relationship with the external identity provider.
157
158
```python { .api }
159
def delete(
160
resource_group_name: str,
161
resource_name: str,
162
federated_identity_credential_resource_name: str,
163
**kwargs
164
) -> None:
165
"""
166
Delete a federated identity credential.
167
168
Parameters:
169
- resource_group_name (str): Name of the resource group
170
- resource_name (str): Name of the user-assigned identity
171
- federated_identity_credential_resource_name (str): Name of the federated credential
172
- **kwargs: Additional request options
173
174
Returns:
175
None
176
177
Raises:
178
ResourceNotFoundError: If credential does not exist
179
HttpResponseError: For other API errors
180
"""
181
```
182
183
**Usage Example:**
184
185
```python
186
try:
187
client.federated_identity_credentials.delete(
188
resource_group_name="myResourceGroup",
189
resource_name="myUserIdentity",
190
federated_identity_credential_resource_name="old-k8s-credential"
191
)
192
print("Federated credential deleted successfully")
193
194
except ResourceNotFoundError:
195
print("Credential not found")
196
except HttpResponseError as e:
197
print(f"Failed to delete credential: {e.message}")
198
```
199
200
### List Federated Credentials
201
202
Lists all federated identity credentials for a user-assigned managed identity, with automatic pagination support.
203
204
```python { .api }
205
def list(
206
resource_group_name: str,
207
resource_name: str,
208
top: Optional[int] = None,
209
skiptoken: Optional[str] = None,
210
**kwargs
211
) -> ItemPaged[FederatedIdentityCredential]:
212
"""
213
List federated identity credentials for an identity.
214
215
Parameters:
216
- resource_group_name (str): Name of the resource group
217
- resource_name (str): Name of the user-assigned identity
218
- top (Optional[int]): Maximum number of results to return per page
219
- skiptoken (Optional[str]): Token for retrieving the next page of results
220
- **kwargs: Additional request options
221
222
Returns:
223
ItemPaged[FederatedIdentityCredential]: Paginated list of credentials
224
225
Raises:
226
ResourceNotFoundError: If identity does not exist
227
HttpResponseError: For other API errors
228
"""
229
```
230
231
**Usage Example:**
232
233
```python
234
# List all federated credentials for an identity
235
print("Federated credentials for myUserIdentity:")
236
for credential in client.federated_identity_credentials.list(
237
resource_group_name="myResourceGroup",
238
resource_name="myUserIdentity"
239
):
240
print(f"- {credential.name}")
241
print(f" Issuer: {credential.issuer}")
242
print(f" Subject: {credential.subject}")
243
print(f" Audiences: {', '.join(credential.audiences)}")
244
245
# Count credentials
246
credential_count = len(list(client.federated_identity_credentials.list(
247
resource_group_name="myResourceGroup",
248
resource_name="myUserIdentity"
249
)))
250
print(f"Total federated credentials: {credential_count}")
251
```
252
253
## Advanced Usage Patterns
254
255
### Kubernetes Workload Identity Setup
256
257
```python
258
def setup_kubernetes_workload_identity(
259
resource_group: str,
260
identity_name: str,
261
oidc_issuer: str,
262
namespace: str,
263
service_account: str
264
):
265
"""
266
Set up complete Kubernetes workload identity federation.
267
268
Args:
269
resource_group: Azure resource group name
270
identity_name: User-assigned identity name
271
oidc_issuer: AKS OIDC issuer URL
272
namespace: Kubernetes namespace
273
service_account: Kubernetes service account name
274
275
Returns:
276
tuple: (client_id, credential_name)
277
"""
278
# First ensure the user-assigned identity exists
279
try:
280
identity = client.user_assigned_identities.get(
281
resource_group_name=resource_group,
282
resource_name=identity_name
283
)
284
except ResourceNotFoundError:
285
print(f"Creating user-assigned identity: {identity_name}")
286
identity = client.user_assigned_identities.create_or_update(
287
resource_group_name=resource_group,
288
resource_name=identity_name,
289
parameters={
290
"location": "eastus",
291
"tags": {"workload-identity": "true", "namespace": namespace}
292
}
293
)
294
295
# Create federated credential for the service account
296
credential_name = f"{namespace}-{service_account}"
297
credential = client.federated_identity_credentials.create_or_update(
298
resource_group_name=resource_group,
299
resource_name=identity_name,
300
federated_identity_credential_resource_name=credential_name,
301
parameters={
302
"properties": {
303
"issuer": oidc_issuer,
304
"subject": f"system:serviceaccount:{namespace}:{service_account}",
305
"audiences": ["api://AzureADTokenExchange"]
306
}
307
}
308
)
309
310
return identity.client_id, credential_name
311
312
# Set up workload identity for a Kubernetes service account
313
client_id, cred_name = setup_kubernetes_workload_identity(
314
resource_group="myResourceGroup",
315
identity_name="aks-workload-identity",
316
oidc_issuer="https://oidc.prod-aks.azure.com/tenant-guid/issuer-guid",
317
namespace="default",
318
service_account="workload-service-account"
319
)
320
321
print(f"Workload identity configured:")
322
print(f" Client ID: {client_id}")
323
print(f" Credential: {cred_name}")
324
print(f" Add this annotation to your service account:")
325
print(f" azure.workload.identity/client-id: {client_id}")
326
```
327
328
### GitHub Actions Integration
329
330
```python
331
def setup_github_actions_identity(
332
resource_group: str,
333
identity_name: str,
334
github_repo: str,
335
branch_or_environment: str = "main",
336
environment_type: str = "branch" # or "environment"
337
):
338
"""
339
Set up federated identity for GitHub Actions.
340
341
Args:
342
resource_group: Azure resource group
343
identity_name: User-assigned identity name
344
github_repo: GitHub repository in format "owner/repo"
345
branch_or_environment: Branch name or environment name
346
environment_type: "branch" or "environment"
347
348
Returns:
349
dict: Configuration details
350
"""
351
# Construct subject based on type
352
if environment_type == "environment":
353
subject = f"repo:{github_repo}:environment:{branch_or_environment}"
354
credential_name = f"github-env-{branch_or_environment}"
355
else:
356
subject = f"repo:{github_repo}:ref:refs/heads/{branch_or_environment}"
357
credential_name = f"github-branch-{branch_or_environment}"
358
359
# Create or get identity
360
try:
361
identity = client.user_assigned_identities.get(
362
resource_group_name=resource_group,
363
resource_name=identity_name
364
)
365
except ResourceNotFoundError:
366
identity = client.user_assigned_identities.create_or_update(
367
resource_group_name=resource_group,
368
resource_name=identity_name,
369
parameters={
370
"location": "eastus",
371
"tags": {"github-actions": "true", "repo": github_repo}
372
}
373
)
374
375
# Create federated credential
376
credential = client.federated_identity_credentials.create_or_update(
377
resource_group_name=resource_group,
378
resource_name=identity_name,
379
federated_identity_credential_resource_name=credential_name,
380
parameters={
381
"properties": {
382
"issuer": "https://token.actions.githubusercontent.com",
383
"subject": subject,
384
"audiences": ["api://AzureADTokenExchange"]
385
}
386
}
387
)
388
389
return {
390
"client_id": identity.client_id,
391
"tenant_id": identity.tenant_id,
392
"credential_name": credential_name,
393
"subject": subject,
394
"setup_instructions": {
395
"AZURE_CLIENT_ID": identity.client_id,
396
"AZURE_TENANT_ID": identity.tenant_id,
397
"AZURE_SUBSCRIPTION_ID": client.subscription_id
398
}
399
}
400
401
# Set up GitHub Actions for main branch
402
github_config = setup_github_actions_identity(
403
resource_group="myResourceGroup",
404
identity_name="github-actions-identity",
405
github_repo="myorg/myrepo",
406
branch_or_environment="main"
407
)
408
409
print("GitHub Actions Configuration:")
410
print("Add these secrets to your GitHub repository:")
411
for key, value in github_config["setup_instructions"].items():
412
print(f" {key}: {value}")
413
```
414
415
### Multi-Environment Federated Credentials
416
417
```python
418
def setup_multi_environment_federation(
419
resource_group: str,
420
base_identity_name: str,
421
environments: dict
422
):
423
"""
424
Set up federated credentials for multiple environments.
425
426
Args:
427
resource_group: Azure resource group
428
base_identity_name: Base name for identities
429
environments: Dict with env_name -> config mapping
430
431
Example environments config:
432
{
433
"dev": {
434
"issuer": "https://dev-oidc.example.com",
435
"subject": "workload-dev-123"
436
},
437
"staging": {
438
"issuer": "https://staging-oidc.example.com",
439
"subject": "workload-staging-456"
440
},
441
"prod": {
442
"issuer": "https://prod-oidc.example.com",
443
"subject": "workload-prod-789"
444
}
445
}
446
"""
447
results = {}
448
449
for env_name, config in environments.items():
450
identity_name = f"{base_identity_name}-{env_name}"
451
452
# Create identity for environment
453
try:
454
identity = client.user_assigned_identities.create_or_update(
455
resource_group_name=resource_group,
456
resource_name=identity_name,
457
parameters={
458
"location": "eastus",
459
"tags": {"environment": env_name, "federation": "true"}
460
}
461
)
462
463
# Create federated credential
464
credential = client.federated_identity_credentials.create_or_update(
465
resource_group_name=resource_group,
466
resource_name=identity_name,
467
federated_identity_credential_resource_name=f"{env_name}-federation",
468
parameters={
469
"properties": {
470
"issuer": config["issuer"],
471
"subject": config["subject"],
472
"audiences": ["api://AzureADTokenExchange"]
473
}
474
}
475
)
476
477
results[env_name] = {
478
"identity_name": identity_name,
479
"client_id": identity.client_id,
480
"principal_id": identity.principal_id,
481
"credential_name": credential.name,
482
"status": "success"
483
}
484
485
except Exception as e:
486
results[env_name] = {
487
"identity_name": identity_name,
488
"status": "failed",
489
"error": str(e)
490
}
491
492
return results
493
494
# Configure multiple environments
495
environments = {
496
"dev": {
497
"issuer": "https://dev-k8s.example.com",
498
"subject": "system:serviceaccount:dev:app-service-account"
499
},
500
"prod": {
501
"issuer": "https://prod-k8s.example.com",
502
"subject": "system:serviceaccount:prod:app-service-account"
503
}
504
}
505
506
env_results = setup_multi_environment_federation(
507
resource_group="myResourceGroup",
508
base_identity_name="myapp-identity",
509
environments=environments
510
)
511
512
for env, result in env_results.items():
513
if result["status"] == "success":
514
print(f"✓ {env}: {result['client_id']}")
515
else:
516
print(f"✗ {env}: {result['error']}")
517
```
518
519
### Credential Validation and Testing
520
521
```python
522
def validate_federated_credential(
523
resource_group: str,
524
identity_name: str,
525
credential_name: str
526
):
527
"""
528
Validate federated credential configuration and provide troubleshooting info.
529
"""
530
try:
531
# Get the credential
532
credential = client.federated_identity_credentials.get(
533
resource_group_name=resource_group,
534
resource_name=identity_name,
535
federated_identity_credential_resource_name=credential_name
536
)
537
538
# Get the parent identity
539
identity = client.user_assigned_identities.get(
540
resource_group_name=resource_group,
541
resource_name=identity_name
542
)
543
544
validation_result = {
545
"valid": True,
546
"credential_name": credential.name,
547
"identity_client_id": identity.client_id,
548
"issuer": credential.issuer,
549
"subject": credential.subject,
550
"audiences": credential.audiences,
551
"validation_checks": []
552
}
553
554
# Validation checks
555
if not credential.issuer.startswith("https://"):
556
validation_result["validation_checks"].append(
557
"WARNING: Issuer should use HTTPS"
558
)
559
560
if "api://AzureADTokenExchange" not in credential.audiences:
561
validation_result["validation_checks"].append(
562
"WARNING: Missing standard audience 'api://AzureADTokenExchange'"
563
)
564
565
if not credential.subject:
566
validation_result["validation_checks"].append(
567
"ERROR: Subject cannot be empty"
568
)
569
validation_result["valid"] = False
570
571
# Add setup instructions based on issuer pattern
572
if "token.actions.githubusercontent.com" in credential.issuer:
573
validation_result["setup_type"] = "GitHub Actions"
574
validation_result["env_vars"] = {
575
"AZURE_CLIENT_ID": identity.client_id,
576
"AZURE_TENANT_ID": identity.tenant_id,
577
"AZURE_SUBSCRIPTION_ID": client.subscription_id
578
}
579
elif "oidc.prod-aks.azure.com" in credential.issuer:
580
validation_result["setup_type"] = "AKS Workload Identity"
581
validation_result["service_account_annotation"] = {
582
"azure.workload.identity/client-id": identity.client_id
583
}
584
585
return validation_result
586
587
except ResourceNotFoundError as e:
588
return {
589
"valid": False,
590
"error": f"Resource not found: {e}",
591
"troubleshooting": [
592
"Check that the identity exists",
593
"Check that the credential name is correct",
594
"Verify resource group name"
595
]
596
}
597
598
# Validate a federated credential
599
validation = validate_federated_credential(
600
resource_group="myResourceGroup",
601
identity_name="myUserIdentity",
602
credential_name="k8s-default-workload"
603
)
604
605
if validation["valid"]:
606
print("✓ Credential is valid")
607
if "env_vars" in validation:
608
print("Environment variables:")
609
for key, value in validation["env_vars"].items():
610
print(f" {key}={value}")
611
else:
612
print("✗ Credential validation failed")
613
print(f"Error: {validation.get('error', 'Unknown error')}")
614
```
615
616
## Types
617
618
```python { .api }
619
class FederatedIdentityCredential:
620
"""Federated identity credential for workload identity federation."""
621
# Read-only properties
622
id: str # Full Azure resource ID
623
name: str # Credential resource name
624
type: str # Resource type (Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials)
625
system_data: SystemData # ARM metadata (creation/modification info)
626
627
# Configurable properties
628
issuer: str # OIDC issuer URL (required) - must be HTTPS
629
subject: str # External identity identifier (required)
630
audiences: List[str] # Token audiences (required) - typically includes "api://AzureADTokenExchange"
631
```
632
633
## Common Issuer Patterns
634
635
### GitHub Actions
636
- **Issuer**: `https://token.actions.githubusercontent.com`
637
- **Subject Patterns**:
638
- Branch: `repo:owner/repo:ref:refs/heads/branch-name`
639
- Tag: `repo:owner/repo:ref:refs/tags/tag-name`
640
- Environment: `repo:owner/repo:environment:environment-name`
641
- Pull Request: `repo:owner/repo:pull_request`
642
643
### Azure Kubernetes Service (AKS)
644
- **Issuer**: `https://oidc.prod-aks.azure.com/{tenant-id}/{aks-cluster-issuer-id}`
645
- **Subject**: `system:serviceaccount:namespace:service-account-name`
646
647
### AWS EKS
648
- **Issuer**: `https://oidc.eks.region.amazonaws.com/id/{cluster-id}`
649
- **Subject**: `system:serviceaccount:namespace:service-account-name`
650
651
### Google Cloud (GKE)
652
- **Issuer**: `https://container.googleapis.com/v1/projects/{project-id}/locations/{location}/clusters/{cluster-name}`
653
- **Subject**: `system:serviceaccount:namespace:service-account-name`
654
655
### Generic OIDC Provider
656
- **Issuer**: Custom HTTPS URL for your OIDC provider
657
- **Subject**: Provider-specific identifier for the workload or user