持久卷加密

概述

持久卷(PV)加密有助于保护有状态工作负载的数据机密性和租户隔离。 对于 ACP 分布式存储,CSI 预配的 PV 的静态加密通过外部密钥管理系统(KMS)和启用加密的 StorageClass 实现。

本章介绍如何:

  • 配置 KMS 访问凭证和连接详情
  • 创建启用加密的 StorageClass
  • 启用和禁用密钥轮转策略
WARNING

本章中的持久卷加密适用于基于 RBD 的 PV。不包含对象存储存储桶。

密钥管理系统(KMS)的访问配置

请先配置 KMS 访问。基于 StorageClass 的 PV 加密依赖于有效的 KMS 凭证和连接元数据。

不同的提供商模式使用不同的认证和元数据模型:

模式encryptionKMSType认证材料
Vault token 模式vaulttokens存储在 Secret 中的静态 Vault token
Vault tenant ServiceAccount 模式vaulttenantsa映射到 Vault 角色的 Kubernetes ServiceAccount 身份
Thales CipherTrust Manager 模式kmipKMIP 端点 + 客户端证书链 + key UID

⚠️ 重要:Alpha 功能免责声明

使用 vaulttenantsa 访问 KMS 处于 Alpha 阶段,仅用于早期技术验证和评估。作为功能提供方,我们不对其稳定性、可靠性或数据完整性提供任何保证。通过配置和使用此功能,您即表示已知悉并接受以下技术限制:

  • 不适用于生产环境: 此功能缺少全面的系统级验证。将其部署到生产环境会带来较高的进程失败或数据损坏风险。
  • 不保证 SLA: 此功能不在标准服务级别协议(SLA)范围内。我们不保证技术支持响应时间,也不提供紧急热修复。
  • Breaking Changes 与弃用: API 端点、配置 schema 和核心处理逻辑在未来版本中可能发生不向后兼容的更改。该功能也可能在未提前通知的情况下被完全弃用。
  • 无法平滑升级: 我们不提供版本之间的升级脚本或数据迁移工具。升级到后续版本通常需要完全清除现有资源并重新部署。由此导致的任何状态或数据丢失均由用户自行承担责任。

使用 vaulttokens 配置访问

前提条件

  • ACP 分布式存储集群处于 Ready 状态。
  • 您具有 cluster-admin 权限。
  • 集群节点可以访问 Vault。
  • 您拥有一个可访问目标后端路径的有效 Vault token。

操作步骤

  1. 创建一个用于存储 Vault token 的 Secret。

    kubectl -n rook-ceph create secret generic ceph-csi-kms-token \
      --from-literal=token='<vault_token>'
  2. 创建或更新 KMS 连接 ConfigMap 条目。

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: csi-kms-connection-details
      namespace: rook-ceph
    data:
      vault-token-kms: |
        {
           "encryptionKMSType": "vaulttokens",
           "vaultAddress": "<https://hostname_or_ip_of_vault_server:port>",
           "vaultBackend": "<vault backend>",
           "vaultBackendPath": "<vault backend path name>",
           "vaultTLSServerName": "<vault TLS server name>",
           "vaultCAVerify": "true",
           "vaultCAFromSecret": "<secret containing CA cert>",
           "vaultClientCertFromSecret": "<secret containing client cert>",
           "vaultClientCertKeyFromSecret": "<secret containing client private key>"
        }

    参数

    参数说明必需
    encryptionKMSTypeKMS 提供商模式。使用 vaulttokens 进行静态 Vault token 认证。
    vaultAddressVault 服务端点,包括协议和端口。
    vaultBackendVault secret engine,默认值:kv-v2
    vaultBackendPath用于 data-encryption keys(DEKs)的 Vault secret engine 路径。默认值:secret/
    vaultTLSServerName用于 SNI 和证书主机名验证的 TLS server name。
    vaultCAVerify连接 Vault server 时是否需要 CA 认证,默认值:true
    vaultCAFromSecret存储 Vault CA 证书的 Secret 名称。
    vaultClientCertFromSecret存储 Vault 客户端证书的 Secret 名称。
    vaultClientCertKeyFromSecret存储 Vault 客户端私钥的 Secret 名称。

