- 存储
- 分布式文件系统
- 对象存储
- 后端
- 高可用
【免费下载链接】ceph
Ceph is a distributed object, block, and file storage platform
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_size与get_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_prefix与rgw_crypt_sse_s3_vault_prefix配置项分隔。给 SSE-KMS 桶所有者授权时,不要授予其操作 SSE-S3 密钥的权限——只有 Ceph 本身应该管理 SSE-S3 密钥。
Bucket 级加密 API
RGW 还支持桶级加密 API,用于配合 S3 托管密钥(SSE-S3)或 AWS KMS 主密钥(SSE-KMS),包括PutBucketEncryption、GetBucketEncryption、DeleteBucketEncryption(详见 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:8100Vault 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"] } EOFTransit 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 engine(key=<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-gcm96Transit 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 mybucketkeyRGW 从 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 Configuration→Client Device Communication Certificates→Modify 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)。
前置步骤
- 配置 Keystone:参见 doc/radosgw/keystone.rst。
- 创建 Keystone 用户:供 RGW 取钥使用,例如
user = rgwcrypt-user、pass = rgwcrypt-password、tenant = 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 v2:
rgw keystone barbican tenant = rgwcrypt - Keystone API v3:
rgw keystone barbican project与rgw 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 TTL(rgw_crypt_s3_kms_cache_positive_ttl) | 成功取回的密钥在缓存中保留的时长 |
Negative TTL(rgw_crypt_s3_kms_cache_negative_ttl) | 记住“某密钥不存在”的时长,避免对 KMS 的无效重复请求 |
Transient Error TTL(rgw_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:缓存清空次数(同时重置size、hit、miss、expired)
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-cache与rgw集合的指标观察命中率与取钥延迟。 - URL 限制:通过
rgw crypt vault prefix/rgw crypt kmip kms key template将 RGW 的取钥范围限制在指定路径/命名子集,最小化密钥暴露面。
- 存储
- 分布式文件系统
- 对象存储
- 后端
- 高可用
【免费下载链接】ceph
Ceph is a distributed object, block, and file storage platform
相关推荐
Ceph RGW 集成 HashiCorp Vault 作为 SSE-KMS 密钥管理后端:配置、认证与加密全指南
Ceph RGW 集成 HashiCorp Vault 作为 SSE KMS 密钥管理后端:配置、认证与加密全指南 Ceph 对象网关(RADOS Gatewa
存储分布式文件系统对象存储后端高可用Ceph RGW 集成 KMIP:以 KMIP 协议作为 SSE-KMS 密钥管理后端的完整配置指南
Ceph RGW 集成 KMIP:以 KMIP 协议作为 SSE KMS 密钥管理后端的完整配置指南 本文基于当前仓库 doc/radosgw/kmip.rst
存储分布式文件系统对象存储后端高可用Rook 对象存储 SSE-S3 服务端加密实战:Ceph RGW 与 HashiCorp Vault 的静态 Token 与 Vault Agent 集成指南
Rook 对象存储 SSE S3 服务端加密实战:Ceph RGW 与 HashiCorp Vault 的静态 Token 与 Vault Agent 集成指南
云原生存储容器编排运维
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考