Ceph RGW 服务端加密(SSE)完全指南:算法选择、KMS 集成与密钥缓存
2026/9/23 22:24:34 网站建设 项目流程
  • 存储
  • 分布式文件系统
  • 对象存储
  • 后端
  • 高可用

【免费下载链接】ceph

Ceph is a distributed object, block, and file storage platform

项目地址:https://gitcode.com/gh_mirrors/ce/ceph
点击查看免费下载

Ceph 对象网关(RGW)支持对上传对象进行服务端加密(Server-Side Encryption,SSE),数据在 HTTP 传输时保持明文,落盘到 Ceph 存储集群时以加密形式保存。本文基于 doc/radosgw/encryption.rst 及其配套的 vault.rst、kmip.rst、barbican.rst 文档,系统讲解 AES-256-CBC/GCM 算法、SSE-C/SSE-KMS/SSE-S3 三种密钥管理模式、Vault/KMIP/Barbican 三种 KMS 后端的完整配置,以及 KMS 密钥缓存的 TTL 与指标机制,帮助你在生产集群中正确选型与部署 RGW 服务端加密。

服务端加密基本概念与安全前提

服务端加密的含义是:客户端通过 HTTP(S) 上传的明文对象,在 RGW 内部被加密后才写入 Ceph 存储集群;读取对象时,RGW 自动解密后返回明文。对客户端而言,数据在网络上是明文(可选 TLS 保护),在磁盘上是密文,密钥永远不会出现在存储层。

使用服务端加密有两个强制前提:

  • 必须走安全的 HTTPS 连接,避免密钥信息以明文在网络中传输。如果使用了反向代理做 SSL 终止(SSL termination),必须在 Ceph 配置中开启rgw trust forwarded https,代理转发过来的请求才会被 RGW 视为安全通道。
  • 服务端加密密钥必须是 256 位(256-bit)且以 base64 编码。这一点贯穿所有加密模式(SSE-C、SSE-KMS、SSE-S3)与所有 KMS 后端(Vault、KMIP、Barbican)。

加密算法:AES-256-CBC 与 AES-256-GCM

RGW 支持两种 AES-256 加密算法(自 "Umbrella" 版本引入),通过配置项rgw crypt sse algorithm指定:

rgw crypt sse algorithm = aes-256-cbc # 默认值,为向后兼容而保留 rgw crypt sse algorithm = aes-256-gcm # 新部署推荐
  • AES-256-CBC(Cipher Block Chaining):传统加密算法,兼容旧版 Ceph,作为默认值以保持向后兼容。CBC 只提供机密性(confidentiality),不提供内置的完整性校验
  • AES-256-GCM(Galois/Counter Mode):现代认证加密(AEAD)算法,同时提供机密性与完整性保护,能检测密文被篡改或损坏,是新部署的推荐算法

在源码层面,这一开关的判定出现在 src/rgw/rgw_crypt.cc 中,例如const bool use_gcm = (s->cct->_conf->rgw_crypt_sse_algorithm == "aes-256-gcm");(见 rgw_crypt.cc),即按配置选择 GCM 或回退到 CBC 路径。

算法切换的注意事项

  • 该配置只影响新加密的对象。已有对象无论当前配置如何,始终使用其加密时采用的算法解密。因此 CBC 加密对象与 GCM 加密对象可以在同一集群中共存。
  • 升级旧版本 Ceph 时,务必保持默认的aes-256-cbc配置,直到所有 RGW 实例都完成升级;当所有实例都支持 GCM 后,再为新的上传启用aes-256-gcm

GCM 加密格式与存储开销

AES-256-GCM 将数据按4 KB(4096 字节)块加密,每个块产出 4112 字节密文(4096 字节加密数据 + 16 字节认证标签)。相关常量在 src/rgw/rgw_crypt.h 中定义:

static constexpr size_t AEAD_CHUNK_SIZE = 4096; static constexpr size_t AEAD_TAG_SIZE = 16; static constexpr size_t AEAD_ENCRYPTED_CHUNK_SIZE = AEAD_CHUNK_SIZE + AEAD_TAG_SIZE; // 4112

