zl程序教程

您现在的位置是:首页 >  前端

当前栏目

cephx: ceph的认证和加密协议

认证 ceph
2023-09-11 14:17:45 时间
Ceph作为一个分布式存储系统,支持对象存储、块设备和文件系统。为了在网络传输中防止数据被篡改,做到较高程度的安全性,加入了Cephx加密认证协议。其目的是识别身份,加密、验证传输中的数据。 在ceph系统中,元数据保存在一个叫做ceph-mon的进程中,也可以称为monitor节点,系统可以有多个monitor副本节点,用paxos保持数据一致性。 这里不谈paxos,也不谈多个monitor

Ceph作为一个分布式存储系统,支持对象存储、块设备和文件系统。为了在网络传输中防止数据被篡改,做到较高程度的安全性,加入了Cephx加密认证协议。其目的是识别身份,加密、验证传输中的数据。

在ceph系统中,元数据保存在一个叫做ceph-mon的进程中,也可以称为monitor节点,系统可以有多个monitor副本节点,用paxos保持数据一致性。 这里不谈paxos,也不谈多个monitor节点,我们只以单个monitor为例,重点说明cephx的实现。

monitor保存了系统中重要的元数据,例如每个用户的key以及权限,这也是我们要重点谈及的,至于其他osdmap, crush数据在这里不涉及。

一个ceph系统主要由monitor, osd, client 这几种类型的节点组成。monitor存放元数据,osd存放对象,client就是使用ceph系统的客户端。

一个monitor里存放着和认证相关的数据,简单可以用表结构来描述:


client和osd 必须先连接到monitor进行认证。client和osd都有一个叫做monclient的模块负责认证和密钥交换。而monitor上有一个AuthMonitor的paxos服务模块负责与monclient对话,cephx协议的实现则位于ceph源代码目录src/auth/cephx,有好几个模块负责。

 

Cephx是一种对称密钥加密协议,加密算法使用AES,并包含临时密钥生成和替换。每个client和osd都在本地有一个密钥,该密钥的副本同样存在于monitor上。

Ceph里面每一个节点都会使用一个名称,类型是EntityName, 例如:client.admin, osd.1等。而每一个节点连接到monitor以后,monitor都会为其生成一个global id,代表这个节点在整个ceph 系统中的全局id。

monclient连接monitor的会话是为了获得session key、ticket以及临时密钥(rotating key)。

ceph 系统里面有auth认证服务,osdmap服务,还有文件系统的mds服务等。当节点之间彼此通讯时,刚连接开始时,使用ticket表明身份,使用rotating key加密加密解密ticket和session key, 验明身份后,后续通讯使用session key加、解密数据包。

在monclient里,对每一种服务monclient都保存有从monitor获得的数据:与某类型节点网络连接时的session key,与某类型节点网络连接对应的ticket, 与该种服务对应的rotating key.


cephx认证大致步骤如下:

monclient向monitor 发起连接,获得与monitor 通讯时的AUTH service的session key以及ticket。

认证信息是以后通讯中识别身份的凭据,其结构如下:

struct AuthTicket {

EntityName name;

uint64_t global_id; /* global instance id */

uint64_t auid;

utime_t created, renew_after, expires;

AuthCapsInfo caps;

__u32 flags;

};

内容依次是发起连接的实体名称,全局id、 用户id、一些和ticket生存周期有关的时间,以及权限。

struct CephXServiceTicketInfo {

AuthTicket ticket;

CryptoKey session_key;

};

 

我们在这里称CephxServiceTicketInfo为ticket,它包含认证信息以及session key。

通过了与monitor的认证以后,client就可以从monitor获取与每一种service类型的相关的session key 和ticket,例如与osd服务和mds服务相关的session key和ticket, ticket的name和global_id,auid是相同的,其他存活期时间信息和权限则是不同的,client在每一种service上可以有不同的权限。其中ticket数据对client是透明的,是被相关service的临时密钥加密的,其内容只有monitor和相关的service会去解密。


对于每一种service,它们的monclient除了上面的内容,还会定时从monitor获取它们自身这种service相关的临时密钥,主要数据结构如下:

