ceph key的创建

ceph中提供了cephx认证机制,客户端到服务端的访问,服务段之间的互访等都提供了认证过程,当然这些都是可配的。本文主要介绍ceph中key的常见过程。
ceph中有两个要弄清的概念:
key和keyring: key标识一个密钥,一串字符;keyring用来存放密钥,也可以理解为一个文件。

创建keyring的过程:

下面这部分代码,从ceph_osd.cc的main方法中提取的。

  if (mkkey) {
    common_init_finish(g_ceph_context);
    //创建KeyRing实例
    KeyRing *keyring = KeyRing::create_empty();
    if (!keyring) {
      derr << "Unable to get a Ceph keyring." << dendl;
      return 1;
    } 

    EntityName ename(g_conf->name);
    EntityAuth eauth;
    //从keyring文件中加载KeyRing信息
    int ret = keyring->load(g_ceph_context, g_conf->keyring);
    if (ret == 0 &&
        keyring->get_auth(ename, eauth)) {
      derr << "already have key in keyring " << g_conf->keyring << dendl;
    } else {
    //创建Key
      eauth.key.create(g_ceph_context, CEPH_CRYPTO_AES);
      keyring->add(ename, eauth);
      bufferlist bl; 
      //将KeyRing信息序列化到bl中(以普通文本的形式)
      keyring->encode_plaintext(bl);
      //保存到keyring文件中
      int r = bl.write_file(g_conf->keyring.c_str(), 0600);                                                                                                                                  
      if (r) 
        derr << TEXT_RED << " ** ERROR: writing new keyring to " << g_conf->keyring
             << ": " << cpp_strerror(r) << TEXT_NORMAL << dendl;
      else
        derr << "created new key in keyring " << g_conf->keyring << dendl;
    } 
  }

这段代码主要实现创建key的过程,首先它试图从给定的keyring文件中去加载,如果没有再去创建,创建成功之后,又以普通文本的形式保持到keyring文件中。

其中涉及的一些抽象结构:

1.KeyRing继承与KeyStore,KeyRing类中包含一个keys(map < EntityName, EntityAuth >)属性。
2.EntityAuth中包含auid(uint64_t)key(CryptoKey) caps(map< string, bufferlist >)
3.CryptoKey中有type(__u16) created(utime_t) secret(bufferptr) ckh(mutable ceph::shared_ptr < CryptoKeyHandler >)
4.CryptoAES 继承于CryptoHandler

创建Key的过程实现

加载keyring

从keyring文件中读取信息,然后反序列化到KeyRing实例中。

int KeyRing::load(CephContext *cct, const std::string &filename)
{
  if (filename.empty())
  ¦ return -EINVAL;

  bufferlist bl;
  std::string err;
  //从keyring文件中读取key
  int ret = bl.read_file(filename.c_str(), &err);
  if (ret < 0) {
  ¦ lderr(cct) << "error reading file: " << filename << ": " << err << dendl;
  ¦ return ret;
  }
//将读取到的信息,反序列化到keys中
  try {
  ¦ bufferlist::iterator iter = bl.begin();
  ¦ decode(iter);
  }
  catch (const buffer::error& err) {
  ¦ lderr(cct) << "error parsing file " << filename << dendl;
  ¦ return -EIO;
  }

  ldout(cct, 2) << "KeyRing::load: loaded key file " << filename << dendl;
  return 0;
}
void KeyRing::decode(bufferlist::iterator& bl) {                                                                                                                  
  __u8 struct_v;                                                                                                                                                  
  bufferlist::iterator start_pos = bl;                                                                                                                            
  try {                                                                                                                                                           
  ¦ ::decode(struct_v, bl);                                                                                                                                                                  
  ¦ ::decode(keys, bl);                                                                                                                                           
  } catch (buffer::error& err) {                                                                                                                                  
  ¦ keys.clear();                                                                                                                                                 
  ¦ decode_plaintext(start_pos);                                                                                                                                  
  }                                                                                                                                                               
}

上面如果发现keyring中没有,或者加载失败,则进入创建新key的过程。

