or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

federated-identity-credentials.mdindex.mdsystem-assigned-identities.mduser-assigned-identities.md

federated-identity-credentials.mddocs/

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