共用方式為


使用密碼存放區延伸模組來擷取密碼,以在已啟用 Azure Arc 的 Kubernetes 叢集中離線存取

適用於 Kubernetes 的 Azure 金鑰保存庫 秘密存放區擴充功能 (“SSE”) 會自動將秘密從 Azure 金鑰保存庫 同步至已啟用 Azure Arc 的 Kubernetes 叢集以進行離線存取。 這表示您可以使用 Azure Key Vault 來儲存、維護及輪替您的密碼,即使在半中斷連線的狀態下執行 Kubernetes 叢集時也是如此。 同步的密碼會儲存在叢集密碼存放區中,讓它們以 Kubernetes 密碼的形式提供,以便以一般方式使用:掛接為資料磁碟區,或公開為 Pod 中的容器的環境變數。

同步處理的秘密是重要的商務資產,因此 SSE 會透過隔離的命名空間和節點、角色型存取控制 (RBAC) 原則,以及秘密同步器的許可權有限來保護它們。 如需額外的保護, 請加密 叢集上的 Kubernetes 秘密存放區。

提示

針對需要離線存取的案例,或如果您需要同步處理至 Kubernetes 秘密存放區的秘密,建議使用 SSE。 如果您不需要這些功能,您可以在已啟用 Arc 的 Kubernetes 叢集中,使用 Azure Key Vault 密碼提供者延伸模組進行密碼管理。 不建議同時在叢集中執行在線 Azure 金鑰保存庫 秘密提供者延伸模組和離線 SSE。

本文說明如何安裝和設定 SSE 作為 已啟用 Azure Arc 的 Kubernetes 擴充功能

重要

SSE 目前為預覽狀態。 請參閱 Microsoft Azure 預覽版增補使用規定,以了解適用於 Azure 功能 (搶鮮版 (Beta)、預覽版,或尚未正式發行的版本) 的法律條款。

必要條件

  • 已啟用 Arc 的叢集。 這可以是您自己連線的範例(本指南中的範例會使用 K3s 叢集)或 Azure Arc 叢集所支援的Microsoft受控 AKS。 叢集必須執行 Kubernetes 1.27 版或更高版本,且位於其中一個支援的區域(美國東部、美國東部 2、美國西部、美國西部 2、美國西部3、西歐、北歐)。 區域是由用來建立 Arc 叢集的資源群組區域定義。
  • 確保您符合叢集延伸模組的一般必要條件,包括最新版的 k8s-extension Azure CLI 延伸模組。
  • 需要 cert-manager 才能支援 TLS 進行內追蹤記錄通訊。 本指南稍後的範例會引導您進行安裝。 如需 cert-manager 的詳細資訊,請參閱 cert-manager.io

如果您尚未登入,請安裝 Azure CLI 並登入:

az login

開始之前,請先設定要用於設定 Azure 和叢集資源的環境變數。 如果您已經有受控識別、Azure Key Vault 或此處所列的其他資源,請更新環境變數中的名稱以反映這些資源。

export RESOURCE_GROUP="AzureArcTest"
export CLUSTER_NAME="AzureArcTest1"
export LOCATION="EastUS"
export SUBSCRIPTION="$(az account show --query id --output tsv)"
az account set --subscription "${SUBSCRIPTION}"
export AZURE_TENANT_ID="$(az account show -s $SUBSCRIPTION --query tenantId --output tsv)"
export CURRENT_USER="$(az ad signed-in-user show --query userPrincipalName --output tsv)"
export KEYVAULT_NAME="my-kv"
export KEYVAULT_SECRET_NAME="my-secret"
export USER_ASSIGNED_IDENTITY_NAME="my-identity"
export FEDERATED_IDENTITY_CREDENTIAL_NAME="my-credential"
export KUBERNETES_NAMESPACE="my-namespace"
export SERVICE_ACCOUNT_NAME="my-service-account"

在您的叢集中啟用工作負載身分識別同盟

SSE 會使用稱為工作負載身分識別同盟的功能來存取和同步處理 Azure 金鑰保存庫 秘密。 本節說明如何設定此設定。 下列各節將詳細說明如何使用。

提示

下列步驟是以使用工作負載身分識別同盟設定已啟用Arc的 Kubernetes 的操作指南為基礎。 如需其他協助,請參閱該檔。

