Skip to content

RabbitMQ 集群 TLS 加密

一、概述

TLS(Transport Layer Security)加密是保护 RabbitMQ 集群通信安全的关键措施。通过 TLS 可以加密客户端连接、节点间通信和管理界面访问,防止数据泄露和中间人攻击。

TLS 加密架构

mermaid
graph TB
    subgraph "TLS 加密通信"
        C[客户端] -->|TLS| LB[负载均衡]
        LB -->|TLS| N1[节点1]
        LB -->|TLS| N2[节点2]
        N1 <-->|TLS| N2
        N1 -->|TLS| M[管理界面]
    end
    
    subgraph "证书链"
        CA[根证书 CA]
        CA --> S1[服务器证书]
        CA --> S2[客户端证书]
    end

二、核心知识点

2.1 TLS 加密范围

加密类型端口说明
AMQPS5671客户端 TLS 连接
HTTPS15671管理界面 TLS
集群 TLS25671节点间 TLS 通信
MQTT TLS8883MQTT TLS 连接

2.2 证书类型

证书类型说明用途
CA 证书根证书签发其他证书
服务器证书服务器身份服务端 TLS
客户端证书客户端身份客户端认证

2.3 TLS 配置参数

参数说明
cacertfileCA 证书文件
certfile服务器证书文件
keyfile私钥文件
verify验证模式
fail_if_no_peer_cert无证书是否拒绝

三、配置示例

3.1 生成证书

bash
# 创建 CA
openssl genrsa -out ca.key 2048
openssl req -x509 -new -nodes -key ca.key -sha256 -days 3650 -out ca.crt

# 创建服务器证书
openssl genrsa -out server.key 2048
openssl req -new -key server.key -out server.csr
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial \
    -out server.crt -days 365 -sha256 \
    -extfile <(echo "subjectAltName=DNS:rabbitmq-node1,DNS:rabbitmq-node2,DNS:rabbitmq-node3")

# 创建客户端证书
openssl genrsa -out client.key 2048
openssl req -new -key client.key -out client.csr
openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial \
    -out client.crt -days 365 -sha256

3.2 RabbitMQ TLS 配置

ini
# /etc/rabbitmq/rabbitmq.conf

# AMQP TLS 配置
listeners.ssl.default = 5671
ssl_options.cacertfile = /etc/rabbitmq/ssl/ca.crt
ssl_options.certfile = /etc/rabbitmq/ssl/server.crt
ssl_options.keyfile = /etc/rabbitmq/ssl/server.key
ssl_options.verify = verify_peer
ssl_options.fail_if_no_peer_cert = false
ssl_options.honor_cipher_order = true
ssl_options.honor_ecc_order = true
ssl_options.versions.1 = tlsv1.3
ssl_options.versions.2 = tlsv1.2

# 管理界面 TLS
management.ssl.port = 15671
management.ssl.cacertfile = /etc/rabbitmq/ssl/ca.crt
management.ssl.certfile = /etc/rabbitmq/ssl/server.crt
management.ssl.keyfile = /etc/rabbitmq/ssl/server.key

# 集群间 TLS
distribution.listener.port_range.min = 25671
distribution.listener.port_range.max = 25671
distribution.ssl.cacertfile = /etc/rabbitmq/ssl/ca.crt
distribution.ssl.certfile = /etc/rabbitmq/ssl/server.crt
distribution.ssl.keyfile = /etc/rabbitmq/ssl/server.key

3.3 客户端证书认证

ini
# /etc/rabbitmq/rabbitmq.conf

# 启用客户端证书认证
auth_mechanisms.1 = EXTERNAL
ssl_cert_login_from = common_name

# 证书到用户的映射
ssl_cert_login_from = subject_alternative_name

3.4 PHP TLS 连接示例

php
<?php

class TLSConnectionManager
{
    private string $host;
    private int $port;
    private string $cacert;
    private string $cert;
    private string $key;
    
    public function __construct(
        string $host,
        int $port = 5671,
        string $cacert = '/path/to/ca.crt',
        string $cert = '/path/to/client.crt',
        string $key = '/path/to/client.key'
    ) {
        $this->host = $host;
        $this->port = $port;
        $this->cacert = $cacert;
        $this->cert = $cert;
        $this->key = $key;
    }
    
    public function createConnection()
    {
        $connection = new AMQPStreamConnection(
            $this->host,
            $this->port,
            'guest',
            'guest',
            '/',
            false,
            'AMQPLAIN',
            null,
            'en_US',
            3.0,
            3.0,
            null,
            true,
            $this->cacert,
            $this->cert,
            $this->key
        );
        
        return $connection;
    }
    
    public function testConnection(): array
    {
        try {
            $connection = $this->createConnection();
            $channel = $connection->channel();
            
            $result = [
                'status' => 'success',
                'server_info' => $connection->getServerProperties(),
            ];
            
            $channel->close();
            $connection->close();
            
            return $result;
        } catch (Exception $e) {
            return [
                'status' => 'failed',
                'error' => $e->getMessage(),
            ];
        }
    }
    
    public function verifyCertificates(): array
    {
        $results = [];
        
        foreach ([$this->cacert, $this->cert, $this->key] as $file) {
            $results[$file] = [
                'exists' => file_exists($file),
                'readable' => is_readable($file),
                'valid' => $this->validateCertificate($file),
            ];
        }
        
        return $results;
    }
    
    private function validateCertificate(string $file): bool
    {
        if (!file_exists($file)) {
            return false;
        }
        
        $ext = pathinfo($file, PATHINFO_EXTENSION);
        
        if (in_array($ext, ['crt', 'pem'])) {
            $result = openssl_x509_read(file_get_contents($file));
            return $result !== false;
        }
        
        if ($ext === 'key') {
            $result = openssl_pkey_get_private(file_get_contents($file));
            return $result !== false;
        }
        
        return true;
    }
}

$manager = new TLSConnectionManager(
    'rabbitmq.example.com',
    5671,
    '/etc/ssl/rabbitmq/ca.crt',
    '/etc/ssl/rabbitmq/client.crt',
    '/etc/ssl/rabbitmq/client.key'
);

$test = $manager->testConnection();
echo "连接测试: {$test['status']}\n";

$verify = $manager->verifyCertificates();
echo "\n证书验证:\n";
print_r($verify);

四、常见问题与解决方案

4.1 证书验证失败

问题: 客户端无法验证服务器证书

解决方案:

bash
# 检查证书链
openssl verify -CAfile ca.crt server.crt

# 检查证书内容
openssl x509 -in server.crt -text -noout

# 检查私钥匹配
openssl x509 -noout -modulus -in server.crt | openssl md5
openssl rsa -noout -modulus -in server.key | openssl md5

4.2 TLS 版本不兼容

问题: TLS 版本不匹配

解决方案:

ini
# 支持的 TLS 版本
ssl_options.versions.1 = tlsv1.3
ssl_options.versions.2 = tlsv1.2

五、最佳实践建议

5.1 证书管理

  1. 使用 CA: 使用受信任的 CA 签发证书
  2. 定期更新: 定期更新证书
  3. 安全存储: 安全存储私钥

5.2 配置建议

  1. 禁用弱加密: 禁用弱加密算法
  2. 证书验证: 启用双向证书验证
  3. 协议版本: 使用 TLS 1.2 或更高版本

六、相关链接