本文共 6640 字,大约阅读时间需要 22 分钟。
前言
在前面的章节中我们记录了 LoadBalancer、Listener、Pool、Member 等等 Octavia 核心资源对象的创建流程,本篇我们在此之上继续讨论处于 LB Management Network 上的 Amphorae 虚拟机是如何与处于 OpenStack Management Network 上的 Octavia Worker 进行安全通信的。
为什么 Octavia 需要自建 CA 证书?
首先我们提出一个问题:为什么 Octavia 需要自建 CA 而不使用 OpenStack 的通用认证体系?
答案是:For production use the ca issuing the client certificate and the ca issuing the server certificate need to be different so a hacker can’t just use the server certificate from a compromised amphora to control all the others.
简而言之,Octavia 自建 CA 证书主要有两个必要:
- amphora-agent 没有加入 OpenStack 鉴权体系,需要证书来保证通讯安全
- 防止恶意用户利用 amphora 作为 “肉鸡” 攻击 OpenStack 的内部网络
基于自建 CA 实现的 SSL 通信
Octavia 提供了自动化脚本通过 OpenSSL 指令来创建 CA 中心并自签发 CA 根证书。执行下述指令即可完成:
$ source /opt/rocky/octavia/bin/create_certificates.sh /etc/octavia/certs/ /opt/rocky/octavia/etc/certificates/openssl.cnf
NOTE:自签发即自己担保自己,用自己的私钥对自己的 CSR 进行签发。只有顶级认证角色才会自签发,所以也称为根证书,本质是签发服务器证书的公钥。
所谓 CA,在操作系统上的载体只是一个文件目录(Directory),包含了各类型秘钥的证书。CA 在信任系统中充当第三方信托机构的角色,提供证书签发和管理服务,可以有效解决非对称加密系统中常见的中间人攻击问题。更多关于 CA 中心为内容可以参考,这里不再赘述。
Octavia 自建的 CA 中心:
$ ll /etc/octavia/certs/total 44-rw-r--r-- 1 stack stack 1294 Oct 26 12:51 ca_01.pem-rw-r--r-- 1 stack stack 989 Oct 26 12:51 client.csr-rw-r--r-- 1 stack stack 1708 Oct 26 12:51 client.key-rw-r--r-- 1 stack stack 4405 Oct 26 12:51 client-.pem-rw-r--r-- 1 stack stack 6113 Oct 26 12:51 client.pem-rw-r--r-- 1 stack stack 71 Oct 26 12:51 index.txt-rw-r--r-- 1 stack stack 21 Oct 26 12:51 index.txt.attr-rw-r--r-- 1 stack stack 0 Oct 26 12:51 index.txt.olddrwxr-xr-x 2 stack stack 20 Oct 26 12:51 newcertsdrwx------ 2 stack stack 23 Oct 26 12:51 private-rw-r--r-- 1 stack stack 3 Oct 26 12:51 serial-rw-r--r-- 1 stack stack 3 Oct 26 12:51 serial.old
- newcerts dir:存放 CA 签署(颁发)过的数字证书
- private dir:存放 CA 的私钥
- serial file:存放证书序列号(e.g. 01),每新建一张证书,序列号会自动加 1
- index.txt file:存放证书信息
- ca_01.pem PEM file:CA 证书文件
- client.csr file:Server CSR 证书签名请求文件
- client.key file:Server 私钥文件
- client-.pem:PEM 编码的 Server 证书文件
- client.pem:结合了 client-.pem 和 client.key 的文件
列举 Octavia 与 CA 认证相关的配置项:
- 应用于 Create Amphora Flow 中的 TASK:GenerateServerPEMTask,生成 Amphora 私钥并签发 Amphora 证书。
[certificates]ca_private_key_passphrase = foobarca_private_key = /etc/octavia/certs/private/cakey.pemca_certificate = /etc/octavia/certs/ca_01.pem
- 应用于 Octavia Worker 的 AmphoraAPIClient,拿着 CA 根证书(是 Amphora 证书的公钥,可以解开 Amphora 证书得到 Amphora 的公钥)和 Amphora 证书向 amphora-agent 发起 SSL 通信。
[haproxy_amphora]server_ca = /etc/octavia/certs/ca_01.pemclient_cert = /etc/octavia/certs/client.pem
- 应用于 Task:CertComputeCreate,指定 CA 根证书的路径
[controller_worker]client_ca = /etc/octavia/certs/ca_01.pem
Amphora Agent 启动加载证书
首先看为 Amphorae 生成证书的代码实现:
# /opt/rocky/octavia/octavia/controller/worker/tasks/cert_task.pyclass GenerateServerPEMTask(BaseCertTask): """Create the server certs for the agent comm Use the amphora_id for the CN """ def execute(self, amphora_id): cert = self.cert_generator.generate_cert_key_pair( cn=amphora_id, validity=CERT_VALIDITY) return cert.certificate + cert.private_key
Octavia Certificates 功能模块提供了 local_cert_generator(default)
和 anchor_cert_generator
两种证书生成器,通过配置项 [certificates] cert_generator
选用。
# /opt/rocky/octavia/octavia/certificates/generator/local.py @classmethod def generate_cert_key_pair(cls, cn, validity, bit_length=2048, passphrase=None, **kwargs): pk = cls._generate_private_key(bit_length, passphrase) csr = cls._generate_csr(cn, pk, passphrase) cert = cls.sign_cert(csr, validity, **kwargs) cert_object = local_common.LocalCert( certificate=cert, private_key=pk, private_key_passphrase=passphrase ) return cert_object
上述 LocalCertGenerator.generate_cert_key_pair
Method 的语义是:
- 生成 Amphora 私钥
- 生成 Amphora 证书签名请求(CSR)
- 向 CA 中心申请签署 Amphora证书
属于常规的证书创建流程,与 create_certificates.sh 脚本的区别在于,Octavia Certificates 应用了 cryptography python 库而非 OpenSSL 来实现。
TASK:GenerateServerPEMTask 最终 return 了 Amphora 私钥和证书,然后实现 TASK:CertComputeCreate 将这些文件注入到 Amphora 虚拟机。登录 Amphora 即可查看这些文件,路径记录在配置文件中:
# /etc/octavia/amphora-agent.conf[amphora_agent]# Octavia Worker 的证书agent_server_ca = /etc/octavia/certs/client_ca.pem# Amphora 的私钥和证书agent_server_cert = /etc/octavia/certs/server.pem
Gunicorn HTTP Server 启动时就会将证书文件加载, 加载证书的 options 如下:
options = { 'bind': bind_ip_port, 'workers': 1, 'timeout': CONF.amphora_agent.agent_request_read_timeout, 'certfile': CONF.amphora_agent.agent_server_cert, 'ca_certs': CONF.amphora_agent.agent_server_ca, 'cert_reqs': True, 'preload_app': True, 'accesslog': '/var/log/amphora-agent.log', 'errorlog': '/var/log/amphora-agent.log', 'loglevel': 'debug', }
AmphoraAPIClient 发送证书请求
class AmphoraAPIClient(object): def __init__(self): super(AmphoraAPIClient, self).__init__() ... self.session = requests.Session() self.session.cert = CONF.haproxy_amphora.client_cert self.ssl_adapter = CustomHostNameCheckingAdapter() self.session.mount('https://', self.ssl_adapter) ... def request(self, method, amp, path='/', timeout_dict=None, **kwargs): ... LOG.debug("request url %s", path) _request = getattr(self.session, method.lower()) _url = self._base_url(amp.lb_network_ip) + path LOG.debug("request url %s", _url) reqargs = { 'verify': CONF.haproxy_amphora.server_ca, 'url': _url, 'timeout': (req_conn_timeout, req_read_timeout), } reqargs.update(kwargs) headers = reqargs.setdefault('headers', { }) ...
上述代码是 requests 库启用 HTTPS 请求的常规实现:
self.session.cert
:上传 Octavia Worker 私钥和证书,用于 Amphora 发起的 SSL 通信reqargs = {'verify': CONF.haproxy_amphora.server_ca, ...}
:携带 Amphora 证书,向 Amphora 发起 SSL 通信
小结
梳理 Octavia 建立 SSL 通信的步骤:
- 创建 Amphora 的过程中 Octavia Worker 会首先生成 Amphora 的私钥,并且向 CA 中心申请签发 Amphora 证书(内含 Amphora 公钥),此时 Amphora 的私钥、证书都会准备好
- Octavia Worker 通过 Config Driver 将 Amphora 的私钥、Amphora 的证书作为 user data 注入到 Amphora 虚拟机。
- Amphora 虚拟机上运行的 amphora-agent Web Server 启动时 Flask app 就会加载 Amphora 的私钥和证书,并启用 HTTPS 通讯协议。
- Octavia Worker 的 AmphoraAPIClient 首次想 amphora-agent 发送请求时,首先会下载 Amphora 证书,然后与自己手上的 CA 根证书解密出 Amphora 的公钥,然后再与 Amphora 的私钥进行匹配。
- 若匹配成功,则建立 SSL 安全通信。
NOTE: 同样的 Amphora 如果希望向 Octavia Worker 自动发起建立 SSL 通信,那么 Amphora 就需要拿着 Octavia Worker 的证书进行访问。所以 Octavia 的证书也同样会被注入到 Amphora。
最后
本篇是《OpenStack Rocky Octavia 实现与分析》系列的第四篇,主要讨论 Amphora 是如何与 Octavia Worker 建立双向的 SSL 安全通信的问题。实话说,Octavia 在解决这个问题的时候并不那么清晰明了,从命名到代码的实现都弥漫着混乱的氛围,需要细细梳理才得以清晰。并且 Octavia 和 Amphora 能够健康通信又是 LBaaS 功能正常运作的基础,所以还是非常有必要掌握这一问题的。
转载地址:https://is-cloud.blog.csdn.net/article/details/88770752 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!