如果您的叢集尚未連線到 Azure Arc, 請遵循下列步驟。 在這些步驟中,啟用工作負載身分識別同盟作為命令的 connect 一部分:

az connectedk8s connect --name ${CLUSTER_NAME} --resource-group ${RESOURCE_GROUP} --enable-oidc-issuer --enable-workload-identity

如果您的叢集已連線到 Azure Arc,請使用 update 命令來啟用工作負載身分識別:

az connectedk8s update --name ${CLUSTER_NAME} --resource-group ${RESOURCE_GROUP} --enable-oidc-issuer --enable-workload-identity

現在,請將叢集設定為使用新的簽發者 URL 發出服務帳戶令牌,service-account-issuer讓Microsoft Entra ID 尋找驗證這些令牌所需的公鑰。 這些公鑰適用於叢集自己的服務帳戶令牌簽發者,而且會因為您上述設定的選項而在此 URL --enable-oidc-issuer 取得和雲端裝載這些公鑰。

或者,您也可以藉由設定OwnerReferencesPermissionEnforcement許可控制器,將 SSE 本身的許可權設定為在控制平面中執行的特殊許可權資源限制。 此許可控制器會限制 SSE 可以變更叢集中其他物件多少。

  1. 使用簽發者 URL 欄位和權限強制執行來設定 kube-apiserver。 下列範例適用 k3s 叢集。 您的叢集可能使用不同的方法來變更 API 伺服器引數:--kube-apiserver-arg="--service-account-issuer=${SERVICE_ACCOUNT_ISSUER}" and --kube-apiserver-arg="--enable-admission-plugins=OwnerReferencesPermissionEnforcement"

    • 取得服務帳戶簽發者 URL。

      export SERVICE_ACCOUNT_ISSUER="$(az connectedk8s show --name ${CLUSTER_NAME} --resource-group ${RESOURCE_GROUP} --query "oidcIssuerProfile.issuerUrl" --output tsv)"
      echo $SERVICE_ACCOUNT_ISSUER
      
    • 開啟 K3s 伺服器設定檔。

      sudo nano /etc/systemd/system/k3s.service
      
    • 編輯伺服器組態,看起來像下列範例,將 <SERVICE_ACCOUNT_ISSUER> 取代為 的上述輸出 echo $SERVICE_ACCOUNT_ISSUER,並記得包含此 URL 的尾端正斜線:

      ExecStart=/usr/local/bin/k3s \
        server --write-kubeconfig-mode=644 \
           --kube-apiserver-arg="--service-account-issuer=<SERVICE_ACCOUNT_ISSUER>" \
           --kube-apiserver-arg="--enable-admission-plugins=OwnerReferencesPermissionEnforcement"
      
  2. 重新啟動 kube-apiserver。

    sudo systemctl daemon-reload
    sudo systemctl restart k3s
    

建立秘密並設定身分識別以存取它

若要存取並同步處理指定的 Azure 金鑰保存庫 秘密,SSE 需要存取具有適當 Azure 許可權的 Azure 受控識別,才能存取該秘密。 受控識別必須使用您上述啟動的工作負載身分識別功能,連結到 Kubernetes 服務帳戶。 SSE 會使用相關聯的同盟 Azure 受控識別,將秘密從 Azure 金鑰保存庫 提取到 Kubernetes 秘密存放區。 下列各節描述如何設定。

建立 Azure Key Vault

建立 Azure Key Vault 並新增密碼。 如果您已經有 Azure Key Vault 和密碼,可以略過本節。

  1. 建立 Azure Key Vault:

    az keyvault create --resource-group "${RESOURCE_GROUP}" --location "${LOCATION}" --name "${KEYVAULT_NAME}" --enable-rbac-authorization
    
  2. 為自己提供保存庫的「密碼長」權限,以便建立密碼:

    az role assignment create --role "Key Vault Secrets Officer" --assignee ${CURRENT_USER} --scope /subscriptions/${SUBSCRIPTION}/resourcegroups/${RESOURCE_GROUP}/providers/Microsoft.KeyVault/vaults/${KEYVAULT_NAME}
    
  3. 建立密碼並加以更新,以便您有兩個版本:

    az keyvault secret set --vault-name "${KEYVAULT_NAME}" --name "${KEYVAULT_SECRET_NAME}" --value 'Hello!'
    az keyvault secret set --vault-name "${KEYVAULT_NAME}" --name "${KEYVAULT_SECRET_NAME}" --value 'Hello2'
    

