➜ Old React website
Chung Cheuk Hang MichaelJava Web Developer
跨程式語言 RSA、AES 加密80 個 Spring Boot annotations

Azure Workload Identity

Table of contents

1 Azure Workload Identity 簡介

顧名思義,Azure Workload Identity 係一種用到 workload 黎做身份驗證既驗證方式。呢種驗證方式可以用喺 Azure K8s(AKS),令我地既 microservices 唔需要用到 password 都可以驗證到 Azure PaaS。
因為係 passwordless 既驗證方式,我地可以同舊時用到 password 既驗證方式(例如 Azure Service Principal 既 client secret)say goodbye。

1.1 好處

Passwordless 既驗證方式既好處有:
  • 通常 password 既 expiry 都好長,所以因為唔再存在 password,就會冇咁容易 leak 到,從而避免被黑客攻擊。
  • 作為用家,唔需要去考慮更新任何野。
    • 如果係用 Azure Service Principal 既 client secret,一般都會有 expiry,咁我地就需要每隔一段時間去更新個 client secret,再更新所有 client secret 既 references。如果數量多,就會好難管理。

1.2 Service principal vs user-assigned managed identity

我地可以用 service principal(SPN)或者 user-assigned managed identity 去做 Workload Identity,但因為 SPN 比較好,所以我地應該揀用 SPN。

1.2.1 共通點

  • User-assigned managed identity 係 SPN 既一種,所以兩者好相似。
  • 我地可以喺 Azure PaaS 裡面新增 role assignments 黎授權兩者使用呢個 Azure PaaS。
  • 兩者都可以新增 federated credential。
  • 兩者都係支援最多 20 個 federated credentials。

1.2.2 差異

  • SPN 一定會有一個關聯既 application object,但 user-assigned managed identity 就冇。
  • User-assigned managed identity 唔係 multi-tenant(Azure tenant)。
  • User-assigned managed identity 有一個反向授權既操作方式,可以畀我地喺個 managed identity 裡面新增 role assignments。呢個功能目前喺 preview 階段。
  • 某啲 Azure regions 唔支援喺 user-assigned managed identity 裡面新增 federated credential。

2 準備功夫

  • 我地既 AKS cluster 需要 enable OpenID Connect(OIDC)以及 Workload Identity。
  • 我地需要有一個 K8s ServiceAccount
  • 我地既 K8s Deployment 既 pod template:
    • 需要有 azure.workload.identity/use: "true" 既 pod label,用黎 enable Workload Identity。
    • 需要用 serviceAccountName 去 reference 個 K8s ServiceAccount
  • 我地既 Azure SPN 需要新增一個 federated credential。
    • Scenario:Kubernetes accessing Azure resources
    • Cluster issuer URL:OIDC issuer URL
    • Namespace:我地個 K8s Pod 所屬既 K8s Namespace
    • Service account name:我地既 K8s ServiceAccount
    • Name:任何 value 都可以,日後冇需要 reference 呢個 value。

3 原理

  1. 我地運行一個 K8s Pod
  2. AKS platform 會見到個 K8s Pod 想用 Workload Identity 以及佢所 reference 既 K8s ServiceAccount,然後生成一個 service account JWT token 喺 container 既 /var/run/secrets/azure/tokens/azure-identity-token 檔案作為 volume mount。
  3. 當我地既 K8s Pod 裡面既 container 運行緊既 microservice 需要使用一個 Azure PaaS,就會用到 Azure Identity SDK 去做驗證。
    1. Azure Identity SDK 會喺上述檔案讀取 service account JWT token,然後透過 Azure Active Directory 去獲得一個 Azure AD token。
    2. Azure Active Directory 會透過 OpenID Connect 既方式,訪問 AKS cluster 既 OIDC issuer URL 去驗證 Azure AD token。
    3. 如果驗證成功,Azure Active Directory 會返回一個 Azure AD token。
    4. Azure SDK 會用呢個 Azure AD token 去驗證目標既 Azure PaaS。
    5. 如果驗證成功,呢個 K8s Pod 裡面既 container 運行緊既 microservice 就可以操作目標既 Azure PaaS。

3.1 Azure Identity SDK