一个会过期的密钥:

struct ExpiringCryptoKey {

CryptoKey key;

utime_t expiration

};

 

一个对过期密钥的管理器:

struct RotatingSecrets {

map uint64_t, ExpiringCryptoKey secrets;

version_t max_ver;

};

管理器包含3个密钥,依次是过去的、现在的和将来的,map的key是一个临时密钥id (称为secret id), 每次往里面添加一个密钥,max_ver增加1,并且把最前面个一密钥删除,始终保持3个密钥,所以每次增加一个密钥,他们的secret id都比以前的大,这样就不存在secret id重复。

当client准备发起对osd的访问时,就用对应的osd service的ticket去访问osd, osd服务则用从monitor得到的临时密钥解密ticket,验证其身份,然后从ticket取出session key, 因为客户端已经有session key, 这样双方就有了相同的session key,以后通讯时client和osd就用这个密钥加密和解密数据包,来验证数据的正确性。只要连接没有断开,session key就保持不变。

 

cephx认证具体步骤如下:

monclient和monitor的会话:

 

Step 1:

monclient: 发送 { protocol: 0, entity name, global id: 0 }

monintor: 保存entity name, 生成并保存64bit server challenge,

并把 server challenge 发送给对方。

 

Step 2:

monclient: 生成一个64bit client challenge, 用本地盘上的密钥把server challenge和client challenge加密后,再用64比特为单位混淆生成一个64bit key, 并发送请求:

{ CEPHX_GET_AUTH_SESSION_KEY, client challenge, key, old ticket }

注意(第一次连接开始old ticket为无效数据)

 

monitor 接收到CEPHX_GET_AUTH_SESSION_KEY请求, 把得到的client challenge和存在自己内存里的server challenge用client对应的key加密后混淆生成一个64bit key, 并与传过来的key比较,如果不相等,则认证不通过。 (注意,monitor在自身数据库存有对方的key) ,解密传过来的old ticket, 得到 CephXServiceTicketInfo结构。从密钥库取出client对应的身份信息(密钥,权限)。 生成新的ticket: (创建的时间,存活时间,global id, auid) ,生成与本monserver对话的session key, 从keystore获取对应于AUTH service 的临时密钥rotating key(secret 密钥, secret id密钥id).

 生成CephXServiceTicket结构(session key, ticket的存活时间), 用client在密钥库中的密钥加密。生成 CephXTicketBlob, 其中包含临时密钥secret id 和 CephXServiceTicketInfo, 而CephxServiceTicketInfo包含 : (session key, ticket, 权限),其中CephxServiceTicketInfo用对应的临时密钥secret加密。注意Client不在乎ticket是什么内容,因为这个作为一张票子是给通讯对方的,自己并不需要解释什么。如果上次成功解密 old ticket info,则使用old tick info中的session key加密整个CephXTicketBlob结构。

 

把经过上述处理后的CephxServiceTicket和CephxTicketBlob一起发送给monclient。

 

Step 3:

monclient 用自身本地盘上的密钥解密 CephxServciceTicket,在获得CephxTicketBlob时,如果CephxTicketBlob是经过加密的,则用客户端当前的session key解密CephxTicketBlob。

保存CephxServiceTicket中的session key为最新的session key,保存CephXServiceTicket中session key的存活时间。

lient 如果需要其他服务的密钥,则发起CEPHX_GET_PRINCIPAL_SESSION_KEY请求。

 首先生成内容HEADER, 包括(global id, service id, CephxServiceTicketBlob),其中service id就是AUTH认证服务的id,然后生成CephXServiceTicketRequest结构, 内容包括bitmask,每一位代表一种服务类型,例如位掩码中可以包含OSD, MDS。

生成CephXAuthorize结构, 内容包含随机数nonc,并用session key 加密CephxAuthorize.

 

monclient发送:Header 、 CephxAuthorize 、 CephxServiceTicketRequest。

 

Monitor读取Header, CephxServiceTickBlob,用CephxServiceTicketBlob中指定的secret id,从内存中获得临时密钥secret,用secret解密CephxServiceTicketBlob, 获得CephXServiceTicketInfo, 检验Header中的global id是否和CephxServiceTickeInfo中的global id相同,不相同就失败。