建立使用者指派的受控識別

接下來,建立使用者指派的受控識別,並授與其存取 Azure Key Vault 的權限。 如果您已經有具有 Azure Key Vault 的 Key Vault 讀者和 Key Vault 密碼使用者權限的受控識別,您可以略過本節。 如需詳細資訊,請參閱建立使用者指派的受控識別搭配 Key Vault 使用 Azure RBAC 密碼、金鑰和憑證權限

  1. 建立使用者指派的受控識別:

    az identity create --name "${USER_ASSIGNED_IDENTITY_NAME}" --resource-group "${RESOURCE_GROUP}" --location "${LOCATION}" --subscription "${SUBSCRIPTION}"
    
  2. 提供身分識別 Key Vault 讀者和 Key Vault 密碼使用者權限。 您可能需要稍微等候,讓身分識別建立複寫,這些命令才會成功:

    export USER_ASSIGNED_CLIENT_ID="$(az identity show --resource-group "${RESOURCE_GROUP}" --name "${USER_ASSIGNED_IDENTITY_NAME}" --query 'clientId' -otsv)"
    az role assignment create --role "Key Vault Reader" --assignee "${USER_ASSIGNED_CLIENT_ID}" --scope /subscriptions/${SUBSCRIPTION}/resourcegroups/${RESOURCE_GROUP}/providers/Microsoft.KeyVault/vaults/${KEYVAULT_NAME}
    az role assignment create --role "Key Vault Secrets User" --assignee "${USER_ASSIGNED_CLIENT_ID}" --scope /subscriptions/${SUBSCRIPTION}/resourcegroups/${RESOURCE_GROUP}/providers/Microsoft.KeyVault/vaults/${KEYVAULT_NAME}
    

建立同盟身分識別認證

為需要存取密碼的工作負載建立 Kubernetes 服務帳戶。 然後,建立同盟身分識別認證,以在受控識別、OIDC 服務帳戶簽發者和 Kubernetes 服務帳戶之間建立連結。

  1. 建立將與受控識別建立同盟的 Kubernetes Service 帳戶。 以相關聯使用者指派的受控識別的詳細資料標註它。

    kubectl create ns ${KUBERNETES_NAMESPACE}
    
    cat <<EOF | kubectl apply -f -
      apiVersion: v1
      kind: ServiceAccount
      metadata:
        name: ${SERVICE_ACCOUNT_NAME}
        namespace: ${KUBERNETES_NAMESPACE}
    EOF
    
  2. 建立同盟身分識別認證:

    az identity federated-credential create --name ${FEDERATED_IDENTITY_CREDENTIAL_NAME} --identity-name ${USER_ASSIGNED_IDENTITY_NAME} --resource-group ${RESOURCE_GROUP} --issuer ${SERVICE_ACCOUNT_ISSUER} --subject system:serviceaccount:${KUBERNETES_NAMESPACE}:${SERVICE_ACCOUNT_NAME}
    

安裝 SSE

SSE 可作為 Azure Arc 延伸模組。 已啟用 Azure Arc 的 Kubernetes 叢集可以使用已啟用 Azure Arc 的 Kubernetes 延伸模組來延伸。 延伸模組可在連線的叢集上啟用 Azure 功能,並為延伸模組安裝和生命週期管理提供 Azure Resource Manager 驅動的體驗。

