Skip to content

Commit 4418cd0

Browse files
committed
Implement workload identity support
1 parent f127c1b commit 4418cd0

File tree

6 files changed

+121
-149
lines changed

6 files changed

+121
-149
lines changed

api/v1alpha1/backendsecurity_policy.go

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -237,21 +237,24 @@ type BackendSecurityPolicyGCPCredentials struct {
237237
// Otherwise, exactly one of ClientSecretRef or OIDCExchangeToken must be specified.
238238
//
239239
// +kubebuilder:validation:XValidation:rule="has(self.useManagedIdentity) && self.useManagedIdentity ? (!has(self.clientSecretRef) && !has(self.oidcExchangeToken)) : ((has(self.clientSecretRef) && !has(self.oidcExchangeToken)) || (!has(self.clientSecretRef) && has(self.oidcExchangeToken)))",message="When useManagedIdentity is true, clientSecretRef and oidcExchangeToken must not be specified. Otherwise, exactly one of clientSecretRef or oidcExchangeToken must be specified"
240-
// +kubebuilder:validation:XValidation:rule="has(self.useManagedIdentity) && self.useManagedIdentity && !has(self.clientID) ? true : has(self.clientID)",message="clientID is optional for system-assigned managed identity but required otherwise"
241240
type BackendSecurityPolicyAzureCredentials struct {
242241
// ClientID is a unique identifier for an application in Azure.
243-
// This field is optional when using system-assigned managed identity,
244-
// but required for user-assigned managed identity and other authentication methods.
242+
// This field is optional when using managed identity or workload identity,
243+
// as the value will be provided via environment variables (AZURE_CLIENT_ID).
244+
// Required for other authentication methods.
245245
//
246246
// +optional
247247
// +kubebuilder:validation:MinLength=1
248-
ClientID string `json:"clientID"`
248+
ClientID string `json:"clientID,omitempty"`
249249

250250
// TenantId is a unique identifier for an Azure Active Directory instance.
251+
// This field is optional when using workload identity with service account annotations,
252+
// as the value will be provided via environment variables (AZURE_TENANT_ID).
253+
// Required for other authentication methods.
251254
//
252-
// +kubebuilder:validation:Required
255+
// +optional
253256
// +kubebuilder:validation:MinLength=1
254-
TenantID string `json:"tenantID"`
257+
TenantID string `json:"tenantID,omitempty"`
255258

256259
// ClientSecretRef is the reference to the secret containing the Azure client secret.
257260
// ai-gateway must be given the permission to read this secret.

examples/basic/azure_openai.yaml

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,29 @@
33
# The full text of the Apache license is available in the LICENSE file at
44
# the root of the repo.
55

6+
# Azure OpenAI Authentication Examples
7+
#
8+
# This file demonstrates two authentication methods for Azure OpenAI:
9+
# 1. Client Secret (default, uncommented)
10+
# 2. Managed Identity / Workload Identity (commented alternatives)
11+
#
12+
# For AKS Workload Identity setup, configure the service account during Helm install:
13+
#
14+
# helm upgrade --install ai-gateway-controller envoyproxy/ai-gateway-helm \
15+
# --set controller.serviceAccount.annotations."azure\.workload\.identity/client-id"="<your-managed-identity-client-id>" \
16+
# --set controller.serviceAccount.annotations."azure\.workload\.identity/tenant-id"="<your-tenant-id>" \
17+
# --create-namespace \
18+
# -n envoy-ai-gateway-system
19+
#
20+
# # Add the required label:
21+
# kubectl label serviceaccount ai-gateway-controller \
22+
# azure.workload.identity/use=true \
23+
# -n envoy-ai-gateway-system
24+
#
25+
# For complete Azure infrastructure setup, see:
26+
# https://learn.microsoft.com/en-us/azure/aks/workload-identity-deploy-cluster
27+
28+
---
629
apiVersion: aigateway.envoyproxy.io/v1alpha1
730
kind: AIGatewayRoute
831
metadata:
@@ -39,6 +62,7 @@ spec:
3962
kind: Backend
4063
group: gateway.envoyproxy.io
4164
---
65+
# Option 1: Client Secret Authentication (Default)
4266
apiVersion: aigateway.envoyproxy.io/v1alpha1
4367
kind: BackendSecurityPolicy
4468
metadata:
@@ -57,6 +81,26 @@ spec:
5781
name: envoy-ai-gateway-basic-azure-client-secret
5882
namespace: default
5983
---
84+
# Option 2: Managed Identity / Workload Identity Authentication
85+
# Uncomment this section and comment out Option 1 to use Managed Identity.
86+
#
87+
# For AKS Workload Identity: Configure service account annotations during Helm install
88+
# (see header comment above for helm upgrade command)
89+
#
90+
# apiVersion: aigateway.envoyproxy.io/v1alpha1
91+
# kind: BackendSecurityPolicy
92+
# metadata:
93+
# name: envoy-ai-gateway-basic-azure-credentials
94+
# namespace: default
95+
# spec:
96+
# targetRefs:
97+
# - group: aigateway.envoyproxy.io
98+
# kind: AIServiceBackend
99+
# name: envoy-ai-gateway-basic-azure
100+
# type: AzureCredentials
101+
# azureCredentials:
102+
# useManagedIdentity: true
103+
---
60104
apiVersion: gateway.envoyproxy.io/v1alpha1
61105
kind: Backend
62106
metadata:

examples/basic/azure_openai_managed_identity.yaml

Lines changed: 0 additions & 117 deletions
This file was deleted.

internal/controller/tokenprovider/azure_managed_identity_token_provider.go

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,21 +23,43 @@ type azureManagedIdentityTokenProvider struct {
2323
tokenOption policy.TokenRequestOptions
2424
}
2525

26-
// NewAzureManagedIdentityTokenProvider creates a new TokenProvider using Azure DefaultAzureCredential.
26+
// NewAzureManagedIdentityTokenProvider creates a new TokenProvider using Azure credentials.
2727
// This supports:
28+
// - AKS Workload Identity (via AZURE_FEDERATED_TOKEN_FILE environment variable)
2829
// - Environment variables (AZURE_CLIENT_ID, AZURE_TENANT_ID, AZURE_CLIENT_SECRET, AZURE_FEDERATED_TOKEN_FILE)
29-
// - AKS Workload Identity (via service account annotations and federated token file)
30-
// - System-assigned managed identity (when clientID is empty)
31-
// - User-assigned managed identity (when clientID is provided)
30+
// - System-assigned managed identity (when clientID is empty and no workload identity)
31+
// - User-assigned managed identity (when clientID is provided and no workload identity)
3232
// - Azure CLI credentials (for development scenarios).
3333
func NewAzureManagedIdentityTokenProvider(_ context.Context, clientID string, tokenOption policy.TokenRequestOptions) (TokenProvider, error) {
3434
clientOptions := GetDefaultAzureCredentialOptions()
3535

3636
var credential azcore.TokenCredential
3737
var err error
3838

39-
if clientID != "" {
39+
// Check if running in AKS Workload Identity environment
40+
federatedTokenFile := os.Getenv("AZURE_FEDERATED_TOKEN_FILE")
41+
tenantID := os.Getenv("AZURE_TENANT_ID")
42+
envClientID := os.Getenv("AZURE_CLIENT_ID")
43+
44+
if federatedTokenFile != "" && tenantID != "" {
45+
// Use Workload Identity - this is the AKS Workload Identity pattern
46+
// Use clientID from environment if not explicitly provided
47+
if clientID == "" && envClientID != "" {
48+
clientID = envClientID
49+
}
50+
51+
workloadIDOptions := &azidentity.WorkloadIdentityCredentialOptions{
52+
ClientID: clientID,
53+
TenantID: tenantID,
54+
TokenFilePath: federatedTokenFile,
55+
}
56+
if clientOptions != nil {
57+
workloadIDOptions.ClientOptions = clientOptions.ClientOptions
58+
}
59+
credential, err = azidentity.NewWorkloadIdentityCredential(workloadIDOptions)
60+
} else if clientID != "" {
4061
// User-assigned managed identity - specify the client ID.
62+
// This uses Azure VM/VMSS Managed Identity via IMDS
4163
managedIDOptions := &azidentity.ManagedIdentityCredentialOptions{
4264
ID: azidentity.ClientID(clientID),
4365
}

manifests/charts/ai-gateway-crds-helm/templates/aigateway.envoyproxy.io_backendsecuritypolicies.yaml

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1729,8 +1729,9 @@ spec:
17291729
clientID:
17301730
description: |-
17311731
ClientID is a unique identifier for an application in Azure.
1732-
This field is optional when using system-assigned managed identity,
1733-
but required for user-assigned managed identity and other authentication methods.
1732+
This field is optional when using managed identity or workload identity,
1733+
as the value will be provided via environment variables (AZURE_CLIENT_ID).
1734+
Required for other authentication methods.
17341735
minLength: 1
17351736
type: string
17361737
clientSecretRef:
@@ -3211,8 +3212,11 @@ spec:
32113212
- oidc
32123213
type: object
32133214
tenantID:
3214-
description: TenantId is a unique identifier for an Azure Active
3215-
Directory instance.
3215+
description: |-
3216+
TenantId is a unique identifier for an Azure Active Directory instance.
3217+
This field is optional when using workload identity with service account annotations,
3218+
as the value will be provided via environment variables (AZURE_TENANT_ID).
3219+
Required for other authentication methods.
32163220
minLength: 1
32173221
type: string
32183222
useManagedIdentity:
@@ -3224,8 +3228,6 @@ spec:
32243228
- System-assigned managed identity (when clientID is not specified)
32253229
- User-assigned managed identity (when clientID is specified)
32263230
type: boolean
3227-
required:
3228-
- tenantID
32293231
type: object
32303232
x-kubernetes-validations:
32313233
- message: When useManagedIdentity is true, clientSecretRef and oidcExchangeToken
@@ -3235,10 +3237,6 @@ spec:
32353237
(!has(self.clientSecretRef) && !has(self.oidcExchangeToken)) :
32363238
((has(self.clientSecretRef) && !has(self.oidcExchangeToken)) ||
32373239
(!has(self.clientSecretRef) && has(self.oidcExchangeToken)))'
3238-
- message: clientID is optional for system-assigned managed identity
3239-
but required otherwise
3240-
rule: 'has(self.useManagedIdentity) && self.useManagedIdentity &&
3241-
!has(self.clientID) ? true : has(self.clientID)'
32423240
gcpCredentials:
32433241
description: GCPCredentials is a mechanism to access a backend(s).
32443242
GCP specific logic will be applied.

site/docs/getting-started/connect-providers/azure-openai.md

Lines changed: 33 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,27 +11,27 @@ import vars from '../../\_vars.json';
1111

1212
This guide will help you configure Envoy AI Gateway to work with Azure OpenAI's foundation models.
1313

14-
There are two ways to do the [Azure OpenAI authentication](https://learn.microsoft.com/en-us/azure/ai-services/openai/reference#authentication): Microsoft Entra ID and API Key.
14+
Azure OpenAI supports two authentication methods:
1515

16-
We will use Microsoft Entra ID to authenticate an application to use the Azure OpenAI service. You can obtain an access token using the OAuth 2.0 client credentials grant flow. This process involves registering the application in Microsoft Entra ID (formerly Azure Active Directory), configuring the appropriate permissions, and acquiring a token from the Microsoft identity platform. The access token is then used as proof of authorization in API requests to the Azure OpenAI endpoint.
16+
1. **API Key**: Simple authentication using an API key from your Azure OpenAI resource.
1717

18-
For detailed steps, refer to the official [Microsoft documentation](https://learn.microsoft.com/en-us/entra/identity-platform/v2-oauth2-client-creds-grant-flow#get-a-token).
18+
2. **Microsoft Entra ID**: OAuth-based authentication with two options:
19+
- **Client Secret**: Uses client credentials (client ID, tenant ID, and secret)
20+
- **Managed Identity / Workload Identity**: Uses Azure Managed Identity/Workload identity (recommended for production on Azure Kubernetes Clusters)
1921

20-
API Key authentication is not supported yet.
22+
This guide focuses on Microsoft Entra ID authentication. For API Key authentication, refer to the [Azure OpenAI API documentation](https://learn.microsoft.com/en-us/azure/ai-services/openai/reference#authentication).
2123

2224
## Prerequisites
2325

2426
Before you begin, you'll need:
2527

26-
- Azure credentials with access to OpenAI service.
28+
- Azure OpenAI resource with model access enabled (e.g., "GPT-4o")
2729
- Basic setup completed from the [Basic Usage](../basic-usage.md) guide
2830
- Basic configuration removed as described in the [Advanced Configuration](./index.md) overview
2931

30-
## Azure Credential Setup
31-
32-
1. An Azure account with OpenAI service access enabled
33-
2. Your Azure tenant ID, client ID, and client secret key
34-
3. Enabled model access to "GPT-4o"
32+
For Microsoft Entra ID authentication, additionally:
33+
- Azure tenant ID, client ID, and either a client secret OR a configured Managed Identity
34+
- For AKS Workload Identity: See [Azure documentation](https://learn.microsoft.com/en-us/azure/aks/workload-identity-deploy-cluster) for infrastructure setup
3535

3636
## Configuration Steps
3737

@@ -43,15 +43,37 @@ Before you begin, you'll need:
4343

4444
### 2. Configure Azure Credentials
4545

46+
The `azure_openai.yaml` file includes examples for both Entra ID authentication methods. By default, it uses client secret authentication.
47+
48+
#### Client Secret Authentication (Default)
49+
4650
Edit the `azure_openai.yaml` file to replace these placeholder values:
4751

4852
- `AZURE_TENANT_ID`: Your Azure tenant ID
4953
- `AZURE_CLIENT_ID`: Your Azure client ID
5054
- `AZURE_CLIENT_SECRET`: Your Azure client secret
5155

56+
#### Managed Identity / Workload Identity Authentication
57+
58+
To use Workload Identity instead, see the commented examples in `azure_openai.yaml`. And configure the service account annotations during Helm installation:
59+
60+
```shell
61+
helm upgrade --install ai-gateway-controller envoyproxy/ai-gateway-helm \
62+
--set controller.serviceAccount.annotations."azure\.workload\.identity/client-id"="<your-managed-identity-client-id>" \
63+
--set controller.serviceAccount.annotations."azure\.workload\.identity/tenant-id"="<your-tenant-id>" \
64+
--create-namespace \
65+
-n envoy-ai-gateway-system
66+
67+
# Add the required label:
68+
kubectl label serviceaccount ai-gateway-controller \
69+
azure.workload.identity/use=true \
70+
-n envoy-ai-gateway-system
71+
```
72+
73+
Then use the Managed Identity `BackendSecurityPolicy` example from the YAML file (uncomment Option 2, comment out Option 1). Omitting the `CLIENT_ID`, `CLIENT_SECRET` and only specify `useManagedIdentity: true`. When configuring the identity on Azure your federated subject should look something like this `system:serviceaccount:envoy-ai-gateway-system:ai-gateway-controller`.
74+
5275
:::caution Security Note
5376
Keep your Azure credentials secure and never commit them to version control.
54-
The credentials will be stored in Kubernetes secrets.
5577
:::
5678

5779
### 3. Apply Configuration

0 commit comments

Comments
 (0)