你当前正在访问 Microsoft Azure Global Edition 技术文档网站。 如果需要访问由世纪互联运营的 Microsoft Azure 中国技术文档网站,请访问 https://docs.azure.cn。
使用机密存储扩展提取用于在已启用 Azure Arc 的 Kubernetes 群集中进行脱机访问的机密
适用于 Kubernetes 的 Azure Key Vault 机密存储扩展(“SSE”)自动将机密从 Azure Key Vault 同步到已启用 Azure Arc 的 Kubernetes 群集以供脱机访问。 这意味着,即使以半断开连接状态运行 Kubernetes 群集,也可使用 Azure Key Vault 存储、维护和轮换机密。 同步的机密存储在群集机密存储中,使其可作为 Kubernetes 机密以所有常用方式使用:作为数据卷装载,或作为环境变量公开给 Pod 中的容器。
同步的机密是关键业务资产,因此 SSE 通过隔离的命名空间和节点、基于角色的访问控制 (RBAC) 策略以及机密同步器的有限权限来保护它们。 为了获得额外的保护,对群集上的 Kubernetes 机密存储进行加密。
提示
对于必需进行脱机访问的场景,或者若需要将机密同步到 Kubernetes 机密存储中,建议使用 SSE。 如果不需要这些功能,可使用 Azure Key Vault 机密提供程序扩展,在已启用 Arc 的 Kubernetes 群集中管理机密。 不建议在群集中并行运行联机 Azure Key Vault 机密提供程序扩展和脱机 SSE。
本文介绍如何将 SSE 安装并配置为已启用 Azure Arc 的 Kubernetes 扩展。
重要
SSE 目前为预览版。 有关 beta 版本、预览版或尚未正式发布的版本的 Azure 功能所适用的法律条款,请参阅 Microsoft Azure 预览版的补充使用条款。
先决条件
- 一个已连接到 Azure Arc、运行 Kubernetes 版本 1.27 或更高版本且位于支持的区域(美国东部、美国东部 2、美国西部、美国西部 2、美国西部 3、西欧、北欧)之一的群集。 该区域由用于创建 Arc 群集的资源组区域定义。
- 本指南中的示例使用 K3s 群集。
- 确保满足群集扩展的常规先决条件,包括最新版本的
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"
配置标识以访问机密
若要访问并同步给定的 Azure Key Vault 机密,SSE 需要访问具有相应 Azure 权限以访问该机密的 Azure 托管标识。 该托管标识必须通过工作负载联合身份验证链接到 Kubernetes 服务帐户。 该 Kubernetes 服务帐户是你在 Kubernetes Pod 或其他工作负载中用于从 Kubernetes 机密存储访问机密的帐户。 SSE 使用关联的联合 Azure 托管标识,将机密从 Azure Key Vault 拉取到 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
) 颁发服务帐户令牌,该 URL 使 Microsoft Entra ID 能够找到验证这些令牌所需的公钥。 这些公钥适用于群集自己的服务帐户令牌颁发者,由于你在上面设置的 --enable-oidc-issuer
选项,它们是在该 URL 上获取和托管的。
另外,你可选择通过配置 OwnerReferencesPermissionEnforcement
许可控制器,将 SSE 自身的权限限制配置为在控制平面中运行的特权资源。 此许可控制器限制了 SSE 可在多大程度上更改群集中的其他对象。
Kubernetes 群集必须运行 Kubernetes 版本 1.27 或更高版本。
使用颁发者 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"
重启 kube-apiserver。
sudo systemctl daemon-reload sudo systemctl restart k3s
创建 Azure Key Vault
创建 Azure Key Vault 并添加机密。 如果已有一个 Azure Key Vault 和机密,可跳过此节。
创建 Azure 密钥保管库:
az keyvault create --resource-group "${RESOURCE_GROUP}" --location "${LOCATION}" --name "${KEYVAULT_NAME}" --enable-rbac-authorization
向自己授予对保管库的“机密管理人员”权限,使你可创建机密:
az role assignment create --role "Key Vault Secrets Officer" --assignee ${CURRENT_USER} --scope /subscriptions/${SUBSCRIPTION}/resourcegroups/${RESOURCE_GROUP}/providers/Microsoft.KeyVault/vaults/${KEYVAULT_NAME}
创建一个机密并对其进行更新,这样你就有两个版本:
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 机密用户”权限的托管标识,则可跳过本节。 有关详细信息,请参阅创建用户分配的托管标识和将 Azure RBAC 机密、密钥和证书权限与 Key Vault 搭配使用。
创建用户分配的托管标识:
az identity create --name "${USER_ASSIGNED_IDENTITY_NAME}" --resource-group "${RESOURCE_GROUP}" --location "${LOCATION}" --subscription "${SUBSCRIPTION}"
向标识授予“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 服务帐户之间建立链接。
创建一个将与托管标识联合的 Kubernetes 服务帐户。 使用关联的用户分配的托管标识的详细信息,对它进行批注。
kubectl create ns ${KUBERNETES_NAMESPACE}
cat <<EOF | kubectl apply -f - apiVersion: v1 kind: ServiceAccount metadata: name: ${SERVICE_ACCOUNT_NAME} namespace: ${KUBERNETES_NAMESPACE} EOF
创建联合标识凭据:
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 资源管理器驱动的体验。
安装 cert-manager 和 trust-manager
如要在群集服务之间针对日志展开安全通信,cert-manager 和 trust-manager 是必要项,必须在安装 Arc 扩展之前安装。
安装 cert-manager。
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.15.3/cert-manager.yaml
安装 trust-manager。
helm repo add jetstack https://charts.jetstack.io helm repo update helm upgrade trust-manager jetstack/trust-manager --install --namespace cert-manager --wait
安装 SSE
使用以下命令,将 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 以及要同步到群集的机密的信息来配置已安装的扩展。 创建两种类型的自定义资源:
- 用于定义与 Key Vault 的连接的
SecretProviderClass
对象。 - 要同步的每个机密的
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
查看上次同步状态
若要查看给定机密的最新同步状态,请使用 SecretSync
对象的 kubectl describe
命令。 输出包括机密创建时间戳、机密的版本以及每个同步事件的详细状态消息。 此输出可用于诊断连接或配置错误,并观察机密值何时更改。
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 Key Vault 的访问及从中拉取机密)。 每个已同步的机密都有一个 SecretSync
对象,其中包含该机密从 Azure Key Vault 到群集机密存储的同步状态。
若要排查问题,请首先查看 SecretSync
对象的状态,如查看上次同步状态中所述。 下表列出了常见状态类型、其含义以及解决错误的潜在故障排除步骤。
SecretSync 状态类型 | 详细信息 | 进一步修复/调查的步骤 |
---|---|---|
CreateSucceeded |
机密已成功创建。 | 不适用 |
CreateFailedProviderError |
由于提供程序存在一些问题(与 Azure Key Vault 的连接),机密创建失败。 此失败可能是由于 Internet 连接、标识同步机密的权限不足、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 Key Vault 是否有更新,但没有要同步的更改。 | 不适用 |
UpdateValueChangeOrForceUpdateSucceeded |
SSE 检查了 Azure Key Vault 是否有更新,并成功更新了值。 | 不适用 |
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 的连接),机密更新失败。 此失败可能是由于 Internet 连接、标识同步机密的权限不足、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
直接删除机密。
后续步骤
- 详细了解 Azure Arc 扩展。
- 详细了解 Azure Key Vault。