cert-managertrust-manager 也需要安全通訊叢集服務之間的記錄,而且必須在 Arc 延伸模組之前安裝。

  1. 安裝 cert-manager。

    helm repo add jetstack https://charts.jetstack.io/ --force-update
    helm install cert-manager jetstack/cert-manager --namespace cert-manager --create-namespace --version v1.16.2 --set crds.enabled=true 
    
  2. 安裝 trust-manager。

    helm upgrade trust-manager jetstack/trust-manager --install --namespace cert-manager --wait
    
  3. 使用下列命令,將 SSE 安裝到已啟用 Arc 的叢集:

    az k8s-extension create \
      --cluster-name ${CLUSTER_NAME} \
      --cluster-type connectedClusters \
      --extension-type microsoft.azure.secretstore \
      --resource-group ${RESOURCE_GROUP} \
      --release-train preview \
      --name ssarcextension \
      --scope cluster 
    

    如有需要,您可以選擇性地藉由新增 --configuration-settings rotationPollIntervalInSeconds=<time_in_seconds> 來修改預設的輪替輪詢間隔:

    參數名稱 描述 預設值
    rotationPollIntervalInSeconds 指定 SSE 檢查或更新其管理秘密的速度。 3600 (1 小時)

設定 SSE

藉由定義 Kubernetes 自訂資源的執行個體,設定已安裝的延伸模組,其中包含 Azure Key Vault 的相關資訊,以及要同步至叢集的密碼。 您可以建立兩個類型的自訂資源:

  • SecretProviderClass 物件,用來定義 Key Vault 的連線。
  • SecretSync 物件,於要同步的每個密碼。

建立 SecretProviderClass 資源

資源 SecretProviderClass 可用來定義 Azure Key Vault 的連線、用來存取保存庫的身分識別、要同步的密碼,以及要保留在本機的每個密碼的版本數目。

針對您想要同步的每個 Azure Key Vault、用於存取 Azure Key Vault 的每個身分識別,以及用於每個目標 Kubernetes 命名空間的身分識別,都需要個別的 SecretProviderClass

遵循此範例,為您的 Key Vault 和密碼建立具有適當值的一或多個 SecretProviderClass YAML 檔案。

cat <<EOF > spc.yaml
apiVersion: secrets-store.csi.x-k8s.io/v1
kind: SecretProviderClass
metadata:
  name: secret-provider-class-name                      # Name of the class; must be unique per Kubernetes namespace
  namespace: ${KUBERNETES_NAMESPACE}                    # Kubernetes namespace to make the secrets accessible in
spec:
  provider: azure
  parameters:
    clientID: "${USER_ASSIGNED_CLIENT_ID}"               # Managed Identity Client ID for accessing the Azure Key Vault with.
    keyvaultName: ${KEYVAULT_NAME}                       # The name of the Azure Key Vault to synchronize secrets from.
    objects: |
      array:
        - |
          objectName: ${KEYVAULT_SECRET_NAME}            # The name of the secret to sychronize.
          objectType: secret
          objectVersionHistory: 2                       # [optional] The number of versions to synchronize, starting from latest.
    tenantID: "${AZURE_TENANT_ID}"                       # The tenant ID of the Key Vault 
EOF

建立 SecretSync 物件

每個同步的密碼也需要 SecretSync 物件,才能定義叢集特定資訊。 在這裡,您會指定資訊,例如叢集中的密碼名稱,以及儲存在您叢集中之每個密碼版本的名稱。

為每個密碼建立一個 SecretSync 物件 YAML 檔案,遵循此範本。 Kubernetes 命名空間應該符合相符 SecretProviderClass 的命名空間。

cat <<EOF > ss.yaml
apiVersion: secret-sync.x-k8s.io/v1alpha1
kind: SecretSync
metadata:
  name: secret-sync-name                                  # Name of the object; must be unique per Kubernetes namespace
  namespace: ${KUBERNETES_NAMESPACE}                      # Kubernetes namespace
spec:
  serviceAccountName: ${SERVICE_ACCOUNT_NAME}             # The Kubernetes service account to be given permissions to access the secret.
  secretProviderClassName: secret-provider-class-name     # The name of the matching SecretProviderClass with the configuration to access the AKV storing this secret
  secretObject:
    type: Opaque
    data:
    - sourcePath: ${KEYVAULT_SECRET_NAME}/0                # Name of the secret in Azure Key Vault with an optional version number (defaults to latest)
      targetKey: ${KEYVAULT_SECRET_NAME}-data-key0         # Target name of the secret in the Kubernetes secret store (must be unique)
    - sourcePath: ${KEYVAULT_SECRET_NAME}/1                # [optional] Next version of the AKV secret. Note that versions of the secret must match the configured objectVersionHistory in the secrets provider class 
      targetKey: ${KEYVAULT_SECRET_NAME}-data-key1         # [optional] Next target name of the secret in the K8s secret store