验证步骤

  1. 验证 token Secret:

    kubectl -n rook-ceph get secret ceph-csi-kms-token
  2. 验证 ConfigMap 条目,并确认 encryptionKMSType: vaulttokens

    kubectl -n rook-ceph get configmap csi-kms-connection-details -o yaml

使用 vaulttenantsa 配置访问

前提条件

  • ACP 分布式存储集群处于 Ready 状态。
  • 在外部密钥管理系统(KMS)中,
    • 确保已存在 policy,并且 Vault 中的 key value backend path 已启用。
    • 确保 Vault server 使用的是签名证书。

操作步骤

在 ACP 分布式存储可以使用 Vault 进行认证并开始使用之前,需要先配置 Kubernetes 认证方式。以下说明将创建并配置 ACP 分布式存储通过 Vault 进行认证所需的 serviceAccountClusterRoleClusterRoleBinding

  1. 在工作负载 namespace 中创建 tenant ServiceAccount。

    kubectl -n <tenant_namespace> create serviceaccount ceph-csi-vault-sa
  2. 在存储 namespace 中应用用于 Vault token review 的 RBAC 资源。

    cat << EOF | kubectl create -f -
    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: rbd-csi-vault-token-review
      namespace: rook-ceph
    ---
    kind: ClusterRole
    apiVersion: rbac.authorization.k8s.io/v1
    metadata:
      name: rbd-csi-vault-token-review
    rules:
      - apiGroups: ["authentication.k8s.io"]
        resources: ["tokenreviews"]
        verbs: ["create", "get", "list"]
    ---
    kind: ClusterRoleBinding
    apiVersion: rbac.authorization.k8s.io/v1
    metadata:
      name: rbd-csi-vault-token-review
    subjects:
      - kind: ServiceAccount
        name: rbd-csi-vault-token-review
        namespace: rook-ceph
    roleRef:
      kind: ClusterRole
      name: rbd-csi-vault-token-review
      apiGroup: rbac.authorization.k8s.io
    EOF
  3. 为 token reviewer ServiceAccount 创建 service-account-token Secret。

    cat << EOF | kubectl create -f -
    apiVersion: v1
    kind: Secret
    metadata:
      name: rbd-csi-vault-token-review-token
      namespace: rook-ceph
      annotations:
        kubernetes.io/service-account.name: rbd-csi-vault-token-review
    type: kubernetes.io/service-account-token
    EOF
  4. 读取 reviewer JWT、cluster CA 和 API endpoint。

    SA_JWT_TOKEN=$(kubectl -n rook-ceph get secret rbd-csi-vault-token-review-token \
      -o jsonpath="{.data['token']}" | base64 --decode; echo)
    SA_CA_CRT=$(kubectl -n rook-ceph get secret rbd-csi-vault-token-review-token \
      -o jsonpath="{.data['ca\.crt']}" | base64 --decode; echo)
    ACP_HOST=$(kubectl config view --minify --flatten -o jsonpath="{.clusters[0].cluster.server}")
  5. 在 Vault 中配置 Kubernetes 认证。

    vault auth enable kubernetes
    vault write auth/kubernetes/config \
      token_reviewer_jwt="$SA_JWT_TOKEN" \
      kubernetes_host="$ACP_HOST" \
      kubernetes_ca_cert="$SA_CA_CRT"
  6. 为 tenant namespace 创建 Vault role。

    vault write "auth/kubernetes/role/csi-kubernetes" \
      bound_service_account_names="ceph-csi-vault-sa" \
      bound_service_account_namespaces="<tenant_namespace>" \
      policies="<policy_name_in_vault>"
    NOTE
    • csi-kubernetes 是 ACP 分布式存储在 Vault 中查找的默认 role 名称。
    • ACP 分布式存储集群中 tenant namespace 里的默认 ServiceAccount 名称是 ceph-csi-vault-sa
    • 可以通过在 tenant namespace 中创建 ConfigMap 来覆盖这些默认值。
  7. 使用 encryptionKMSType: vaulttenantsa 创建或更新 KMS 连接条目。

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: csi-kms-connection-details
      namespace: rook-ceph
    data:
      vault-tenant-sa-kms: |
        {
           "encryptionKMSType": "vaulttenantsa",
           "vaultAddress": "<https://hostname_or_ip_of_vault_server:port>",
           "vaultTLSServerName": "<vault TLS server name>",
           "vaultAuthPath": "/v1/auth/kubernetes/login",
           "vaultAuthNamespace": "<vault auth namespace name>",
           "vaultNamespace": "<vault namespace name>",
           "vaultBackendPath": "<vault backend path name>",
           "vaultCAFromSecret": "<secret containing CA cert>",
           "vaultClientCertFromSecret": "<secret containing client cert>",
           "vaultClientCertKeyFromSecret": "<secret containing client private key>",
           "tenantSAName": "<service account name in the tenant namespace>"
        }

    参数

    参数说明必需
    encryptionKMSType设置为 vaulttenantsa,以使用 ServiceAccount 进行 Vault 认证。
    vaultAddress带端口号的 Vault server 主机名或 IP 地址。
    vaultBackendPathVault 中用于存储加密密钥的后端路径。
    vaultTLSServerName用于验证 Vault 证书主机名的 TLS server name。
    vaultAuthPath在 Vault 中启用 kubernetes 认证方式的路径。默认路径是 kubernetes。如果认证方式启用在不同于 kubernetes 的路径下,则此变量需要设置为 /v1/auth/<path>/login
    vaultAuthNamespace启用 kubernetes 认证方式的 Vault namespace。
    vaultNamespace存放所用密钥的后端路径所在的 Vault namespace。
    vaultCAFromSecretCSI 使用的 Vault CA 证书所在 Secret。
    vaultClientCertFromSecret用于与 Vault 进行 mTLS 的客户端证书所在 Secret。
    vaultClientCertKeyFromSecretvaultClientCertFromSecret 匹配的私钥所在 Secret。
    vaultRole绑定到 tenant ServiceAccount 和 policy 的 Vault Kubernetes auth role。
    tenantSAName工作负载使用的 tenant ServiceAccount 名称,通常为 ceph-csi-vault-sa

