当前位置: 首页 > 工具软件 > Nova > 使用案例 >

【Nova】nova-cert学习

席俊驰
2023-12-01

nova-cert顾名思义,是与证书有关的服务,用于为上传镜像生成X509证书,只在EC2 API中才会被用到。

nova-cert作为rpc server运行,对外提供证书有关的RpcAPI,作用和CA类似。


由于对PKI了解的不是太多,因此下面可能有错漏,还望斧正

1.在服务开始运行之前,需要判断ca证书是否存在,不存在就需要使用openssl创建自己的ca证书和私钥,这些文件通常存放在配置项state_path下的CA目录里

def ensure_ca_filesystem():

    # 确认CA目录的路径, 即配置项$state_path/CA
    ca_dir = ca_folder()
    # 如果CA证书不存在
    if not os.path.exists(ca_path()):
        # 确认genrootca.sh脚本的所在
        genrootca_sh_path = os.path.abspath(
                os.path.join(os.path.dirname(__file__), 'CA', 'genrootca.sh'))

        start = os.getcwd()
        # 创建CA目录
        fileutils.ensure_tree(ca_dir)
        # 切换工作目录至CA目录
        os.chdir(ca_dir)
        # 通过sh执行genrootca.sh脚本来生成CA证书和私钥
        utils.execute("sh", genrootca_sh_path)
        # 恢复原来的工作目录
        os.chdir(start)

class CertManager(manager.Manager):

    target = messaging.Target(version='2.0')

    def __init__(self, *args, **kwargs):
        super(CertManager, self).__init__(service_name='cert',
                                          *args, **kwargs)

    def init_host(self):
        # 服务启动之前, 需要保证CA证书、私钥以及存放它们和用户证书的目录存在
        crypto.ensure_ca_filesystem()
2.之后, 就可以通过generate_x509_cert RpcAPI来为自己生成签名证书了

def _sign_csr(csr_text, ca_folder):
    # 创建临时目录
    with utils.tempdir() as tmpdir:
        inbound = os.path.join(tmpdir, 'inbound.csr')
        outbound = os.path.join(tmpdir, 'outbound.csr')

        try:
            with open(inbound, 'w') as csrfile:
                # 将证书请求写入inbound.csr临时文件
                csrfile.write(csr_text)
        except IOError:
            with excutils.save_and_reraise_exception():
                LOG.exception(_('Failed to write inbound.csr'))

        LOG.debug(_('Flags path: %s'), ca_folder)
        start = os.getcwd()

        # 确保CA目录存在, 然后切换工作目录到CA目录
        fileutils.ensure_tree(ca_folder)
        os.chdir(ca_folder)
        # 通过inbound.csr证书请求文件生成outbound.csr签名证书文件;
        # CA目录下的openssl.cnf是openssl的配置文件, 里面配置了新生成证书的存放目录, 默认是CA目录/newcerts;
        # 所以该命令在生成outbound.csr证书之余, 还会在CA目录/newcerts存放一个副本, 副本名为"序列号.pem";
        utils.execute('openssl', 'ca', '-batch', '-out', outbound, '-config',
                      './openssl.cnf', '-infiles', inbound)
        # 获取outbound.csr证书的序列号
        out, _err = utils.execute('openssl', 'x509', '-in', outbound,
                                  '-serial', '-noout')
        serial = string.strip(out.rpartition('=')[2])
        os.chdir(start)

        with open(outbound, 'r') as crtfile:
            # 返回序列号和证书内容
            return (serial, crtfile.read())

def sign_csr(csr_text, project_id=None):
    # 可以配置为每个project均有一个CA, 默认为False, 也即所有project共用一个CA;
    # 这里通过project_id来确定CA目录;
    # 最后通过_sign_csr方法生成自签名证书
    if not CONF.use_project_ca:
        project_id = None
    if not project_id:
        return _sign_csr(csr_text, ca_folder())
    _ensure_project_folder(project_id)
    project_folder = ca_folder(project_id)
    return _sign_csr(csr_text, ca_folder(project_id))


# 为项目中的用户生成签名证书
def generate_x509_cert(user_id, project_id, bits=1024):
    # 通过user_id,project_id来生成证书主题
    subject = _user_cert_subject(user_id, project_id)

    # 创建临时目录
    with utils.tempdir() as tmpdir:
        keyfile = os.path.abspath(os.path.join(tmpdir, 'temp.key'))
        csrfile = os.path.abspath(os.path.join(tmpdir, 'temp.csr'))
        # 调用openssl生成RSA私钥文件
        utils.execute('openssl', 'genrsa', '-out', keyfile, str(bits))
        # 调用openssl生成证书请求
        utils.execute('openssl', 'req', '-new', '-key', keyfile, '-out',
                      csrfile, '-batch', '-subj', subject)
        private_key = open(keyfile).read()
        csr = open(csrfile).read()

    # 通过证书请求来生成签名证书和序列号, project_id用于确认CA目录
    (serial, signed_csr) = sign_csr(csr, project_id)
    # 用于确定证书的存放路径
    fname = os.path.join(ca_folder(project_id), 'newcerts/%s.pem' % serial)
    cert = {'user_id': user_id,
            'project_id': project_id,
            'file_name': fname}
    # 将证书的相关信息譬如user_id、project_id和file_name等存入数据库
    db.certificate_create(context.get_admin_context(), cert)
    # 返回用户私钥和签名证书内容
    return (private_key, signed_csr)





 类似资料: