ceph key的创建

来源:互联网 发布:淘宝试衣服软件 编辑:程序博客网 时间:2024/06/07 22:27

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的形式。

原创粉丝点击