文档中给出一个 GCM 尺寸计算示例:

描述大小说明
原始明文10,000 字节用户数据
分块数3⌈10000 ÷ 4096⌉
认证标签48 字节3 块 × 16 字节
磁盘上的加密大小10,048 字节明文 + 标签

存储开销约为 0.4%(每 4 KB 增加 16 字节)。S3 API 响应始终报告原始明文大小,因此该开销对客户端完全透明。rgw_crypt.h中还提供了加密大小↔明文大小的换算辅助函数(如get_encrypted_sizeget_plaintext_size,见 rgw_crypt.h),并针对“剩余密文不足一个标签大小”的畸形块给出错误日志,说明格式校验是严格实现的。

三种密钥管理模式:SSE-C、SSE-KMS、SSE-S3

RGW 的服务端加密按密钥管理方式分为三种模式:

SSE-C(Customer-Provided Keys,客户提供密钥)

客户端在每次读写请求中都携带加密密钥,由客户端自行管理密钥,并记住每个对象使用了哪把密钥。此模式遵循 Amazon 的 SSE-C 规范。

由于密钥管理完全在客户端侧完成,RGW 无需任何特殊 Ceph 配置即可支持该模式。相应地,客户端必须自行负责密钥的保管、分发与对象↔密钥的映射。

SSE-KMS(Key Management Service,密钥管理服务)

管理员将密钥存放在安全的密钥管理服务中,RGW 按需从 KMS 检索密钥来执行加密或解密。此模式遵循 Amazon 的 SSE-KMS 规范。

原则上任何 KMS 都可以接入,当前仓库已实现的集成包括:

  • OpenStackBarbican(详见 doc/radosgw/barbican.rst)
  • HashiCorpVault(详见 doc/radosgw/vault.rst)
  • KMIP(详见 doc/radosgw/kmip.rst)

客户端上传对象时在请求中指定--sse=aws:kms--sse-kms-key-id <key-id>,RGW 据此从 KMS 取出密钥完成加密。

SSE-S3(S3 托管密钥)

密钥对用户完全不可见:密钥仍存储在 Vault 中,但由 Ceph自动创建、自动删除,需要时自动检索。此模式遵循 Amazon 的 SSE-S3 规范。

当前仅实现了 Vault 集成。安全建议:如果同时使用 SSE-KMS 与 SSE-S3,应将两者指向独立的容器——可以是独立的 Vault 实例、单独挂载的 transit 实例,或同一 transit 挂载点下的不同分支,通过 vault.rst 中提到的rgw_crypt_vault_prefixrgw_crypt_sse_s3_vault_prefix配置项分隔。给 SSE-KMS 桶所有者授权时,不要授予其操作 SSE-S3 密钥的权限——只有 Ceph 本身应该管理 SSE-S3 密钥

Bucket 级加密 API

RGW 还支持桶级加密 API,用于配合 S3 托管密钥(SSE-S3)或 AWS KMS 主密钥(SSE-KMS),包括PutBucketEncryptionGetBucketEncryptionDeleteBucketEncryption(详见 encryption.rst),可对桶内对象批量启用/查询/关闭服务端加密。

自动加密(仅限测试用途)

可以在 ceph.conf 中设置rgw crypt default encryption key,强制所有未指定加密模式的对象都进行加密。配置值必须是base64 编码的 256 位密钥,例如:

rgw crypt default encryption key = 4YSmvJtBv0aZ7geVgAsdpRnLBEwWSWlMIGnRS8a9TSA=

在源码中,该配置出现在 src/rgw/rgw_crypt.cc 的自动加密路径中(如s->cct->_conf->rgw_crypt_default_encryption_key != ""分支,见 rgw_crypt.cc),密钥经from_base64解码后用作主密钥。

重要警告:此模式仅用于诊断/测试目的!ceph.conf 不是存储加密密钥的安全方式。任何意外暴露在该配置中的密钥都应视为已泄露(compromised),必须立即更换。

KMS 集成一:HashiCorp Vault

