使用机密容器和默认策略部署 AKS 群集

本文使用 Azure CLI 部署 Azure Kubernetes 服务 (AKS) 群集,并使用默认安全策略配置机密容器(预览版)。 然后可以将应用程序部署为机密容器。 若要了解详细信息,请参阅 AKS 机密容器概述

通常,AKS 机密容器入门涉及以下步骤。

  • 使用 Azure CLI 部署或升级 AKS 群集
  • 将批注添加到 Pod YAML 清单,以将 Pod 标记为作为机密容器运行
  • 将安全策略添加到 Pod YAML 清单
  • 启用安全策略的强制实施
  • 在机密计算中部署应用程序

先决条件

  • Azure CLI 版本 2.44.1 或更高版本。 可通过运行 az --version 查找版本,运行 az upgrade 升级版本。 如果需要进行安装或升级,请参阅安装 Azure CLI

  • aks-preview Azure CLI 扩展版本 0.5.169 或更高版本。

  • confcom 机密容器 Azure CLI 扩展 0.3.3 或更高版本。 confcom 是生成安全策略所必需的。

  • 在 Azure 订阅中注册 Preview 功能。

  • AKS 支持版本 1.25.0 及更高版本的机密容器(预览版)。

  • 工作负载标识和联合标识凭据。 使用工作负载标识凭据,Kubernetes 应用程序可以使用基于带注释的服务帐户通过 Microsoft Entra ID 安全地访问 Azure 资源。 如果不熟悉 Microsoft Entra 工作负载 ID,请参阅 Microsoft Entra 工作负载 ID 概述并查看工作负载标识如何与 AKS 配合使用

  • 用于创建群集的标识具有合适的的最低权限。 有关 AKS 的访问和标识的详细信息,请参阅 Azure Kubernetes 服务 (AKS) 的访问和标识选项

  • 若要管理 Kubernetes 群集,请使用 Kubernetes 命令行客户端 kubectl。 可以使用 az aks install-cli 命令在本地安装 kubectl。

  • AKS 上的机密容器提供用于证明和安全密钥发布的挎斗开放源代码容器。 该挎斗与 Azure Key Vault 等密钥管理服务 (KMS) 集成,以便在验证完成后将密钥发布到容器组。

安装 aks-preview Azure CLI 扩展

重要

AKS 预览功能是可选择启用的自助功能。 预览功能是“按现状”和“按可用”提供的,不包括在服务级别协议和有限保证中。 AKS 预览功能是由客户支持尽最大努力部分覆盖。 因此,这些功能并不适合用于生产。 有关详细信息,请参阅以下支持文章:

若要安装 aks-preview 扩展,请运行以下命令:

az extension add --name aks-preview

运行以下命令以更新到已发布的最新扩展版本:

az extension update --name aks-preview

安装 confcom Azure CLI 扩展

若要安装 confcom 扩展,请运行以下命令:

az extension add --name confcom

运行以下命令以更新到已发布的最新扩展版本:

az extension update --name confcom

注册 KataCcIsolationPreview 功能标志

使用 KataCcIsolationPreview 命令注册 KataCcIsolationPreview 功能标志,如以下示例所示:

az feature register --namespace "Microsoft.ContainerService" --name "KataCcIsolationPreview"

状态显示为“已注册”需要几分钟时间。 使用 az feature show 命令验证注册状态:

az feature show --namespace "Microsoft.ContainerService" --name "KataCcIsolationPreview"

当状态反映为“已注册”时,使用 az provider register 命令刷新 Microsoft.ContainerService 资源提供程序的注册:

az provider register --namespace "Microsoft.ContainerService"