创建key
int CryptoKey::create(CephContext *cct, int t)                                                                                                                                               
{                                                                                                                                                                 
  CryptoHandler *ch = CryptoHandler::create(t);                                                                                                                   
  if (!ch) {                                                                                                                                                      
  ¦ if (cct)                                                                                                                                                      
  ¦ ¦ lderr(cct) << "ERROR: cct->get_crypto_handler(type=" << t << ") returned NULL" << dendl;                                                                    
  ¦ return -EOPNOTSUPP;                                                                                                                                           
  }                                                                                                                                                               
  bufferptr s;                                                                                                                                                    
  int r = ch->create(s);                                                                                                                                          
  delete ch;                                                                                                                                                      
  if (r < 0)                                                                                                                                                      
  ¦ return r;                                                                                                                                                     

  r = _set_secret(t, s);                                                                                                                                          
  if (r < 0)                                                                                                                                                      
  ¦ return r;                                                                                                                                                     
  created = ceph_clock_now();                                                                                                                                     
  return r;                                                                                                                                                       
}

该法方法中创建了CryptoHandler来完成key的创建,深入到create方法中会发现该方法返回的是CryptoHandler的子类,由它来创建key。
创建CryptoAES实例。

CryptoHandler *CryptoHandler::create(int type)                                                                                                                    
{                                                                                                                                                                 
  switch (type) {                                                                                                                                                 
  case CEPH_CRYPTO_NONE:                                                                                                                                          
  ¦ return new CryptoNone;                                                                                                                                        
  case CEPH_CRYPTO_AES:                                                                                                                                           
  ¦ return new CryptoAES;                                                                                                                                         
  default:                                                                                                                                                        
  ¦ return NULL;                                                                                                                                                                             
  }                                                                                                                                                               
}
创建一串字符来作为key
int CryptoAES::create(bufferptr& secret)                                                                                                                          
{                                                                                                                                                                 
  bufferlist bl;                                                                                                                                                                             
  int r = get_random_bytes(AES_KEY_LEN, bl);                                                                                                                      
  if (r < 0)                                                                                                                                                      
  ¦ return r;                                                                                                                                                     
  secret = buffer::ptr(bl.c_str(), bl.length());                                                                                                                  
  return 0;                                                                                                                                                       
} 

int get_random_bytes(char *buf, int len)
{
  int fd = TEMP_FAILURE_RETRY(::open("/dev/urandom", O_RDONLY));
  if (fd < 0)
    return -errno;
  int ret = safe_read_exact(fd, buf, len);
  VOID_TEMP_FAILURE_RETRY(::close(fd));
  return ret;
}

由以上代码可以知道key是由linux系统的/dev/urandom,随机生成。

设置key
int CryptoKey::_set_secret(int t, const bufferptr& s)                                                                                                             
{                                                                                                                                                                 
  if (s.length() == 0) {                                                                                                                                          
  ¦ secret = s;                                                                                                                                                   
  ¦ ckh.reset();                                                                                                                                                  
  ¦ return 0;                                                                                                                                                     
  }                                                                                                                                                               

  CryptoHandler *ch = CryptoHandler::create(t);                                                                                                                   
  if (ch) {                                                                                                                                                       
  ¦ int ret = ch->validate_secret(s);                                                                                                                             
  ¦ if (ret < 0) {                                                                                                                                                
  ¦ ¦ delete ch;                                                                                                                                                  
  ¦ ¦ return ret;                                                                                                                                                 
  ¦ }                                                                                                                                                             
  ¦ string error;                                                                                                                                                 
  ¦ ckh.reset(ch->get_key_handler(s, error));                                                                                                                     
  ¦ delete ch;                                                                                                                                                    
  ¦ if (error.length()) {                                                                                                                                         
  ¦ ¦ return -EIO;                                                                                                                                                
  ¦ }                                                                                                                                                             
  } else {                                                                                                                                                        
  ¦ ¦ return -EOPNOTSUPP;                                                                                                                                         
  }                                                                                                                                                               
  type = t;                                                                                                                                                       
  secret = s;                                                                                                                                                     
  return 0;                                                                                                                                                       
}

验证key的长度,创建CryptoAESKeyHandler,并生成对secret加密后的字符串。

int CryptoAES::validate_secret(const bufferptr& secret)
{
  if (secret.length() < (size_t)AES_KEY_LEN) {
  ¦ return -EINVAL;
  }

  return 0;
} 

CryptoKeyHandler *CryptoAES::get_key_handler(const bufferptr& secret,                                                                                             
                                             string& error)                                                                                                       
{                                                                                                                                                                 
  CryptoAESKeyHandler *ckh = new CryptoAESKeyHandler;                                                                                                             
  ostringstream oss;                                                                                                                                              
  if (ckh->init(secret, oss) < 0) {                                                                                                                               
  ¦ error = oss.str();                                                                                                                                            
  ¦ delete ckh;                                                                                                                                                   
  ¦ return NULL;                                                                                                                                                  
  }                                                                                                                                                               
  return ckh;                                                                                                                                                     
}