Vault 可作为 SSE-KMS 的安全密钥管理后端。RGW 支持的 Vault secrets engine 与认证方式如下。

支持的 Secrets Engine

  • KV secrets engine v2:存储任意的键/值密钥对。在 Vault 侧启用:vault secrets enable -path secret kv-v2;RGW 侧配置rgw crypt vault secret engine = kv
  • Transit engine:对传输中的数据执行密码学操作。启用:vault secrets enable transit;RGW 侧配置rgw crypt vault secret engine = transit

KV engine 中,secret 以键值对存储,RGW 约定密钥字段名为key,即 secret 必须是key=<secret key>形式。

认证方式与 Token 策略

RGW 支持两种 Vault 认证方式:

Token 认证(配置文件指定 token 文件):

rgw crypt vault auth = token rgw crypt vault token file = /run/.rgw-vault-token rgw crypt vault addr = https://vault-server-fqdn:8200

出于安全考虑,token 文件必须仅对 RGW 可读。注意:绝大多数 Vault token 都有生命周期(root token 除外),而 Ceph 自身没有刷新 token 的逻辑。最稳妥的实践是同时运行 Vault agent 来刷新 token 文件,并利用文件系统权限限制 token 的使用者。

Vault agent 认证(代理模式,RGW 指向本地 agent):

rgw crypt vault auth = agent rgw crypt vault addr = http://127.0.0.1:8100

Vault agent 可代为添加/续期 token,支持 AppRole、AWS、Certs、JWT、Azure 等更多认证机制。采用代理模式时,务必确保 RGW 到 Vault agent 的网络路径安全(例如让 agent 只监听 localhost)。

Token 策略(Policy)示例——KV engine 只读策略:

vault policy write rgw-kv-policy -<<EOF path "secret/data/*" { capabilities = ["read"] } EOF

Transit engine 策略(含denied_parameters防止导出密钥、允许轮换):

vault policy write rgw-transit-policy -<<EOF path "transit/keys/*" { capabilities = [ "create", "update" ] denied_parameters = {"exportable" = [], "allow_plaintext_backup" = [] } } path "transit/keys/*" { capabilities = ["read", "delete"] } path "transit/keys/" { capabilities = ["list"] } path "transit/keys/+/rotate" { capabilities = [ "update" ] } path "transit/*" { capabilities = [ "update" ] } EOF

如果从旧版 Ceph 升级且之前使用 transit engine 作为简单密钥仓库,可能需要追加旧策略:path "transit/export/encryption-key/*" { capabilities = ["read"] }

Vault Namespace(企业版)

Vault Enterprise 支持命名空间(namespace)以隔离租户。RGW 通过配置项访问指定命名空间:

rgw crypt vault namespace = tenant1

在 Vault 中创建密钥

KV enginekey=<base64 密钥>形式):

vault kv put secret/myproject/mybucketkey key=$(openssl rand -base64 32)

Transit engine(创建aes256-gcm96类型密钥环,默认不可导出):

vault write -f transit/keys/mybucketkey vault read transit/keys/mybucketkey # 验证:type 应为 aes256-gcm96

Transit engine 兼容模式

transit engine 对旧版 Ceph(将其当作简单密钥仓库)提供兼容支持,通过compat选项配置:

  • rgw crypt vault secret engine = transit compat=0:完全禁用向后兼容(未来版本默认,新安装安全)。
  • rgw crypt vault secret engine = transit compat=1当前版本默认。新对象用新引擎,旧对象仍走旧引擎;此时 Vault token 需同时具备新旧两套 transit 策略。
  • rgw crypt vault secret engine = transit compat=2:强制仅用旧引擎。若 Vault prefix 以export/encryption-key结尾(旧文档配置方式),会自动选择该模式。

配置 RGW 使用 Vault

完整的 Vault KMS 配置汇总(写入 Ceph 配置文件):

