在 AKS 整合 Workload Identity
一步步整合 Azure AD Workload Identity 與 AKS,讓 Pod 透過 managed identity 安全存取 Azure 資源,免管理密鑰。
本指南將說明如何把 Azure AD Workload Identity 整合到 Azure Kubernetes Service (AKS)。透過這個整合,AKS 上的工作負載可以使用 managed identity 安全地存取 Azure 資源,而不需要在應用程式中直接管理密鑰或認證。
Prerequisites
Account Permission
開始之前,請確認以下事項:
- 你已經以使用者身分登入 Azure CLI。
- 你登入的帳號具備在 Azure 中建立 user-assigned managed identity 的足夠權限。
Tools
- Azure CLI 版本 ≥ 2.42.0
- Helm 3
Managed Cluster
- 版本 ≥ v1.22 的 Kubernetes 叢集
Components Installation
OIDC
OpenID Connect metadata URL 是 identity provider 的 issuer 位置;Azure AD 會在 token exchange protocol 中用它來驗證 token,接著才以 user-assigned managed identity 的身分簽發 token。
如果你還沒有任何叢集,執行以下指令建立:
az aks create \
--resource-group myResourceGroup \
--name myAKSCluster \
--node-count 1 \
--enable-oidc-issuer \
--generate-ssh-keys如果已有叢集,則用以下指令更新:
az aks update --resource-group myResourceGroup --name myAKSCluster --enable-oidc-issuer接著取得叢集的 OIDC issuer URL,稍後會用到:
az aks show --resource-group <resource_group> --name <cluster_name> --query "oidcIssuerProfile.issuerUrl" -otsvMutating Admission Webhook
它具備以下功能:
- 將簽署過的 service account token 投射到一個已知的路徑。
- 依據加上註解的 service account,把與驗證相關的環境變數注入到你的 Pod。
Install by Azure CLI
az aks update --resource-group myResourceGroup --name myAKSCluster --enable-workload-identityInstall by Helm
可以參考這份文件。
執行上述指令後,AKS 叢集會建立一個 workload identity controller。
Export Environment Variables
先確認我們目前已經有的東西:
- OIDC issuer URL
- AKS 中為 Workload Identity Webhook 建立的資源
進入下一步之前,先匯出以下環境變數:
export RESOURCE_GROUP="azwi-quickstart-$(openssl rand -hex 2)"
export USER_ASSIGNED_IDENTITY_NAME="<your user-assigned managed identity name>"
export SERVICE_ACCOUNT_NAMESPACE="default"
export SERVICE_ACCOUNT_NAME="workload-identity-sa"
export SERVICE_ACCOUNT_ISSUER="<your service account issuer URL>"Create a User-Assigned Managed Identity and Grant Permissions to Access Your Resources
建立一個將與 service account 綁定的 managed identity:
az identity create --name "${USER_ASSIGNED_IDENTITY_NAME}" --resource-group "${RESOURCE_GROUP}"接著為它指派角色。舉例來說,如果你想讓 Pod 能列出叢集憑證,可以為這個 managed identity 指派 Azure Kubernetes Service Cluster Admin Role。
Create a Kubernetes Service Account
建立一個用來綁定 managed identity 的 service account:
export USER_ASSIGNED_IDENTITY_CLIENT_ID="$(az identity show --name "${USER_ASSIGNED_IDENTITY_NAME}" --resource-group "${RESOURCE_GROUP}" --query 'clientId' -otsv)"
export USER_ASSIGNED_IDENTITY_OBJECT_ID="$(az identity show --name "${USER_ASSIGNED_IDENTITY_NAME}" --resource-group "${RESOURCE_GROUP}" --query 'principalId' -otsv)"cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: ServiceAccount
metadata:
annotations:
azure.workload.identity/client-id: ${USER_ASSIGNED_IDENTITY_CLIENT_ID}
name: ${SERVICE_ACCOUNT_NAME}
namespace: ${SERVICE_ACCOUNT_NAMESPACE}
EOF如果你的 managed identity 與 service account 位於不同 tenant,你應該替 service account 加上註解,讓 workload identity manager 能夠辨識它。
Establish Federated Identity Credential Between the Identity and the Service Account Issuer & Subject
把 service account 與 managed identity 綁定:
az identity federated-credential create \
--name "kubernetes-federated-credential" \
--identity-name "${USER_ASSIGNED_IDENTITY_NAME}" \
--resource-group "${RESOURCE_GROUP}" \
--issuer "${SERVICE_ACCOUNT_ISSUER}" \
--subject "system:serviceaccount:${SERVICE_ACCOUNT_NAMESPACE}:${SERVICE_ACCOUNT_NAME}"Deploy Workload
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: quick-start
namespace: ${SERVICE_ACCOUNT_NAMESPACE}
labels:
azure.workload.identity/use: "true"
spec:
serviceAccountName: ${SERVICE_ACCOUNT_NAME}
containers:
- image: mcr.microsoft.com/azure-cli
name: oidc
command: ["tail", "-f", "/dev/null"] # 執行 tail -f /dev/null 讓容器保持運作
resources:
requests:
memory: "256Mi" # 要求 256 MiB 記憶體
cpu: "100m" # 要求 100 millicpu (0.1 CPU core)
limits:
memory: "512Mi" # 限制 512 MiB 記憶體
cpu: "500m" # 限制 500 millicpu (0.5 CPU core)
nodeSelector:
kubernetes.io/os: linux
EOF你會看到 AZURE_AUTHORITY_HOST、AZURE_CLIENT_ID、AZURE_TENANT_ID、AZURE_FEDERATED_TOKEN_FILE 都被注入到 quick-start。各屬性的意義可參考這份文件。
kubectl describe pod quick-startVerification
你可以連進 quick-start 這個 Pod,執行以下指令:
az login --service-principal --tenant $AZURE_TENANT_ID --federated-token "$(cat ${AZURE_FEDERATED_TOKEN_FILE})" -u $AZURE_CLIENT_ID我們也可以用 init container 在一開始就取得憑證,後續再使用:
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: quick-start
namespace: ${SERVICE_ACCOUNT_NAMESPACE}
labels:
azure.workload.identity/use: "true"
spec:
serviceAccountName: ${SERVICE_ACCOUNT_NAME}
initContainers:
- name: azure-login
image: mcr.microsoft.com/azure-cli
command:
- /bin/sh
- -c
# 1. 需要加上跳脫符號,因為環境變數不應由目前的 shell 直接展開
# 2. 需要確保 kube config 的 ACL,否則會出現權限錯誤
- |
az login --service-principal --tenant \$AZURE_TENANT_ID --federated-token "\$(cat \$AZURE_FEDERATED_TOKEN_FILE)" -u \$AZURE_CLIENT_ID && \
az aks get-credentials --resource-group myResourceGroup --name myAKSCluster --admin --file /custom/.kube/config && \
addgroup -S myUser && \
adduser -S myUser -G myUser && \
chown myUser /custom/.kube/config
volumeMounts:
- name: aks-credentials
mountPath: /custom
resources:
requests:
memory: "256Mi"
cpu: "200m"
limits:
memory: "256Mi"
cpu: "200m"
containers:
- image: my-workload:latest
name: Workload
command: ["tail", "-f", "/dev/null"] # 讓容器保持運作
volumeMounts:
- name: aks-credentials
mountPath: /custom
env:
- name: KUBECONFIG
value: /custom/.kube/config
resources:
requests:
memory: "512Mi"
cpu: "500m"
limits:
memory: "512Mi"
cpu: "500m"
volumes:
- name: aks-credentials
emptyDir: {}
nodeSelector:
kubernetes.io/os: linux
EOF