Azure Identity SDK 會根據以下既野去做驗證:
  • 我地傳入 Azure SDK TokenCredential object 既 parameters,例如 Azure SPN client ID。
    • final TokenCredential credential = new DefaultAzureCredentialBuilder() .workloadIdentityClientId("<Azure SPN client ID>") .build();
  • Container 既 environment variables,包括:
    • AZURE_CLIENT_ID(如果用 K8s ServiceAccountazure.workload.identity/client-id annotation 黎傳入 Azure SPN client ID,AKS platform 就會自動 set 呢個 environment variable)
    • AZURE_TENANT_ID
    • AZURE_FEDERATED_TOKEN_FILE(默認係 /var/run/secrets/azure/tokens/azure-identity-token
  • Container 既 service account JWT token 檔案(path 係 AZURE_FEDERATED_TOKEN_FILE environment variable 既 value)。

4 Java 例子

4.1 Spring Boot/Cloud Azure 配置例子

我地可以直接用 Spring Boot、Spring Cloud Azure 既 auto-configuration 方式,令底層既 Azure SDK 幫我地用 Workload Identity。
呢個方法唔需要將 Azure SPN client ID 放入 K8s ServiceAccount

4.1.1 Azure SQL

重點既 Maven dependencies:
TypeGroup IDArtifact IDVersion
Dependency managementorg.springframework.bootspring-boot-starter-parent3.3.1
Dependency managementcom.azure.springspring-cloud-azure-dependencies5.14.0
Dependencycom.azureazure-identity(Managed by Azure BOM)
Dependencyorg.springframework.bootspring-boot-starter-data-jpa(Managed by Spring BOM)
Dependencycom.microsoft.sqlservermssql-jdbc(Managed by Spring BOM)
Spring Data JDBC 配置:
spring: datasource: url: "jdbc://sqlserver://xxxxxx.database.windows.net:1433;databaseName=xxxxxx;authentication=ActiveDirectoryDefault" username: "<Azure SPN client ID>"

4.1.2 Azure Service Bus

重點既 Maven dependencies:
TypeGroup IDArtifact IDVersion
Dependency managementcom.azure.springspring-cloud-azure-dependencies5.14.0
Dependencycom.azureazure-identity(Managed by Azure BOM)
Dependencycom.azure.springspring-cloud-azure-stream-binder-servicebus(Managed by Azure BOM)
Spring Cloud Stream + ASB binder 配置:
1spring: 2 cloud: 3 function: 4 definition: demoConsume;demoProduce 5 6 stream: 7# default-binder: demoBinder1 # 因為我地有 2 個 binders,所以唔需要配置 default binder 8 output-bindings: demoProduce-out-0 9 10 binders: 11 demoBinder1: 12 type: servicebus 13 environment: 14 spring.cloud.azure.credential.managed-identity-enabled: true 15 spring.cloud.azure.credential.client-id: "<Azure SPN client ID>" 16 spring.cloud.azure.servicebus.namespace: xxxxxx 17 demoBinder2: 18 type: servicebus 19 environment: 20 spring.cloud.azure.credential.managed-identity-enabled: true 21 spring.cloud.azure.credential.client-id: "<Azure SPN client ID>" 22 spring.cloud.azure.servicebus.namespace: xxxxxx 23 24 bindings: 25 demoProduce-out-0: 26 destination: demo-topic-1 27 binder: demoBinder1 28 demoConsume-in-0: 29 destination: demo-topic-1 30 group: demo-subscription-1 31 binder: demoBinder2 32 33 servicebus: 34 bindings: 35 demoProduce-out-0: 36 producer: 37 entity-type: topic 38 demoConsume-in-0: 39 consumer: 40 entity-type: topic 41 auto-complete: true

4.2 Azure SDK for Java 例子

4.2.1 Azure Service Bus

重點既 Maven dependencies:
TypeGroup IDArtifact IDVersion
Dependency managementcom.azureazure-sdk-bom1.2.25
Dependencycom.azureazure-identity(Managed by Azure BOM)
Dependencycom.azureazure-messaging-servicebus(Managed by Azure BOM)
Java code:
1final TokenCredential credential = new DefaultAzureCredentialBuilder() 2 .workloadIdentityClientId("<Azure SPN client ID>") 3 .build(); 4 5final ServiceBusSenderClient senderClient = new ServiceBusClientBuilder() 6 .fullyQualifiedNamespace("xxxxxx.servicebus.windows.net") 7 .credential(credential) 8 .sender() 9 .topicName("<ASB topic>") 10 .buildClient();

4.2.2 Azure Key Vault

重點既 Maven dependencies:
TypeGroup IDArtifact IDVersion
Dependency managementcom.azureazure-sdk-bom1.2.25
Dependencycom.azureazure-identity(Managed by Azure BOM)
Dependencycom.azureazure-security-keyvault-secrets(Managed by Azure BOM)
Java code:
1final TokenCredential credential = new DefaultAzureCredentialBuilder() 2 .workloadIdentityClientId("<Azure SPN client ID>") 3 .build(); 4 5final SecretClient secretClient = new SecretClientBuilder() 6 .vaultUrl("https://xxxxxx.vault.azure.net") 7 .credential(credential) 8 .buildClient();

5 注意事項

注意事項意味
一個 Azure subscription 只支援最多 4000 個 role assignments如果一個 microservice 用一個或多個 SPNs 黎驗證 Azure PaaS,喺一間擁有過千 microservices 既大企業裡面,呢個會係一個需要考慮既因素。
一個 Azure SPN 只支援最多 20 個 federated credentials因為 federated credential 係 per K8s ServiceAccount,如果多個 microservices 會用不同既 K8s ServiceAccount 而都係共用同一個 Azure SPN,就好易會達到上限。

6 參考資料