rgw crypt s3 kms backend = vault # 认证方式二选一 rgw crypt vault auth = token rgw crypt vault token file = /run/.rgw-vault-token rgw crypt vault addr = https://vault-server-fqdn:8200 # 或 rgw crypt vault auth = agent rgw crypt vault addr = http://localhost:8100 # secrets engine 二选一 rgw crypt vault secret engine = kv # 或 rgw crypt vault secret engine = transit # 可选:命名空间 rgw crypt vault namespace = tenant1 # 可选:限制取钥 URL 前缀 rgw crypt vault prefix = /v1/secret/data # KV engine # 或 rgw crypt vault prefix = /v1/transit # transit engine # 可选:自定义 SSL 证书(强烈建议 verify ssl = true) rgw crypt vault verify ssl = true rgw crypt vault ssl cacert = /etc/ceph/vault.ca rgw crypt vault ssl clientcert = /etc/ceph/vault.crt rgw crypt vault ssl clientkey = /etc/ceph/vault.key

其中vault.ca为 CA 证书,vault.key/vault.crt是 RGW 访问 Vault 服务器的私钥与证书。文档明确警告:verify ssl设为false非常危险,应避免在生产环境使用。

取钥 URL 的构造规则:secret 的获取地址由“基础地址(rgw crypt vault addr)+ 可选前缀(rgw crypt vault prefix)+ key ID”拼接而成。例如 KV engine 下 key ID 为myproject/mybucketkey时,取钥地址为http://vaultserver:8200/v1/secret/data/myproject/mybucketkey;transit engine 下 key ID 为mybucketkey时,加密使用http://vaultserver:8200/v1/transit/mybucketkey

上传加密对象(Vault 示例)

使用 AWS CLI(KV engine):

aws --endpoint=http://radosgw:8000 s3 cp plaintext.txt s3://mybucket/encrypted.txt --sse=aws:kms --sse-kms-key-id myproject/mybucketkey

使用 AWS CLI(transit engine 新风格):

aws --endpoint=http://radosgw:8000 s3 cp plaintext.txt s3://mybucket/encrypted.txt --sse=aws:kms --sse-kms-key-id mybucketkey

RGW 从 Vault 取回密钥、加密对象并存入桶;后续任何下载请求都会自动从 Vault 检索对应密钥并解密。

KMS 集成二:KMIP

KMIP(OASIS 标准)可作为 SSE-KMS 后端。使用前需要完成三件事:在 KMIP 中为 Ceph 关联客户端信息、配置 Ceph 使用该客户端信息、在 KMIP 中创建密钥。

在 KMIP 中为 Ceph 设置访问权限

IBM SKLM(商业产品):基于证书认证。可以先用 OpenSSL 自签证书或由 SKLM 签发证书,再配置 Ceph 尝试使用——首次尝试会失败,但会在 SKLM 留下 "untrusted client device certificate",随后在 Web 界面(Advanced ConfigurationClient Device Communication CertificatesModify SSL/KMIP Certificates for Clients)中勾选信任并完成注册。

PyKMIP(实验/测试用):无注册流程,直接信任证书,但证书必须由 PyKMIP 信任的 CA 签发;PyKMIP 偏好证书包含 "extended key usage" 扩展(可通过服务器配置enable_tls_client_auth=False绕过)。

在 KMIP 中创建密钥

除 Web 界面外,可用 PyKMIP 客户端库创建 AES-256 密钥。首先安装并准备客户端配置(替换{hostname}{clientcert}{clientkey}{clientca}为实际值):

cat <<EOF >$HOME/my-kmip-configuration [client] host={hostname} port=5696 certfile={clientcert} keyfile={clientkey} ca_certs={clientca} ssl_version=PROTOCOL_TLSv1_2 EOF

随后用 Python 脚本创建密钥(create指定 AES/256,并附带ENCRYPT/DECRYPT使用掩码,再activate激活):