EOF

套用設定 CR

使用 kubectl apply 命令套用設定自訂資源 (CR):

kubectl apply -f ./spc.yaml
kubectl apply -f ./ss.yaml

SSE 會自動尋找秘密,並開始將它們同步至叢集。

檢視設定選項

若要檢視這兩個自訂資源類型的其他設定選項,請使用 kubectl describe 命令來檢查叢集中的 CRD:

# Get the name of any applied CRD(s)
kubectl get crds -o custom-columns=NAME:.metadata.name

# View the full configuration options and field parameters for a given CRD
kubectl describe crd secretproviderclass
kubectl describe crd secretsync

觀察同步至叢集的密碼

套用組態之後,秘密就會在安裝 SSE 時指定的頻率自動同步至叢集。

檢視同步的密碼

執行下列命令來檢視同步至叢集的密碼:

# View a list of all secrets in the namespace
kubectl get secrets -n ${KUBERNETES_NAMESPACE}

# View details of all secrets in the namespace
kubectl get secrets -n ${KUBERNETES_NAMESPACE} -o yaml

檢視上次同步狀態

若要檢視指定密碼的最新同步狀態,請使用 kubectl describe 命令取得 SecretSync 物件。 輸出包含密碼建立時間戳記、密碼版本,以及每個同步事件的詳細狀態訊息。 此輸出可用來診斷連線或設定錯誤,以及觀察密碼值何時變更。

kubectl describe secretsync secret-sync-name -n ${KUBERNETES_NAMESPACE}

檢視密碼值

若要檢視同步的密碼值 (現在儲存在 Kubernetes 密碼存放區中),請使用下列命令:

kubectl get secret secret-sync-name -n ${KUBERNETES_NAMESPACE} -o jsonpath="{.data.${KEYVAULT_SECRET_NAME}-data-key0}" | base64 -d
kubectl get secret secret-sync-name -n ${KUBERNETES_NAMESPACE} -o jsonpath="{.data.${KEYVAULT_SECRET_NAME}-data-key1}" | base64 -d

疑難排解

SSE 是 Kubernetes 部署,其中包含具有兩個容器的 Pod:控制器,其會管理在叢集中儲存秘密,以及管理 Azure 金鑰保存庫 存取權和提取秘密的提供者。 每個同步的密碼都有一個 SecretSync 物件,其包含該密碼從 Azure Key Vault 同步至叢集密碼存放區的狀態。

若要針對問題進行疑難排解,請從查看 SecretSync 物件的狀態開始,如檢視上次同步狀態中所述。 下表列出常見的狀態類型、其意義,以及解決錯誤的潛在疑難排解步驟。