用CephxServiceTicketInfo中的session key解密CephxAuthorize.

生成CephXAuthorizeReply , 内容包含CephxAuthoriz的nonce +1.

解码 CephxServiceTicketRequest, 对其中的bitmask对应的每一种service,过程如下:

 

生成与该服务对话的session key

从keystore获取对应于该service的临时密钥(secret, secret id).

生成 CephXServiceTicket(session key, ticket的存活时间),

用刚才解密的CephxServiceTicketInfo中的session key加密之。

 

生成 CephXTicketBlob, 其中包含 (secret id 和 CephXServiceTicketInfo)

而CephXServiceTicketInfo代表代表一张票子(ticket), 其中包含 : (刚才生成的与该service对话的session key, ticket, 权限),其中CephxServiceTicketInfo用服务对应的临时密钥secret加密. ticket继承了step 2中的大部分内容,但是权限项目是对应的service中该client的权限。使用解密的CephxServiceTickt中的session key加密整个CephXTicketBlob.

把经过上述处理后的CephxServiceTicket和CephxTicketBlob一起发送给client.

 

monclient:对每一种service服务,过程如下:

用与monitor对话的session key解密CephxServciceTicket,如果CephxTicketBlob时经过密钥

加密的,则用这个session key解密CephxTicketBlob。保存CephxServiceTicket中的session key为最新的session key,保存CephXServiceTicket中session key的存活时间。

client 与 osd会话的建立:

ceph 使用消息通讯机制,其中messenger模块负责通讯,以simple messenger为例:

起实现通讯的代码位于src/msg/simple/Pipe.cc中,例如当发起一个连接时,Pipe::connect被调用,执行开始就区获得一个认证信息:




get_authorizer最终会执行到Client的代码中:

而build_authorizer最后会执行到CephxTicketManager中,该代码取出对应于某service的认证处理代码:

 

而该处理程序则提供认证信息:


我们看到它主要是打包global_id, service id 以及ticket和一个随机数,然后用session key加密。

以上时连接方发起的,下面看接收连接方时如何工作的:
接收连接方的入口在src/msg/simple/Pipe.cc的accept()函数:




而vierfy_authorizer函数最终会执行到:

我们看到这个函数最终获得对方的caps_info也即权限信息,对方的名称,对方的全局id, 对方的session_key,以及uid.




而cephx_verify_authorizer做了什么? 它用get_service_secret(service_id, ticket.secret_id, service_secret)得到临时密钥,然后decode_decrypt_enc_bl(cct, ticket_info, service_secret, ticket.blob, error)把票子解密。检验票子中的global id是否和明文发送过来的global id相同,不相同就会返回失败。

最后它做一些nonce的解密,这不太重要,没有什么信息量。


双方握手成功后,都会创建一个消息处理器,主要起到数据报的加密和检验。


以后双方发送数据都用sign_message签名:



而当前cephx 的sign_message依赖crc数据,只使用头尾几个crc字段来计算签名:


而接收数据方调用check_message_signature来验证签名:





网站要不要部署SSL加密? 生活在这个互联网时代,我们每天的衣食住行几乎都离不开互联网,网上购物、点餐、网约车......尤其是近些年来互联网行业的迅猛发展,网络用户的数量呈现激增态势,互联网更是渗透进了我们生活的方方面面。在我们享受着互联网带来的各种便利的同时,使用中的各种潜在的风险和隐患也在不断的增多,用户数据信息的保护也已经成为刻不容缓的问题。
如何ssl双向证书认证? 随着如今社会会的发展迅速越来越多的人选择在互联网上。进行信息的传输以及网络购物等,我们用户个人的信息以及IP地址等都会有一定的程度泄露。而现在针对这一现象,SSL证书便因此而生。而用户想要使用SSL证书的话,就必须要进行SSL双向证书认证。
请确定 SAML 授权是安全和私有的,你需要在你的应用程序中设置SSL/TLS。 请参考in the application. See Running Confluence Over SSL or HTTPS 页面中的内容。