验证步骤

  1. 验证 ServiceAccount 创建:

    kubectl -n <tenant_namespace> get sa ceph-csi-vault-sa
    kubectl -n rook-ceph get sa rbd-csi-vault-token-review
  2. 验证 token review 权限:

    kubectl auth can-i create tokenreviews.authentication.k8s.io \
      --as=system:serviceaccount:rook-ceph:rbd-csi-vault-token-review
  3. 验证 ConfigMap 条目,并确认 encryptionKMSType: vaulttenantsatenantSAName

  4. <tenant_namespace> 中创建一个测试加密 PVC,并验证其能够成功绑定。

使用 Thales CipherTrust Manager (kmip) 配置访问

前提条件

  • 您可以访问已启用 KMIP 的 Thales CipherTrust Manager。
  • 您拥有 KMIP endpoint(<kmip_address>:5696)、客户端证书链和 key unique identifier(UID)。
  • 您有权限在 rook-ceph 中创建 Secret 和 ConfigMap。

操作步骤

  1. 在 Thales CipherTrust Manager 中,创建一个 KMIP client profile 并注册客户端。

  2. 从 profile 中下载客户端证书、私钥和 CA 证书。

  3. 为 KMIP 客户端凭证创建一个 Secret。

    kubectl -n rook-ceph create secret generic thales-kmip-client \
      --from-file=client.crt=<client_crt_path> \
      --from-file=client.key=<client_key_path> \
      --from-file=ca.crt=<ca_crt_path>
  4. 创建或更新 KMS 连接 ConfigMap 条目。

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: csi-kms-connection-details
      namespace: rook-ceph
    data:
      thales-kmip-kms: |
        {
          "encryptionKMSType": "kmip",
          "kmipAddress": "<kmip_address>",
          "kmipPort": 5696,
          "kmipCAPath": "/etc/ceph-csi-kms-config/ca.crt",
          "keyIdentifier": "<thales_key_uid>"
        }

验证步骤

  1. 验证 KMIP 凭证 Secret:

    kubectl -n rook-ceph get secret thales-kmip-client
  2. 验证 ConfigMap 条目,并确认 encryptionKMSType: kmip

  3. 确认 KMS 条目中的 key UID 与 Thales CipherTrust Manager 中生成的 key 一致。

NOTE

对于 kmip,关键区别在于:加密密钥通过 KMIP key UID 和 mutual TLS 信任链进行解析,而不是通过 Vault token。