from kmip.pie import client from kmip import enums import os, sys, json, ssl c = client.ProxyKmipClient(config_file=os.environ['HOME']+"/my-kmip-configuration") while True: l = sys.stdin.readline() keyname = l.strip() if keyname == "": break with c: key_id = c.create( enums.CryptographicAlgorithm.AES, 256, operation_policy_name='default', name=keyname, cryptographic_usage_mask=[ enums.CryptographicUsageMask.ENCRYPT, enums.CryptographicUsageMask.DECRYPT, ]) c.activate(key_id) attrs = c.get_attributes(uid=key_id) r = {} for a in attrs[1]: r[str(a.attribute_name)] = str(a.attribute_value) print(json.dumps(r))

配置 RGW 使用 KMIP

rgw crypt s3 kms backend = kmip rgw crypt kmip ca path = /etc/ceph/kmiproot.crt rgw crypt kmip client cert = /etc/ceph/kmip-client.crt rgw crypt kmip client key = /etc/ceph/private/kmip-client.key rgw crypt kmip kms key template = pykmip-$keyid

路径需按实际存放位置调整。rgw crypt kmip kms key template描述 Ceph 在 KMIP 中查找密钥前如何改写传入的 key ID,默认值为$keyid(原样使用)。如果不希望 Ceph 看到 KMIP 中全部密钥,可用该模板将 Ceph 限定到密钥命名空间的某个子集。

上传加密对象(KMIP 示例)

aws --endpoint=http://radosgw:8000 s3 cp plaintext.txt \ s3://mybucket/encrypted.txt --sse=aws:kms --sse-kms-key-id mybucketkey

密钥从 KMIP 取回时使用由模板构造的名字(以$keyid替换为实际 key ID)。例如上述配置下,RGW 会查找名为pykmip-mybucketkey的密钥。

KMS 集成三:OpenStack Barbican

Barbican 依赖 Keystone 做授权与访问控制,整体调用关系可参考 doc/images/rgw-encryption-barbican.png(RGW 向 Keystone 获取 token,再携带 token 向 Barbican 请求密钥,Barbican 验证 token 后返回密钥,RGW 据此加密对象并写入 OSD)。

前置步骤

  1. 配置 Keystone:参见 doc/radosgw/keystone.rst。
  2. 创建 Keystone 用户:供 RGW 取钥使用,例如user = rgwcrypt-userpass = rgwcrypt-passwordtenant = rgwcrypt

在 Barbican 中创建密钥

请求必须携带有效的 Keystone token(X-Auth-Token头)。密钥要求同样是256 位、base64 编码。示例:

POST /v1/secrets HTTP/1.1 Host: barbican.example.com:9311 Accept: */* Content-Type: application/json X-Auth-Token: 7f7d588dd29b44df983bc961a6b73a10 Content-Length: 299 { "name": "my-key", "expiration": "2016-12-28T19:14:44.180394", "algorithm": "aes", "bit_length": 256, "mode": "cbc", "payload": "6b+WOZ1T3cqZMxgThRcXAQBrS5mXKdDUphvpxptl9/4=", "payload_content_type": "application/octet-stream", "payload_content_encoding": "base64" }

响应中的secret_ref末尾 UUID 即 key id(可用户任何 SSE-KMS 请求):

{"secret_ref": "http://barbican.example.com:9311/v1/secrets/d1e7ef3b-f841-4b7c-90b2-b7d90ca2d723"}

新创建的密钥默认对rgwcrypt-user不可访问,必须通过 ACL 授权(以下示例假设rgwcrypt-user的 Keystone id 为906aa90bd8a946c89cdff80d0869460f):

PUT /v1/secrets/d1e7ef3b-f841-4b7c-90b2-b7d90ca2d723/acl HTTP/1.1 Host: barbican.example.com:9311 Accept: */* Content-Type: application/json X-Auth-Token: 7f7d588dd29b44df983bc961a6b73a10 Content-Length: 101 { "read":{ "users":[ "906aa90bd8a946c89cdff80d0869460f" ], "project-access": true } }

配置 RGW 使用 Barbican

rgw crypt s3 kms backend = barbican rgw barbican url = http://barbican.example.com:9311 rgw keystone barbican user = rgwcrypt-user rgw keystone barbican password = rgwcrypt-password