部署一个新群集

  1. 使用 az aks create 命令并指定以下参数创建 AKS 群集:

    • --os-sku:AzureLinux。 在此预览版本中,只有 Azure Linux os-sku 支持此功能。
    • --node-vm-size:属于第 2 代 VM 并支持嵌套虚拟化的任何 Azure VM 大小都有效。 例如,[标准_DC8as_cc_v5][DC8as 系列] VM。
    • --enable-workload-identity:启用创建 Microsoft Entra 工作负载 ID,使 Pod 能够使用 Kubernetes 标识。
    • --enable-oidc-issuer:启用 OpenID Connect (OIDC) 证书颁发者。 它允许 Microsoft Entra ID 或其他云提供商标识和访问管理平台发现 API 服务器的公钥签名密钥。

    以下示例更新名为 myAKSCluster 的群集,并在 myResourceGroup 中创建单个系统节点池:

    az aks create --resource-group myResourceGroup --name myAKSCluster --kubernetes-version <1.25.0 and above> --os-sku AzureLinux --node-vm-size Standard_DC4as_cc_v5 --node-count 1 --enable-oidc-issuer --enable-workload-identity --generate-ssh-keys
    

    片刻之后,该命令将会完成,并返回有关群集的 JSON 格式信息。 在上一步骤中创建的群集包含单个节点池。 在下一步中,我们将第二个节点池添加到群集。

  2. 群集准备就绪后,使用 az aks get-credentials 命令获取群集凭据。

    az aks get-credentials --resource-group myResourceGroup --name myAKSCluster
    
  3. 使用 az aks nodepool add 命令将用户节点池添加到在 myResourceGroupnodepool2 中有两个节点的 myAKSCluster。 指定下列参数:

    • --workload-runtime:指定 KataCcIsolation 以在节点池上启用机密容器功能。 使用此参数时,这些其他参数应满足以下要求。 否则,该命令将失败,并报告相应参数的问题。
    • --os-sku:AzureLinux。 在此预览版本中,只有 Azure Linux os-sku 支持此功能。
    • --node-vm-size:属于第 2 代 VM 并支持嵌套虚拟化的任何 Azure VM 大小都有效。 例如,[标准_DC8as_cc_v5][DC8as 系列] VM。
    az aks nodepool add --resource-group myResourceGroup --name nodepool2 --cluster-name myAKSCluster --node-count 2 --os-sku AzureLinux --node-vm-size Standard_DC4as_cc_v5 --workload-runtime KataCcIsolation
    

片刻之后,该命令将会完成,并返回有关群集的 JSON 格式信息。

部署到现有群集

若要将此功能用于现有 AKS 群集,必须满足以下要求:

使用以下命令通过创建节点池来托管机密容器(预览版)。

  1. 使用 az aks nodepool add 命令将节点池添加到 AKS 群集。 指定下列参数:

    • --resource-group:输入要在其中创建 AKS 群集的现有资源组的名称。
    • --cluster-name:输入 AKS 群集的唯一名称,例如 myAKSCluster
    • --name:输入群集节点池的唯一名称,例如 nodepool2
    • --workload-runtime:指定 KataCcIsolation 以在节点池上启用该功能。 除了 --workload-runtime 参数外,这些其他参数应满足以下要求。 否则,该命令将失败,并报告相应参数的问题。
    • --os-sku:AzureLinux。 在此预览版本中,只有 Azure Linux os-sku 支持此功能。
    • --node-vm-size:属于第 2 代 VM 并支持嵌套虚拟化的任何 Azure VM 大小都有效。

    以下示例将用户节点池添加到 myAKSCluster,其中有两个节点在 myResourceGroupnodepool2 中:

    az aks nodepool add --resource-group myResourceGroup --name nodepool2 –-cluster-name myAKSCluster --node-count 2 --os-sku AzureLinux --node-vm-size Standard_DC4as_cc_v5 --workload-runtime KataCcIsolation
    

    片刻之后,该命令将会完成,并返回有关群集的 JSON 格式信息。

  2. 运行 az aks update 命令以在群集上启用机密容器(预览版)。

    az aks update --name myAKSCluster --resource-group myResourceGroup
    

    片刻之后,该命令将会完成,并返回有关群集的 JSON 格式信息。

  3. 群集准备就绪后,使用 az aks get-credentials 命令获取群集凭据。

    az aks get-credentials --resource-group myResourceGroup --name myAKSCluster
    

配置容器

在配置对 Azure Key Vault 和机密的访问权限并将应用程序部署为机密容器之前,需要完成工作负载标识的配置。

若要配置工作负载标识,请执行部署和配置工作负载标识一文中所述的以下步骤:

  • 检索 OIDC 颁发者 URL
  • 创建托管标识
  • 创建 Kubernetes 服务帐户
  • 建立联合标识凭据

重要

你需要根据部署和配置工作负载标识一文中的“导出环境变量”部分来设置环境变量,以继续完成本教程。 请记得将变量 SERVICE_ACCOUNT_NAMESPACE 设置为 kafka,并在配置工作负载标识之前执行命令 kubectl create namespace kafka

使用 kata-cc 和证明容器部署受信任的应用程序

以下步骤使用 Azure 托管硬件安全模块 (mHSM) 管理的加密密钥为 Kafka 消息配置端到端加密。 仅当 Kafka 使用者在机密容器中运行并且 Azure 证明机密预配容器注入到 Pod 中时,才会释放密钥。

此配置基于以下四个组件:

  • Kafka 群集:在群集上的 Kafka 命名空间中部署的简单 Kafka 群集。
  • Kafka 生成者:作为 Vanilla Kubernetes Pod 运行的 Kafka 生成者,使用公钥将加密的用户配置的消息发送到 Kafka 主题。
  • Kafka 使用者:使用 kata-cc 运行时运行的 Kafka 使用者 Pod,配备了安全密钥发布容器,用于检索私钥,以解密 Kafka 消息并将消息呈现到 Web UI。