为持久卷加密创建 StorageClass

完成 KMS 访问配置后,创建带有加密参数的 StorageClass。

前提条件

  • 您有权限创建 StorageClass。
  • 您知道目标 KMS 配置 ID(<kms_config_id>)。

操作步骤

  1. 进入 Administrator

  2. 在左侧导航栏中,点击 Storage > StorageClasses

  3. 点击 Create Storage Class

    注意:以下内容是表单形式的示例,您也可以选择 YAML 完成该操作。

  4. 选择 CephRBD Block Storage,然后点击 Next

  5. 切换到 YAML 视图

  6. 在参数中启用加密:

    • encrypted: "true"
    • encryptionKMSID: "<kms_config_id>"
  7. 点击 Create

验证步骤

  1. 验证 StorageClass 参数:

    kubectl get sc encrypted-rbd-sc -o yaml
  2. 确认存在 encrypted: "true" 和预期的 encryptionKMSID

  3. 使用此 StorageClass 创建一个测试 PVC,并确认其进入 Bound 状态:

    apiVersion: v1
    kind: PersistentVolumeClaim
    metadata:
      name: encrypted-rbd-pvc
    spec:
      accessModes:
        - ReadWriteOnce
      resources:
        requests:
          storage: 1Gi
      storageClassName: encrypted-rbd-sc
    kubectl apply -f <encrypted-rbd-pvc.yaml>
    kubectl get pvc encrypted-rbd-pvc

使用 tenant ConfigMap 覆盖 Vault 连接详情

可以通过在 ACP namespace 中创建一个 ConfigMap 来按 tenant 重新配置 Vault 连接详情,该 ConfigMap 中的配置选项与 rook-ceph namespace 中 csi-kms-connection-details ConfigMap 的值不同。该 ConfigMap 需要位于 tenant namespace 中。tenant namespace 中 ConfigMap 的值将覆盖该 namespace 中已创建的加密 Persistent Volume 所使用的 csi-kms-connection-details ConfigMap 值。

操作步骤

  1. 在 ACP 控制台中,导航到 Alauda Container Platform -> Configuration -> ConfigMaps

  2. 切换到目标 tenant project/namespace。

  3. 点击 Create ConfigMap,并将名称设置为 ceph-csi-kms-config

  4. 添加 tenant 特定的 Vault 覆盖值:

    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: ceph-csi-kms-config
      namespace: <tenant_namespace>
    data:
      vaultAddress: "<vault_address:port>"
      vaultBackendPath: "<backend_path>"
      vaultTLSServerName: "<vault_tls_server_name>"
      vaultNamespace: "<vault_namespace>"
  5. 点击 Create

验证步骤

  1. 验证 tenant 覆盖 ConfigMap:

    kubectl -n <tenant_namespace> get configmap ceph-csi-kms-config -o yaml
  2. 在同一 namespace 中创建一个新的加密 PVC,并确认其进入 Bound

  3. 如果密钥访问失败,请检查 namespace 事件和 CSI provisioner 日志中的 Vault endpoint 和 auth-path 是否不匹配。

启用和禁用密钥轮转(可选)

密钥轮转支持对加密 PV 使用的加密密钥进行周期性刷新。

前提条件

  • 请确保以下两个镜像已上传到平台私有镜像仓库:
    • quay.io/csiaddons/k8s-controller:v0.14.0 -> <registry>/csiaddons/k8s-controller:v0.14.0
    • quay.io/csiaddons/k8s-sidecar:v0.14.0 -> <registry>/csiaddons/k8s-sidecar:v0.14.0