按 Keystone API 版本补充租户/项目信息:

  • Keystone API v2rgw keystone barbican tenant = rgwcrypt
  • Keystone API v3rgw keystone barbican projectrgw keystone barbican domain(需按实际项目/域配置)

KMS 密钥缓存:TTL 机制、内核密钥环与监控指标

KMS 密钥缓存能显著提升服务端加密性能、减轻 KMS 负载。缓存实现位于 src/rgw/rgw_kms_cache.cc,构造时读取rgw_crypt_s3_kms_cache_max_size及三个 TTL 配置(见 rgw_kms_cache.cc)。

存储:Linux Kernel Key Retention Service

secret 缓存在RGW 进程的进程密钥环(process keyring)中(通过 Linux Kernel Key Retention Service)。该存储受全局配额限制,必须与配置的缓存大小相匹配。根据 RGW 是否以 root 运行,通过以下内核参数调整配额:

  • root 运行:/proc/sys/kernel/keys/root_maxkeys/proc/sys/kernel/keys/root_maxbytes
  • 非 root 运行:/proc/sys/kernel/keys/maxkeys/proc/sys/kernel/keys/maxbytes

超出配额会导致缓存被禁用、请求以内部错误失败,并记录失败日志。

三种 TTL

TTL 类型含义
Positive TTLrgw_crypt_s3_kms_cache_positive_ttl成功取回的密钥在缓存中保留的时长
Negative TTLrgw_crypt_s3_kms_cache_negative_ttl记住“某密钥不存在”的时长,避免对 KMS 的无效重复请求
Transient Error TTLrgw_crypt_s3_kms_cache_transient_error_ttl对 KMS 超时等临时故障的缓存时长

TTL 回收由独立的 reaper 线程/定时器驱动(make_ttl_reaper_thread,见 rgw_kms_cache.cc),其运行周期取三个 TTL 的最小值。

监控指标

缓存本身在kms-cache集合下导出指标:

  • hit:缓存命中计数器
  • miss:缓存未命中计数器
  • expired:TTL 过期条目数
  • size:当前缓存大小
  • capacity:缓存最大容量
  • clear:缓存清空次数(同时重置sizehitmissexpired

rgw集合还提供 KMS 请求级指标(定义于 src/rgw/rgw_perf_counters.cc,在 src/rgw/rgw_kms.cc 中递增):

  • kms_fetch_lat:平均 KMS 取钥延迟(附带成功请求计数;每次成功都会产生一个 positive 缓存条目)
  • kms_error_transient:临时性 KMS 取钥错误计数(每次触发 transient error 缓存条目)
  • kms_error_permanent:永久性 KMS 取钥错误计数(如密钥不存在;每次触发 negative 缓存条目)

常见问题与最佳实践小结

  • 算法升级路径:旧集群先保持aes-256-cbc,全部 RGW 实例升级后再切aes-256-gcm;新对象用新算法、旧对象自动按原算法解密,两者可共存。
  • 密钥安全:密钥一律 256 位 base64;rgw crypt default encryption key仅限诊断使用,一旦泄露立即视为密钥失密并更换。
  • 传输安全:SSE 请求必须走 HTTPS;使用代理终结 SSL 时记得开rgw trust forwarded https
  • KMS 认证:Vault token 有生命周期,建议配合 Vault agent 续期;不要在生产使用 root token;SSE-KMS 与 SSE-S3 的 Vault 权限务必隔离。
  • 缓存调优:根据实际密钥规模设置rgw_crypt_s3_kms_cache_max_size并同步调整内核密钥环配额(maxkeys/maxbytes),避免配额触发导致请求失败;用kms-cachergw集合的指标观察命中率与取钥延迟。
  • URL 限制:通过rgw crypt vault prefix/rgw crypt kmip kms key template将 RGW 的取钥范围限制在指定路径/命名子集,最小化密钥暴露面。
  • 存储
  • 分布式文件系统
  • 对象存储
  • 后端
  • 高可用

【免费下载链接】ceph

Ceph is a distributed object, block, and file storage platform

项目地址:https://gitcode.com/gh_mirrors/ce/ceph
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询