Amphorae 與 Octavia Worker 的安全通信實現


前言

在前面的章節中我們記錄了 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 中心為內容可以參考《使用 OpenSSL 自建 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.old
drwxr-xr-x 2 stack stack   20 Oct 26 12:51 newcerts
drwx------ 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 = foobar
ca_private_key = /etc/octavia/certs/private/cakey.pem
ca_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.pem
client_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.py

class 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 的語義是:

  1. 生成 Amphora 私鑰
  2. 生成 Amphora 證書簽名請求(CSR)
  3. 向 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 通信的步驟

  1. 創建 Amphora 的過程中 Octavia Worker 會首先生成 Amphora 的私鑰,並且向 CA 中心申請簽發 Amphora 證書(內含 Amphora 公鑰),此時 Amphora 的私鑰、證書都會准備好
  2. Octavia Worker 通過 Config Driver 將 Amphora 的私鑰、Amphora 的證書作為 user data 注入到 Amphora 虛擬機。
  3. Amphora 虛擬機上運行的 amphora-agent Web Server 啟動時 Flask app 就會加載 Amphora 的私鑰和證書,並啟用 HTTPS 通訊協議。
  4. Octavia Worker 的 AmphoraAPIClient 首次想 amphora-agent 發送請求時,首先會下載 Amphora 證書,然后與自己手上的 CA 根證書解密出 Amphora 的公鑰,然后再與 Amphora 的私鑰進行匹配。
  5. 若匹配成功,則建立 SSL 安全通信。

NOTE: 同樣的 Amphora 如果希望向 Octavia Worker 自動發起建立 SSL 通信,那么 Amphora 就需要拿着 Octavia Worker 的證書進行訪問。所以 Octavia 的證書也同樣會被注入到 Amphora。
在這里插入圖片描述

最后

本篇是《OpenStack Rocky Octavia 實現與分析》系列的第四篇,主要討論 Amphora 是如何與 Octavia Worker 建立雙向的 SSL 安全通信的問題。實話說,Octavia 在解決這個問題的時候並不那么清晰明了,從命名到代碼的實現都彌漫着混亂的氛圍,需要細細梳理才得以清晰。並且 Octavia 和 Amphora 能夠健康通信又是 LBaaS 功能正常運作的基礎,所以還是非常有必要掌握這一問題的。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM