Skip to content

Commit a4fb1d3

Browse files
committed
Implement workload identity support
1 parent 4b3b8f6 commit a4fb1d3

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
@@ -234,21 +234,24 @@ type BackendSecurityPolicyGCPCredentials struct {
234234
// Otherwise, exactly one of ClientSecretRef or OIDCExchangeToken must be specified.
235235
//
236236
// +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"
237-
// +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"
238237
type BackendSecurityPolicyAzureCredentials struct {
239238
// ClientID is a unique identifier for an application in Azure.
240-
// This field is optional when using system-assigned managed identity,
241-
// but required for user-assigned managed identity and other authentication methods.
239+
// This field is optional when using managed identity or workload identity,
240+
// as the value will be provided via environment variables (AZURE_CLIENT_ID).
241+
// Required for other authentication methods.
242242
//
243243
// +optional
244244
// +kubebuilder:validation:MinLength=1
245-
ClientID string `json:"clientID"`
245+
ClientID string `json:"clientID,omitempty"`
246246

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

253256
// ClientSecretRef is the reference to the secret containing the Azure client secret.
254257
// 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
@@ -1655,8 +1655,9 @@ spec:
16551655
clientID:
16561656
description: |-
16571657
ClientID is a unique identifier for an application in Azure.
1658-
This field is optional when using system-assigned managed identity,
1659-
but required for user-assigned managed identity and other authentication methods.
1658+
This field is optional when using managed identity or workload identity,
1659+
as the value will be provided via environment variables (AZURE_CLIENT_ID).
1660+
Required for other authentication methods.
16601661
minLength: 1
16611662
type: string
16621663
clientSecretRef:
@@ -3063,8 +3064,11 @@ spec:
30633064
- oidc
30643065
type: object
30653066
tenantID:
3066-
description: TenantId is a unique identifier for an Azure Active
3067-
Directory instance.
3067+
description: |-
3068+
TenantId is a unique identifier for an Azure Active Directory instance.
3069+
This field is optional when using workload identity with service account annotations,
3070+
as the value will be provided via environment variables (AZURE_TENANT_ID).
3071+
Required for other authentication methods.
30683072
minLength: 1
30693073
type: string
30703074
useManagedIdentity:
@@ -3076,8 +3080,6 @@ spec:
30763080
- System-assigned managed identity (when clientID is not specified)
30773081
- User-assigned managed identity (when clientID is specified)
30783082
type: boolean
3079-
required:
3080-
- tenantID
30813083
type: object
30823084
x-kubernetes-validations:
30833085
- message: When useManagedIdentity is true, clientSecretRef and oidcExchangeToken
@@ -3087,10 +3089,6 @@ spec:
30873089
(!has(self.clientSecretRef) && !has(self.oidcExchangeToken)) :
30883090
((has(self.clientSecretRef) && !has(self.oidcExchangeToken)) ||
30893091
(!has(self.clientSecretRef) && has(self.oidcExchangeToken)))'
3090-
- message: clientID is optional for system-assigned managed identity
3091-
but required otherwise
3092-
rule: 'has(self.useManagedIdentity) && self.useManagedIdentity &&
3093-
!has(self.clientID) ? true : has(self.clientID)'
30943092
gcpCredentials:
30953093
description: GCPCredentials is a mechanism to access a backend(s).
30963094
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
@@ -8,27 +8,27 @@ sidebar_position: 3
88

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

11-
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.
11+
Azure OpenAI supports two authentication methods:
1212

13-
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.
13+
1. **API Key**: Simple authentication using an API key from your Azure OpenAI resource.
1414

15-
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).
15+
2. **Microsoft Entra ID**: OAuth-based authentication with two options:
16+
- **Client Secret**: Uses client credentials (client ID, tenant ID, and secret)
17+
- **Managed Identity / Workload Identity**: Uses Azure Managed Identity/Workload identity (recommended for production on Azure Kubernetes Clusters)
1618

17-
API Key authentication is not supported yet.
19+
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).
1820

1921
## Prerequisites
2022

2123
Before you begin, you'll need:
2224

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

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

3333
## Configuration Steps
3434

@@ -40,15 +40,37 @@ curl -O https://raw.githubusercontent.com/envoyproxy/ai-gateway/main/examples/ba
4040

4141
### 2. Configure Azure Credentials
4242

43+
The `azure_openai.yaml` file includes examples for both Entra ID authentication methods. By default, it uses client secret authentication.
44+
45+
#### Client Secret Authentication (Default)
46+
4347
Edit the `azure_openai.yaml` file to replace these placeholder values:
4448

4549
- `AZURE_TENANT_ID`: Your Azure tenant ID
4650
- `AZURE_CLIENT_ID`: Your Azure client ID
4751
- `AZURE_CLIENT_SECRET`: Your Azure client secret
4852

53+
#### Managed Identity / Workload Identity Authentication
54+
55+
To use Workload Identity instead, see the commented examples in `azure_openai.yaml`. And configure the service account annotations during Helm installation:
56+
57+
```shell
58+
helm upgrade --install ai-gateway-controller envoyproxy/ai-gateway-helm \
59+
--set controller.serviceAccount.annotations."azure\.workload\.identity/client-id"="<your-managed-identity-client-id>" \
60+
--set controller.serviceAccount.annotations."azure\.workload\.identity/tenant-id"="<your-tenant-id>" \
61+
--create-namespace \
62+
-n envoy-ai-gateway-system
63+
64+
# Add the required label:
65+
kubectl label serviceaccount ai-gateway-controller \
66+
azure.workload.identity/use=true \
67+
-n envoy-ai-gateway-system
68+
```
69+
70+
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`.
71+
4972
:::caution Security Note
5073
Keep your Azure credentials secure and never commit them to version control.
51-
The credentials will be stored in Kubernetes secrets.
5274
:::
5375

5476
### 3. Apply Configuration

0 commit comments

Comments
 (0)