SecretSync 狀態類型 詳細資料 進一步修正/調查的步驟
CreateSucceeded 已成功建立密碼。 n/a
CreateFailedProviderError 密碼建立失敗,因為提供者發生一些問題 (與 Azure Key Vault 的連線)。 此失敗可能是因為網際網路連線、同步密碼的身分識別權限不足、SecretProviderClass 設定錯誤或其他問題所造成。 使用下列命令查看提供者的記錄,以進一步調查:
kubectl get pods -n azure-secret-store
kubectl logs <secret-sync-controller-pod-name> -n azure-secret-store --container='provider-azure-installer'
CreateFailedInvalidLabel 秘密建立失敗,因為秘密已經存在,而沒有 SSE 用來管理其秘密的正確 Kubernetes 標籤。 移除現有的標籤和秘密,並允許 SSE 重新建立秘密: kubectl delete secret <secret-name>
若要強制 SSE 重新建立比設定的輪替輪詢間隔快的秘密,請刪除 SecretSync 物件 (kubectl delete secretsync <secret-name>) 並重新套用秘密同步類別 (kubectl apply -f <path_to_secret_sync>)。
CreateFailedInvalidAnnotation 秘密建立失敗,因為秘密已經存在,而沒有 SSE 用來管理其秘密的正確 Kubernetes 批注。 移除現有的批注和秘密,並允許 SSE 重新建立秘密: kubectl delete secret <secret-name>
若要強制 SSE 重新建立比設定的輪替輪詢間隔快的秘密,請刪除 SecretSync 物件 (kubectl delete secretsync <secret-name>) 並重新套用秘密同步類別 (kubectl apply -f <path_to_secret_sync>)。
UpdateNoValueChangeSucceeded SSE 會在設定的輪詢間隔結束時檢查 Azure 金鑰保存庫 是否有更新,但沒有同步的變更。 n/a
UpdateValueChangeOrForceUpdateSucceeded SSE 已檢查 Azure 金鑰保存庫 是否有更新,並已成功更新值。 n/a
UpdateFailedInvalidLabel 秘密更新失敗,因為 SSE 用來管理其秘密的標籤已修改。 移除現有的標籤和秘密,並允許 SSE 重新建立秘密: kubectl delete secret <secret-name>
若要強制 SSE 重新建立比設定的輪替輪詢間隔快的秘密,請刪除 SecretSync 物件 (kubectl delete secretsync <secret-name>) 並重新套用秘密同步類別 (kubectl apply -f <path_to_secret_sync>)。
UpdateFailedInvalidAnnotation 秘密更新失敗,因為 SSE 用來管理秘密的秘密註釋已修改。 移除現有的批注和秘密,並允許 SSE 重新建立秘密: kubectl delete secret <secret-name>
若要強制 SSE 重新建立比設定的輪替輪詢間隔快的秘密,請刪除 SecretSync 物件 (kubectl delete secretsync <secret-name>) 並重新套用秘密同步類別 (kubectl apply -f <path_to_secret_sync>)。
UpdateFailedProviderError 密碼更新失敗,因為提供者發生一些問題 (與 Azure Key Vault 的連線)。 此失敗可能是因為網際網路連線、同步密碼的身分識別權限不足、SecretProviderClass 的設定或其他問題所造成。 使用下列命令查看提供者的記錄,以進一步調查:
kubectl get pods -n azure-secret-store
kubectl logs <secret-sync-controller-pod-name> -n azure-secret-store --container='provider-azure-installer'
UserInputValidationFailed 密碼更新失敗,因為密碼同步類別設定不正確 (例如無效的密碼類型)。 檢閱密碼同步類別定義,並更正任何錯誤。 然後,刪除 SecretSync 物件 (kubectl delete secretsync <secret-name>)、刪除密碼同步類別 (kubectl delete -f <path_to_secret_sync>),然後重新套用密碼同步類別 (kubectl apply -f <path_to_secret_sync>)。
ControllerSpcError 秘密更新失敗,因為 SSE 無法取得提供者類別或提供者類別設定錯誤。 檢閱提供者類別並更正任何錯誤。 然後,刪除 SecretSync 物件 (kubectl delete secretsync <secret-name>)、刪除提供者類別 (kubectl delete -f <path_to_provider>),然後重新套用提供者類別 (kubectl apply -f <path_to_provider>)。
ControllerInternalError 秘密更新失敗,因為 SSE 發生內部錯誤。 如需詳細資訊,請查看 SSE 記錄或事件:
kubectl get pods -n azure-secret-store
kubectl logs <secret-sync-controller-pod-name> -n azure-secret-store --container='manager'
SecretPatchFailedUnknownError 修補 Kubernetes 密碼值期間密碼更新失敗。 如果 SSE 以外的人員修改秘密,或 SSE 更新期間發生問題,就可能發生此失敗。 嘗試刪除秘密和 SecretSync 物件,然後重新套用秘密同步CR,讓 SSE 重新建立秘密:
kubectl delete secret <secret-name>
kubectl delete secretsync <secret-name>
kubectl apply -f <path_to_secret_sync>

拿掉 SSE

若要移除 SSE 並停止同步處理秘密,請使用 az k8s-extension delete 命令將其卸載:

az k8s-extension delete --name ssarcextension --cluster-name $CLUSTER_NAME  --resource-group $RESOURCE_GROUP  --cluster-type connectedClusters    

解除安裝延伸模組不會從叢集移除密碼、SecretSync 物件或 CRD。 這些物件必須使用 kubectl 直接移除。

刪除 SecretSync CRD 會移除所有 SecretSync 物件,且預設會移除所有擁有的密碼,但如果發生下列狀況,可能會保存密碼:

在上述情況下,必須使用 kubectl 直接刪除密碼。

下一步