对于此预览版,建议出于测试和评估目的创建或使用现有的 Azure Key Vault 高级层资源来支持在硬件安全模块 (HSM) 中存储密钥。 不建议使用生产密钥保管库。 如果没有 Azure Key Vault,请参阅使用 Azure CLI 创建密钥保管库

  1. 授予之前创建的托管标识以及帐户对密钥保管库的访问权限。 分配 标识 Key Vault Crypto OfficerKey Vault Crypto User Azure RBAC 角色。

    注意

    运行以下命令来设置范围:

    AKV_SCOPE=$(az keyvault show --name <AZURE_AKV_RESOURCE_NAME> --query id --output tsv)
    

    运行以下命令以分配 Key Vault Crypto Officer 角色。

    az role assignment create --role "Key Vault Crypto Officer" --assignee "${USER_ASSIGNED_IDENTITY_NAME}" --scope $AKV_SCOPE
    

    运行以下命令以分配 Key Vault Crypto User 角色。

    az role assignment create --role "Key Vault Crypto User" --assignee "${USER_ASSIGNED_IDENTITY_NAME}" --scope $AKV_SCOPE
    
  2. 运行以下命令,在 kafka 命名空间中安装 Kafka 群集:

    kubectl create -f 'https://strimzi.io/install/latest?namespace=kafka' -n kafka
    
  3. 运行以下命令以应用 kafka 群集 CR 文件。

    kubectl apply -f https://strimzi.io/examples/latest/kafka/kafka-persistent-single.yaml -n kafka
    
  4. 使用 GitHub 中工作负载的 bash 脚本来准备 RSA 加密/解密密钥。 将文件另存为 setup-key.sh

  5. 运行以下命令,将 MAA_ENDPOINT 环境变量设置为证明 URI 的 FQDN。

    export MAA_ENDPOINT="$(az attestation show --name "myattestationprovider" --resource-group "MyResourceGroup" --query 'attestUri' -o tsv | cut -c 9-)"
    

    检查证明 URI 的 FQDN 是否采用了正确的格式(MAA_ENDPOINT不应包含前缀“https://”):

    echo $MAA_ENDPOINT
    

    注意

    若要设置 Azure 证明,请参阅[快速入门:使用 Azure CLI 设置 Azure 证明][attestation-quickstart-azure-cli]。

  6. 复制以下 YAML 清单并将其另存为 consumer.yaml

    apiVersion: v1
    kind: Pod
    metadata:
      name: kafka-golang-consumer
      namespace: kafka
      labels:
        azure.workload.identity/use: "true"
        app.kubernetes.io/name: kafka-golang-consumer
    spec:
      serviceAccountName: workload-identity-sa
      runtimeClassName: kata-cc-isolation
      containers:
        - image: "mcr.azk8s.cn/aci/skr:2.7"
          imagePullPolicy: Always
          name: skr
          env:
            - name: SkrSideCarArgs
              value: ewogICAgImNlcnRjYWNoZSI6IHsKCQkiZW5kcG9pbnRfdHlwZSI6ICJMb2NhbFRISU0iLAoJCSJlbmRwb2ludCI6ICIxNjkuMjU0LjE2OS4yNTQvbWV0YWRhdGEvVEhJTS9hbWQvY2VydGlmaWNhdGlvbiIKCX0gIAp9
          command:
            - /bin/skr
          volumeMounts:
            - mountPath: /opt/confidential-containers/share/kata-containers/reference-info-base64
              name: endor-loc
        - image: "mcr.azk8s.cn/acc/samples/kafka/consumer:1.0"
          imagePullPolicy: Always
          name: kafka-golang-consumer
          env:
            - name: SkrClientKID
              value: kafka-encryption-demo
            - name: SkrClientMAAEndpoint
              value: sharedeus2.eus2.test.attest.chinacloudapi.cn
            - name: SkrClientAKVEndpoint
              value: "myKeyVault.vault.azure.cn"
            - name: TOPIC
              value: kafka-demo-topic
          command:
            - /consume
          ports:
            - containerPort: 3333
              name: kafka-consumer
          resources:
            limits:
              memory: 1Gi
              cpu: 200m
      volumes:
        - name: endor-loc
          hostPath:
            path: /opt/confidential-containers/share/kata-containers/reference-info-base64
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: consumer
      namespace: kafka
    spec:
      type: LoadBalancer
      selector:
        app.kubernetes.io/name: kafka-golang-consumer
      ports:
        - protocol: TCP
          port: 80
          targetPort: kafka-consumer
    

    注意

    更新 Pod 环境变量 SkrClientAKVEndpoint 的值以匹配 Azure Key Vault 的 URL,不包括协议值 https://。 当前值占位符值为 myKeyVault.vault.azure.cn。 将 Pod 环境变量 SkrClientMAAEndpoint 的值更新为 MAA_ENDPOINT 的值。 可以通过运行命令 echo $MAA_ENDPOINT 或命令 az attestation show --name "myattestationprovider" --resource-group "MyResourceGroup" --query 'attestUri' -o tsv | cut -c 9- 来查找 MAA_ENDPOINT 的值。

  7. 运行以下命令,为 Kafka 使用者 YAML 清单生成安全策略,并获取存储在 WORKLOAD_MEASUREMENT 变量中的安全策略的哈希:

    export WORKLOAD_MEASUREMENT=$(az confcom katapolicygen -y consumer.yaml --print-policy | base64 -d | sha256sum | cut -d' ' -f1)
    
  8. 若要生成 RSA 非对称密钥对(公钥和私钥),请使用以下命令运行 setup-key.sh 脚本。 <Azure Key Vault URL> 值应为 <your-unique-keyvault-name>.vault.azure.cn

    export MANAGED_IDENTITY=${USER_ASSIGNED_CLIENT_ID}
    bash setup-key.sh "kafka-encryption-demo" <Azure Key Vault URL>
    

    注意

    • Bash 脚本 setup-key.sh 需要环境变量 MANAGED_IDENTITY

    • 执行 bash 脚本后,公钥将另存为 kafka-encryption-demo-pub.pem

    重要

    如果收到错误 ForbiddenByRbac,则你可能需要等待最多 24 小时,因为托管标识的后端服务将每个资源 URI 的缓存保留最多 24 小时。 另请参阅:Azure RBAC 故障排除

  9. 为验证密钥是否已成功上传到密钥保管库,请运行以下命令:

    az account set --subscription <Subscription ID>
    az keyvault key list --vault-name <KeyVault Name> -o table
    
  10. 复制以下 YAML 清单并将其另存为 producer.yaml

    apiVersion: v1
    kind: Pod
    metadata:
      name: kafka-producer
      namespace: kafka
    spec:
      containers:
        - image: "mcr.azk8s.cn/acc/samples/kafka/producer:1.0"
          name: kafka-producer
          command:
            - /produce
          env:
            - name: TOPIC
              value: kafka-demo-topic
            - name: MSG
              value: "Azure Confidential Computing"
            - name: PUBKEY
              value: |-
                -----BEGIN PUBLIC KEY-----
                MIIBojAN***AE=
                -----END PUBLIC KEY-----
          resources:
            limits:
              memory: 1Gi
              cpu: 200m
    

    注意

    将以 -----BEGIN PUBLIC KEY----- 开头且以 -----END PUBLIC KEY----- 字符串结尾的值更新为在上一步中创建的 kafka-encryption-demo-pub.pem 中的内容。

  11. 使用之前保存的文件部署 consumerproducer YAML 清单。

    kubectl apply -f consumer.yaml
    
    kubectl apply -f producer.yaml
    
  12. 使用以下命令获取 Web 服务的 IP 地址:

    kubectl get svc consumer -n kafka
    
  13. 将使用者服务的外部 IP 地址复制并粘贴到浏览器中,并观察解密的消息。

    命令的输出类似于以下示例:

    Welcome to Confidential Containers on AKS!
    Encrypted Kafka Message:
    Msg 1: Azure Confidential Computing
    
  14. 还应尝试通过删除 skr containerkata-cc runtime class 规范以常规 Kubernetes Pod 的形式运行使用者。由于未使用 kata-cc 运行时类运行使用者,因此不再需要该策略。

  15. 删除整个策略,并在重新部署工作负载后在浏览器中再次观察消息。 消息显示为 base64 编码的已加密文本,因为无法检索私钥。 无法检索密钥,因为使用者不再在机密环境中运行,并且缺少 skr container,从而无法解密消息。

清理

完成此功能的评估后,为避免 Azure 费用,请清理不必要的资源。 如果在评估或测试过程中部署了新群集,则可以使用 az aks delete 命令删除该群集。

az aks delete --resource-group myResourceGroup --name myAKSCluster

如果在现有群集上启用了机密容器(预览版),则可以使用 kubectl delete pod 命令删除 Pod。

kubectl delete pod pod-name

后续步骤

  • 详细了解如何对 AKS 群集中的节点使用 Azure 专用主机,以便对 Azure 平台维护事件使用硬件隔离和控制。