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_modecipher必须为“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加密相关推荐

  1. [转]信息安全相关理论题(二)

    27.在工程实施之前,验收方可以不给施工方弱电布线图纸,但施工结束后必须有图纸 A. 对 B. 错 您的答案: 标准答案: B 28.在OSI七层协议中,提供一种建立连接并有序传输数据的方法的层是 A ...

  2. kvm qcow2和ceph rbd虚拟机磁盘加密

    微信公众号:运维开发故事,作者:wanger kvm qcow2磁盘加密 关于luks加密 LUKS 实现了一种独立于平台的标准磁盘格式,用于各种工具.LUKS 用于加密块设备.加密设备的内容是任意的 ...

  3. Cephx认证及rbd的使用

    CephX 认证机制: Ceph 使用 cephx 协议对客户端进行身份认证 cephx 用于对 ceph 保存的数据进行认证访问和授权,用于对访问 ceph 的请求进行认证和授 权检测,与 mon ...

  4. 2. Ceph的权限管理、RBD与Cephfs的挂载使用和MDS的高可用

    1. Ceph用户的权限管理及授权流程 Ceph使用Ceph X协议对客户端进行身份的认证. 客户端与Mon节点的通讯均需要通过Cephx认证,可在Mon节点关闭Cephx认证,关闭认证后将允许所有访 ...

  5. k8s主从自动切换mysql_K8S与Ceph RBD集成-多主与主从数据库示例

    参考文章: 感谢以上作者提供的技术参考,这里我加以整理,分别实现了多主数据库集群和主从数据库结合Ceph RDB的实现方式.以下配置只为测试使用,不能做为生产配置. K8S中存储的分类 在K8S的持久 ...

  6. 【云原生 | Kubernetes 系列】--Ceph认证和RBD

    1. Ceph 认证机制 ceph使用cephx协议对客户端进行身份认证. cephx用于对ceph保存的数据进行认证访问和授权,用于对访问ceph的请求进行认证和授权检查,与mon通信的请求都要经过 ...

  7. ceph rbd mysql_如何在 Kubernetes 环境中搭建 MySQL(三):使用 PVC 挂接 RBD

    MySQL in Kubernetes MySQL 中的数据是关键信息,是有状态的,不可能随着 MySQL pod 的销毁而被销毁,所以数据必须要外接到一个可靠的存储系统中,目前已经有了 Ceph 系 ...

  8. Ceph 认证授权和RBD块存储、对象存储使用(三)

    RBD块存储 RBD介绍 1.RBD是Ceph分布式集群中最常用的存储类型 2.块是一个有序字节,普通的一个块大小为512字节,基于块的存储是最常见的存储方式,比如常见的硬盘.软盘和CD光盘等,都是存 ...

  9. SPDK简介(其与Ceph rbd的关系)

    转载:SPDK简介 SPDK(Storage Performance Development Kit)是Intel发布的存储性能开发工具集. 简介 固态存储设备正在取代数据中心.目前这一代的闪存存储, ...

  10. RSA签名算法,计算调用加密报文,安全传输

    RSA签名算法 1. 获取当前的时间戳参数 2. 计算参数签名 3. 获取请求对象的MD5密文 4. 通过私钥计算某个参数的RSA签名 5. 转换字符集到utf8 6. MD5加密字符串 7. bas ...

最新文章

  1. 李开复:AI进入落地期,单凭科学家颠覆行业的机会几乎不存在,这个领域除外...
  2. 网内病毒问题快速排除集锦
  3. Android --- RecycleView获取第 i 个 item 里面的控件并进行赋值
  4. 【网络安全】Metasploit生成的Shellcode的导入函数解析以及执行流程分析(2)
  5. 2高并发服务器:多路IO之poll
  6. JVM系列之:对象的锁状态和同步
  7. Asp.net导出Excel报表(解决无网格问题)
  8. 计算机网络校园网网络设计报告,计算机网络课程设计报告-校园网的组建和应用...
  9. wifi 协议栈的历史的总结
  10. 软件测试基础知识【纯知识分享】
  11. 上传照片(身份证照片正反面)
  12. (十二)苏世民:我的经验和教训:苏世民带领黑石走向巅峰的十大管理原则
  13. ArcGIS 网络分析[2.3] 最近设施点
  14. HTML网页设计结课作业~仿蘑菇街商城网站源码(HTML+CSS+JS)
  15. HCIP课堂笔记总结
  16. C#多线程(二) -- ThreadStart
  17. jQuery keydown事件
  18. 华为麦芒6支持鸿蒙吗,华为麦芒6支持电信吗_华为麦芒6支持电信卡吗-太平洋IT百科...
  19. 2019年5月25日
  20. Oracle Advanced Queuing 触发器入列和异步通知消息出列

热门文章

  1. 路由器与交换机知识总
  2. Android MediaRecorder录制视频
  3. 微软商店上架WindowsOffice破解工具,并获5星好评?
  4. 微信支付SDK使用总结
  5. 大疆网上测评题库_大疆在线测评 - 逻辑题
  6. 多目标进化算法(二)——非支配排序/NSGA-II
  7. eighth day for learning
  8. Qos限速、流量监管、流量整形原理和实验(华为设备)
  9. win7休眠、待机api
  10. 老婆,我竟在婚礼上失去了你!-_-!!