使用 CephObjectStoreUser(Ceph 驱动)控制 COSI 桶的访问权限和配额

本指南向 Kubernetes 管理员展示如何结合 CephObjectStoreUser (COSU)BucketClass/BucketClaimBucketAccessClass/BucketAccess,实现基于 Ceph RGW 的 COSI 桶的最小权限访问配额管理

您将构建的内容

  1. 一个具有明确权限和可选用户配额的 CephObjectStoreUser;
  2. 一个告诉 Ceph COSI 驱动使用哪个 COSU 凭证的 BucketClass;
  3. 一个或多个用于创建桶的 BucketClaim;
  4. 使用 BucketAccessClass/BucketAccess 实现细粒度的每工作负载凭证(只读、只写、读写),并可选支持匿名读取。

前提条件

  • 一个健康的 Ceph 集群,已安装 RGW 和 Rook。
  • 已安装 COSI 插件。
  • 集群管理员权限(用于创建集群范围资源)。

第 1 步 — 创建带权限和配额的 CephObjectStoreUser

CephObjectStoreUser 是驱动用来在 RGW 中执行桶操作的服务账户。它必须存在于 rook-ceph 命名空间,并指向你的 CephObjectStore

apiVersion: ceph.rook.io/v1
kind: CephObjectStoreUser
metadata:
  name: user-for-cosi
  namespace: rook-ceph
spec:
  # 目标 CephObjectStore
  store: object-store
  # COSI 桶生命周期所需权限
  capabilities:
    bucket: read, write
    user: read, write
  # RGW 强制的可选用户配额
  quotas:
    maxBuckets: 50        # 限制该用户可拥有的桶数量
    maxObjects: 500       # 桶中对象总数(示例)
    maxSize: 100Gi        # 桶中对象总逻辑大小
  displayName: "User for COSI driver"

获取生成的访问密钥(Rook 会为该用户创建一个 Secret):

kubectl get cephobjectstoreuser user-for-cosi -n rook-ceph -o yaml
# 查看 status.info.secretName -> 持有 AccessKey/SecretKey 的 Secret 名称

这些 COSU 凭证由驱动程序使用(而非你的应用)来代表你创建/删除桶。

第 2 步 — 定义绑定到 CephObjectStoreUser 的 BucketClass

BucketClass 指示驱动在创建桶时使用哪个 COSU Secret。

apiVersion: objectstorage.k8s.io/v1alpha1
kind: BucketClass
metadata:
  name: ceph-cosi-driver-class
deletionPolicy: Delete
# 必须与驱动名称匹配
driverName: ceph.objectstorage.k8s.io
parameters:
  # 引用为 CephObjectStoreUser 创建的 Secret
  objectStoreUserSecretName: <secret-name-from-step-1>
  objectStoreUserSecretNamespace: rook-ceph

deletionPolicy 控制删除 BucketClaim 时桶的物理生命周期(DeleteRetain)。

第 3 步 — 使用 BucketClaim 创建桶

通过引用 BucketClass 在你的应用命名空间中创建桶。

apiVersion: objectstorage.k8s.io/v1alpha1
kind: BucketClaim
metadata:
  name: my-bucket-claim
  namespace: app-a
spec:
  bucketClassName: ceph-cosi-driver-class

等待 status.bucketReady: true,并记录 status.bucketName,这是实际的 RGW 桶名称。

第 4 步 — 使用 BucketAccessClass/BucketAccess 发放最小权限凭证

通过 BucketAccessClass 定义策略模板,并通过 BucketAccess 为每个工作负载生成凭证。支持的策略有:readonlywriteonlyreadwrite。通过设置 parameters.anonymous: "true"(字符串)可启用匿名读取。

示例 BucketAccessClass(只读)

apiVersion: objectstorage.k8s.io/v1alpha1
kind: BucketAccessClass
metadata:
  name: ceph-readonly-access-class
authenticationType: KEY
driverName: ceph.objectstorage.k8s.io
parameters:
  policy: readonly
  anonymous: "false"

使用 BucketAccess 生成凭证

apiVersion: objectstorage.k8s.io/v1alpha1
kind: BucketAccess
metadata:
  name: my-bucket-readonly-access
  namespace: app-a
spec:
  bucketAccessClassName: ceph-readonly-access-class
  bucketClaimName: my-bucket-claim
  credentialsSecretName: my-bucket-readonly-credentials

驱动会写入名为 credentialsSecretName 的 Secret。解码 .data.BucketInfo(base64)即可获得 secretS3.endpointaccessKeyIDaccessSecretKey,供你的 S3 客户端使用。

提示:为每个 Deployment/Job 颁发不同的凭证,简化凭证轮换和撤销,避免影响其他工作负载。

第 5 步 — 匿名公共读取(可选)

如果需要公共静态资源托管:

apiVersion: objectstorage.k8s.io/v1alpha1
kind: BucketAccessClass
metadata:
  name: ceph-anonymous-readonly-class
authenticationType: KEY
driverName: ceph.objectstorage.k8s.io
parameters:
  policy: readonly
  anonymous: "true"

将其绑定到你的 BucketClaimBucketAccess。授权后,对象可通过未认证的 HTTP GET 访问(请确保网络暴露配置正确)。

第 6 步 — 配额控制:在哪里执行及如何修改

作用范围: CephObjectStoreUser 上的 quotas 块针对每个用户生效,由 RGW 在该用户拥有的所有桶中统一执行。

  • maxBuckets:用户可创建/拥有的桶数量上限。
  • maxObjects:用户可存储的对象总数上限(跨桶)。
  • maxSize:用户允许的总逻辑存储大小。

更新配额,编辑 COSU 资源:

kubectl -n rook-ceph edit cephobjectstoreuser user-for-cosi
# 修改 spec.quotas.{maxBuckets,maxObjects,maxSize},保存退出。
# Rook 会自动调和并应用新的 RGW 用户配额。

设计选择: 保持 COSU 配额 较为严格,以限制影响范围。通过 BAC/BA 使用最小权限策略,限制应用凭证在桶内的操作权限。

运行与故障排查

  • 命名空间位置CephObjectStoreUser 及其 Secret 必须在 rook-ceph,应用级资源(BucketClaimBucketAccess)应在应用命名空间。
  • 策略未生效:确认 BAC 中的 bucketAccessClassNameparameters.policy 是否正确(readonly|writeonly|readwrite)。
  • 匿名读取失败:确保 anonymous: "true" 是字符串类型而非布尔值;检查 endpoint 暴露和 HTTP 访问路径(/<bucket>/<object>)。
  • 找不到密钥:检查 BucketAccess Secret,解码 .data.BucketInfo
  • 凭证轮换:创建新的 BucketAccess,将工作负载切换到新 Secret,随后删除旧 Secret 和 BA。

清理

  • 删除工作负载凭证:删除对应的 BucketAccess 和引用的 Secret。
  • 删除桶:删除 BucketClaim(行为遵循 BucketClass.deletionPolicy)。