为卷复制设置环境

  1. 设置 CsiAddons Controller

    在 Control 节点上执行以下命令:

    kubectl create -f https://raw.githubusercontent.com/csi-addons/kubernetes-csi-addons/v0.14.0/deploy/controller/crds.yaml
    kubectl create -f https://raw.githubusercontent.com/csi-addons/kubernetes-csi-addons/v0.14.0/deploy/controller/setup-controller.yaml
    kubectl create -f https://raw.githubusercontent.com/csi-addons/kubernetes-csi-addons/v0.14.0/deploy/controller/rbac.yaml
    kubectl create -f https://raw.githubusercontent.com/csi-addons/kubernetes-csi-addons/v0.14.0/deploy/controller/csi-addons-config.yaml
    
    kubectl -n csi-addons-system set image deployment/csi-addons-controller-manager manager=<registry>/csiaddons/k8s-controller:v0.14.0

    参数

    • <registry>:平台的镜像仓库地址。
  2. 启用 CsiAddons sidecar

    在 Control 节点上执行以下命令:

    kubectl patch cm rook-ceph-operator-config -n rook-ceph --type json --patch \
    '[
      {
        "op": "add",
        "path": "/data/CSI_ENABLE_CSIADDONS",
        "value": "true"
      },
      {
        "op": "add",
        "path": "/data/ROOK_CSIADDONS_IMAGE",
        "value": "<registry>/csiaddons/k8s-sidecar:v0.14.0"
      }
    ]'

    等待所有 csi pod 成功重启

    kubectl get po -n rook-ceph -w | grep csi

(可选)强制密钥轮转优先级

在密钥轮转中,优先级指系统检查计划注解的顺序。默认优先级设置为 storage class(推荐)。这意味着系统只读取 storage class 中的注解。

但是,如果您希望系统先检查 persistent volume claim(PVC),再回退到 storage class,可以在 CSI-addons ConfigMap 中将 schedule-precedence 设置为 PVC 来配置此行为。

您可以按如下方式定义 csi-addons 的 ConfigMap:

apiVersion: v1
kind: ConfigMap
metadata:
  name: csi-addons-config
  namespace: rook-ceph
data:
  schedule-precedence: "pvc"

重新启动 csi-addons operator pod 以使更改生效:

kubectl apply -f <csi-addons-config.yaml>
kubectl -n rook-ceph delete pod -l app.kubernetes.io/name=csi-addons

启用密钥轮转

要启用密钥轮转,请将注解 keyrotation.csiaddons.openshift.io/schedule: <value> 添加到 PersistentVolumeClaim、Namespace 或 StorageClass 上(优先级依次降低)。

<value> 可以是 @hourly@daily@weekly@monthly@yearly。如果 <value> 为空,则默认值为 @weekly。以下示例使用 @weekly

为 Namespace 添加注解

kubectl annotate namespace <tenant_namespace> \
  "keyrotation.csiaddons.openshift.io/schedule=@weekly"

为 StorageClass 添加注解

kubectl annotate storageclass encrypted-rbd-sc \
  "keyrotation.csiaddons.openshift.io/schedule=@weekly"

为 PersistentVolumeClaims 添加注解

kubectl annotate pvc <encrypted_pvc_name> \
  "keyrotation.csiaddons.openshift.io/schedule=@weekly"

禁用密钥轮转

您可以针对以下对象禁用密钥轮转:

  • 某个 storage class 下的所有 persistent volume claims(PVCs)
  • 某个特定 PVC

为某个 storage class 下的所有 PVC 禁用密钥轮转

kubectl annotate storageclass encrypted-rbd-sc \
  "keyrotation.csiaddons.openshift.io/enable=false" --overwrite

为某个特定 persistent volume claim 禁用密钥轮转

  1. 找出您要禁用密钥轮转的 PVC 对应的 EncryptionKeyRotationCronJob CR:

    kubectl get encryptionkeyrotationcronjob -o jsonpath='{range .items[?(@.spec.jobTemplate.spec.target.persistentVolumeClaim=="<PVC_NAME>")]}{.metadata.name}{"\n"}{end}'

    其中 <PVC_NAME> 是您要禁用的 PVC 名称。

  2. 对上一步中的 EncryptionKeyRotationCronJob CR 执行以下操作以禁用密钥轮转:

    • 将 csiaddons.openshift.io/state 注解从 managed 更新为 unmanaged:

      kubectl annotate encryptionkeyrotationcronjob <encryptionkeyrotationcronjob_name> "csiaddons.openshift.io/state=unmanaged" --overwrite=true

      其中 <encryptionkeyrotationcronjob_name>EncryptionKeyRotationCronJob CR 的名称。

    • 在 spec 字段下添加 suspend: true

      kubectl patch encryptionkeyrotationcronjob <encryptionkeyrotationcronjob_name> -p '{"spec": {"suspend": true}}' --type=merge
  3. 保存并退出。该 PVC 的密钥轮转将被禁用。