创建secret的加密后的key。

  int CryptoAESKeyHandler::init(const bufferptr& s, ostringstream& err) {                                                                                                                                         
  ¦ secret = s;                                                                                                                                                   

  ¦ enc_key = new CryptoPP::AES::Encryption(                                                                                                                      
  ¦ ¦ (byte*)secret.c_str(), CryptoPP::AES::DEFAULT_KEYLENGTH);                                                                                                   
  ¦ dec_key = new CryptoPP::AES::Decryption(                                                                                                                      
  ¦ ¦ (byte*)secret.c_str(), CryptoPP::AES::DEFAULT_KEYLENGTH);                                                                                                   

  ¦ return 0;                                                                                                                                                     
  }

到这里key就创建完成了,下面是将内存中的key导入的文件中(普通文本形式)。

将内存中的key序列化之后导出到keyring中

//将KeyRing实例中的信息,以普通文本的形式写入到bl中。
void KeyRing::encode_plaintext(bufferlist& bl)                                                                                                                    
{                                                                                                                                                                 
  std::ostringstream os;                                                                                                                                                                     
  print(os);                                                                                                                                                      
  string str = os.str();                                                                                                                                          
  bl.append(str);                                                                                                                                                 
}  
//将KeyRing实例中的信息,输出到out流中。
void KeyRing::print(ostream& out)                                                                                                                                 
{                                                                                                                                                                 
  for (map<EntityName, EntityAuth>::iterator p = keys.begin();                                                                                                                               
  ¦ ¦ ¦p != keys.end();                                                                                                                                           
  ¦ ¦ ¦++p) {                                                                                                                                                     
  ¦ out << "[" << p->first << "]" << std::endl;                                                                                                                   
  ¦ out << "\tkey = " << p->second.key << std::endl;                                                                                                              
  ¦ if (p->second.auid != CEPH_AUTH_UID_DEFAULT)                                                                                                                  
  ¦ ¦ out << "\tauid = " << p->second.auid << std::endl;                                                                                                          

  ¦ for (map<string, bufferlist>::iterator q = p->second.caps.begin();                                                                                            
        ¦q != p->second.caps.end();                                                                                                                               
        ¦++q) {                                                                                                                                                   
  ¦ ¦ bufferlist::iterator dataiter = q->second.begin();                                                                                                          
  ¦ ¦ string caps;                                                                                                                                                
  ¦ ¦ ::decode(caps, dataiter);                                                                                                                                   
  ¦ ¦ out << "\tcaps " << q->first << " = \"" << caps << '"' << std::endl;                                                                                        
  ¦ }                                                                                                                                                             
  }                                                                                                                                                               
}

这个方法就导出了平常在keyring文件中看到的key的形式。

创建 CephFS 并使用它,需要遵循以下步骤: 1. 确保在 Ceph 集群中已启用 CephFS 功能。在 ceph.conf 文件中,确保以下配置项已设置为“true”: ``` [global] fsid = <your fsid> mon_initial_members = <your mon node names> mon_host = <your mon node IP addresses> auth_cluster_required = cephx auth_service_required = cephx auth_client_required = cephx [client] keyring = /etc/ceph/<your ceph client keyring> ``` 2. 在 Ceph 集群中创建一个 MDS(元数据服务器)节点。这个节点将处理文件系统的元数据。可以使用以下命令创建 MDS 节点: ``` ceph-deploy mds create <mds node names> ``` 3. 创建 CephFS 文件系统。可以使用以下命令创建文件系统: ``` ceph fs new <fs name> <metadata pool name> <data pool name> ``` 其中,“fs name”是文件系统的名称,“metadata pool name”是用于存储文件系统元数据的池的名称,“data pool name”是用于存储文件数据的池的名称。 4. 挂载 CephFS 文件系统。可以使用以下命令将文件系统挂载到本地目录: ``` mount -t ceph <mon node>:<path> <mount point> -o name=<client name>,secret=<client key> ``` 其中,“mon node”是监视器节点的名称或 IP 地址,“path”是文件系统的路径,“mount point”是本地目录的路径,“client name”是用于访问文件系统的客户端名称,“client key”是用于访问文件系统的客户端密钥。 完成以上步骤后,就可以使用 CephFS 文件系统了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值