ceph16 rbd加密
1 命令
rbd encryption format {pool-name}/{image-name} {luks1|luks2} {passphrase-file} [–cipher-alg {aes-128 | aes-256}] 对image加密
src/tools/action/Encryption.cc中实现此命令
rbd -p {pool-name} device map {image-name} -t nbd -o encryption-format={luks1|luks2},encryption-passphrase-file={passphrase-file} 映射加密的image为磁盘
rbd -p {pool-name} device unmap {image-name} -t nbd -o encryption-format={luks1|luks2},encryption-passphrase-file={passphrase-file}
src/tools/action/Nbd.cc中实现这三个命令,需要内核的nbd模块支持
2 encryption format
src/librbd/librbd.cc中的rbd_encryption_format函数对image加密
这里的create_encryption_format函数用来创建librbd::crypto::EncryptionFormat类(src/librbd/crypto/EncryptionFormat.h中定义)对象。
若format的值为RBD_ENCRYPTION_FORMAT_LUKS1,则创建的是
librbd::crypto::luks::LUKS1EncryptionFormat类(是类 librbd::crypto::EncryptionFormat
的子类,在src/librbd/crypto/luks/EncryptionFormat.h中定义)对象。
若format的值为RBD_ENCRYPTION_FORMAT_LUKS2,则创建的是
librbd::crypto::luks::LUKS2EncryptionFormat类(是类librbd::crypto::EncryptionFormat的子
类,在src/librbd/crypto/luks/EncryptionFormat.h中定义)对象。
m_alg是加密类型:RBD_ENCRYPTION_ALGORITHM_AES128和
RBD_ENCRYPTION_ALGORITHM_AES256,由opts->alg确定。
接下来的librbd::crypto::FormatRequest<I>::create函数和req->send()创建一个format请求
(librbd::crypto::FormatRequest类,在src/librbd/crypto/FormatRequest.h中定义)并处理
这里的m_format即是前面创建的librbd::crypto::EncryptionFormat类对象,其实调用的是
librbd::crypto::luks::EncryptionFormat类(在src/librbd/crypto/luks/EncryptionFormat.h中定
义)的format函数
RAND_bytes((unsigned char *)key, key_size) 生成加密密钥
文件src/librbd/crypto/luks/Header.cc中调用cryptSetup库的API用于加密头部信息处理
m_header.init() 在内存中创建一个文件,用来暂时存放加密头部信息
m_fd = syscall(SYS_memfd_create, "LibcryptsetupInterface", 0) 创建一个内存文件
path = "/proc/" + to_string(getpid()) + "/fd/" + to_string(m_fd) 通过/proc下的fd来访问它
crypt_init(&m_cd, path.c_str()) 初始化crypt device上下文信息
m_header.format(…) 格式化luks标头
crypt_format(m_cd, type, alg, cipher_mode, NULL, key, key_size, params) 在上面创
建的文件中格式化luks标头
m_cd crypt device上下文
type 是luks类型:CRYPT_LUKS1 或 CRYPT_LUKS2
alg 是加密类型: aes
key 加密密钥
cipher_mode 这里设置为"xts-plain64"
可以通过params设置data_alignment(这里设置为ceph对象大小/512),luks2还可
以设置sector_size (luks1是512字节,luks2是4096字节)
m_header.add_keyslot(m_passphrase.c_str(), …)
crypt_keyslot_add_by_volume_key(m_cd, CRYPT_ANY_SLOT, NULL, 0, passphrase,
passphrase_size) 在crypt device上创建密钥槽,这里的密钥是用户密钥,上面的key是加
密密钥,不要混淆了。crypt device的密钥槽可以有多个,既可以有多个用户密码。
crypSetup的crypt_keyslot_add_by_passphrase也可以用来设置密钥槽。
util::build_crypto(m_image_ctx->cct, key, key_size, m_header.get_sector_size(),
m_header.get_data_offset(), m_result_crypto)
key 加密密钥
m_header.get_sector_size() 既上面设置的sector_size
m_header.get_data_offset() 数据偏移,因为luks加密头部信息也需要写入到image中,
导致用户数据在image中的偏移不是从0开始,而是要加上luks加密头部信息等长度。这个值
就是用户数据在image中的起始偏移值,也就是luks加密头部信息长度,luks1和luks2的都
是32MB。
openssl::DataCryptor类在src/librbd/crypto/openssl/DataCryptor.h中定义,注意是对
openssl库中EVP_CIPHER_系列函数的封装
openssl::DataCryptor类的init函数调用EVP_get_cipherbyname(cipher_suite)获取
m_cipher(const EVP_CIPHER*类型) (加密类型为aes-128时,cipher_suite为"aes-
128-xts",key_length为32;为aes-256时,cipher_suite为"aes-256-xts",key_length为
64)。 openssl::DataCryptor类的m_key存放加密密钥,m_key_size存放加密密钥长度
(既为key_length)。
创建类BlockCrypto对象,类BlockCrypto在src/librbd/crypto/BlockCrypto.h中定义,用
来使用上面的openssl::DataCryptor类方法对数据进行加解密。类BlockCrypto的
m_block_size既为前面的luks头的sector_size,m_data_offset既为用户数据在image中的
起始偏移值。
m_result_crypto(前面创建的librbd::crypto::FormatRequest类的成员)存放创建的这
个类BlockCrypto对象。
m_header.read(&bl);
读取创建的luks加密头等信息
把luks加密头等信息写入到image中。
Ctx里设置回调函数handle_write_header,加密头写入到image中后,会调用此回调函
数。handle_write_header中会调用librbd::crypto::luks::FormatRequest<I>::finish(…),里面
又会调用上层的回调,此回调中又会调用librbd::crypto::Format<I>::finish(…)。
这里的util::set_crypto(在src/librbd/crypto/Utils.cc中定义)调用下面4行创建ObjectDispatch和ImageDispatch,并注册此ObjectDispatch和ImageDispatch,用于对对象数据的 加解密auto object_dispatch = CryptoObjectDispatch<I>::create(image_ctx, crypto); auto image_dispatch = CryptoImageDispatch::create(crypto->get_data_offset());image_ctx->io_object_dispatcher->register_object_dispatch(object_dispatch)image_ctx->io_image_dispatcher->register_dispatch(image_dispatch)
3 encryption load
src/librbd/librbd.cc中的rbd_encryption_load函数从image中获取luks加密头信息
这里的create_encryption_format函数和encryption format一节中的作用相同,已经讲过,这里不再重复。
接下来的librbd::crypto::LoadRequest<I>::create函数和req->send()创建一个load请求(librbd::crypto::LoadRequest类,在src/librbd/crypto/ LoadRequest.h中定义)并处理
这里的m_format即是前面创建的librbd::crypto::LoadRequest类对象,其实调用的是librbd::crypto::luks::EncryptionFormat类(在src/librbd/crypto/luks/EncryptionFormat.h中定义)的load函数,获取完luks加密头信息后,就调用回调finish,里面调用util::set_crypto函数,作用在encryption format一节中相同,在此不再重复介绍。
Luks::LoadRequest在src/librbd/luks/LoadRequest.h中定义
m_header.init() 在内存中创建一个文件,用来暂时存放加密头部信息
m_fd = syscall(SYS_memfd_create, "LibcryptsetupInterface", 0) 创建一个内存文件
path = "/proc/" + to_string(getpid()) + "/fd/" + to_string(m_fd) 通过/proc下的fd来访问它
crypt_init(&m_cd, path.c_str()) 初始化crypt device上下文信息
read(m_initial_read_size, ctx)
auto req = io::ImageDispatchSpec::create_read(*m_image_ctx,
io::IMAGE_DISPATCH_LAYER_API_START, aio_comp, {{m_offset, length}},
io::ReadResult{&m_bl}, m_image_ctx->get_data_io_context(), 0, 0, trace);
req->send();
从image中读取在encryption format阶段写入的luks加密头等信息,m_offset为0,length为
DEFAULT_INITIAL_READ_SIZE(既288 * 1024)
m_header.write(m_bl) 把从image中读取的luks加密头等信息写入到crypt device文件中
m_header.load(type)
crypt_load(m_cd, type, NULL) 从crypt device文件加载crypt device参数信息,因为最后
一个参数为NULL,则在这里只是检查上一步的写入是否成功
调用m_header.get_cipher()和m_header.get_cipher_mode()分别获取cipher和
cipher_mode,cipher必须为“aes”,cipher_mode必须为"xts-plain64"
m_header.read_volume_key(m_passphrase.c_str(), m_passphrase.size(),
reinterpret_cast<char*>(volume_key), &volume_key_size)
调用cryptSetup的crypt_volume_key_get函数根据用户密码从crypt device文件中获取加密
密码。
因为用户密码可以有多个,因此实际用到的加密头部等信息不是固定的(最多是
m_header.get_data_offset()既32MB),前面只从image中读取了
DEFAULT_INITIAL_READ_SIZE字节,小于m_header.get_data_offset(),读出来的信息中
可能并不包含密码m_passphrase,需要执行上面的从image中读luks头部等信息(读取大小
为m_header.get_data_offset()),写入crypt device文件,调用crypt_volume_key_get根据用
户密码从crypt device文件中获取加密密码。
util::build_crypto(m_image_ctx->cct, m_header.get_cipher(),reinterpret_cast<unsigned char*>(volume_key),volume_key_size, m_header.get_sector_size(), m_header.get_data_offset(), m_result_crypto)创建用于对数据进行加解密的类BlockCrypto对象,类BlockCrypto在src/librbd/crypto/BlockCrypto.h中定义。util::build_crypto的具体介绍在上一节encryption format中已经讲过,这里不再重复。
4 用户数据到object的映射
因为luks加密头部信息也需要写入到image中,导致用户数据在image中的偏移不是从0开始,而是要加上luks加密头部信息等长度。
librbd::io::util::file_to_extents用于把用户数据映射到object
librbd::io::util::extent_to_file用于把object映射为用户数据
类librbd::crypto::CryptoImageDispatch的remap_extents用来在用户数据和image数据之间相互映射,里面会加减luks加密头部信息等长度(32M)。
Striper::extent_to_file和Striper::file_to_extents根据条带算法在image数据和object直接相互映射
5 Image实际大小
因为luks加密头部信息也需要写入到image,导致用户实际可用的数据减小,需要减去luks加密头部信息等长度(32M)。如果不减去luks加密头部信息等长度会导致用户使用时出问题,例如:开启object map时,映射为磁盘后,对磁盘格式化出错。
添加ImageCtx::get_effective_image_size接口,获取用户实际可用的数据。
image_info接口中获取image大小时应该使用ImageCtx::get_effective_image_size,而不是get_image_size。
ceph16 rbd加密相关推荐
- [转]信息安全相关理论题(二)
27.在工程实施之前,验收方可以不给施工方弱电布线图纸,但施工结束后必须有图纸 A. 对 B. 错 您的答案: 标准答案: B 28.在OSI七层协议中,提供一种建立连接并有序传输数据的方法的层是 A ...
- kvm qcow2和ceph rbd虚拟机磁盘加密
微信公众号:运维开发故事,作者:wanger kvm qcow2磁盘加密 关于luks加密 LUKS 实现了一种独立于平台的标准磁盘格式,用于各种工具.LUKS 用于加密块设备.加密设备的内容是任意的 ...
- Cephx认证及rbd的使用
CephX 认证机制: Ceph 使用 cephx 协议对客户端进行身份认证 cephx 用于对 ceph 保存的数据进行认证访问和授权,用于对访问 ceph 的请求进行认证和授 权检测,与 mon ...
- 2. Ceph的权限管理、RBD与Cephfs的挂载使用和MDS的高可用
1. Ceph用户的权限管理及授权流程 Ceph使用Ceph X协议对客户端进行身份的认证. 客户端与Mon节点的通讯均需要通过Cephx认证,可在Mon节点关闭Cephx认证,关闭认证后将允许所有访 ...
- k8s主从自动切换mysql_K8S与Ceph RBD集成-多主与主从数据库示例
参考文章: 感谢以上作者提供的技术参考,这里我加以整理,分别实现了多主数据库集群和主从数据库结合Ceph RDB的实现方式.以下配置只为测试使用,不能做为生产配置. K8S中存储的分类 在K8S的持久 ...
- 【云原生 | Kubernetes 系列】--Ceph认证和RBD
1. Ceph 认证机制 ceph使用cephx协议对客户端进行身份认证. cephx用于对ceph保存的数据进行认证访问和授权,用于对访问ceph的请求进行认证和授权检查,与mon通信的请求都要经过 ...
- ceph rbd mysql_如何在 Kubernetes 环境中搭建 MySQL(三):使用 PVC 挂接 RBD
MySQL in Kubernetes MySQL 中的数据是关键信息,是有状态的,不可能随着 MySQL pod 的销毁而被销毁,所以数据必须要外接到一个可靠的存储系统中,目前已经有了 Ceph 系 ...
- Ceph 认证授权和RBD块存储、对象存储使用(三)
RBD块存储 RBD介绍 1.RBD是Ceph分布式集群中最常用的存储类型 2.块是一个有序字节,普通的一个块大小为512字节,基于块的存储是最常见的存储方式,比如常见的硬盘.软盘和CD光盘等,都是存 ...
- SPDK简介(其与Ceph rbd的关系)
转载:SPDK简介 SPDK(Storage Performance Development Kit)是Intel发布的存储性能开发工具集. 简介 固态存储设备正在取代数据中心.目前这一代的闪存存储, ...
- RSA签名算法,计算调用加密报文,安全传输
RSA签名算法 1. 获取当前的时间戳参数 2. 计算参数签名 3. 获取请求对象的MD5密文 4. 通过私钥计算某个参数的RSA签名 5. 转换字符集到utf8 6. MD5加密字符串 7. bas ...
最新文章
- 李开复:AI进入落地期,单凭科学家颠覆行业的机会几乎不存在,这个领域除外...
- 网内病毒问题快速排除集锦
- Android --- RecycleView获取第 i 个 item 里面的控件并进行赋值
- 【网络安全】Metasploit生成的Shellcode的导入函数解析以及执行流程分析(2)
- 2高并发服务器:多路IO之poll
- JVM系列之:对象的锁状态和同步
- Asp.net导出Excel报表(解决无网格问题)
- 计算机网络校园网网络设计报告,计算机网络课程设计报告-校园网的组建和应用...
- wifi 协议栈的历史的总结
- 软件测试基础知识【纯知识分享】
- 上传照片(身份证照片正反面)
- (十二)苏世民:我的经验和教训:苏世民带领黑石走向巅峰的十大管理原则
- ArcGIS 网络分析[2.3] 最近设施点
- HTML网页设计结课作业~仿蘑菇街商城网站源码(HTML+CSS+JS)
- HCIP课堂笔记总结
- C#多线程(二) -- ThreadStart
- jQuery keydown事件
- 华为麦芒6支持鸿蒙吗,华为麦芒6支持电信吗_华为麦芒6支持电信卡吗-太平洋IT百科...
- 2019年5月25日
- Oracle Advanced Queuing 触发器入列和异步通知消息出列