安全配置

生产环境中,RabbitMQ 的安全配置至关重要,包括用户认证、权限控制和通信加密。

🎯 本章目标

  • 掌握 RabbitMQ 用户和权限管理
  • 学会配置 TLS/SSL 加密通信
  • 了解生产环境安全最佳实践

👤 用户管理

用户角色

角色权限说明
none无法登录管理界面
management查看自己的连接、队列
policymaker管理策略和参数
monitoring查看所有节点信息
administrator完全管理权限

用户操作命令

# 添加用户
rabbitmqctl add_user <username> <password>

# 删除用户
rabbitmqctl delete_user <username>

# 修改密码
rabbitmqctl change_password <username> <newpassword>

# 设置用户角色
rabbitmqctl set_user_tags <username> <role>
# 例如:rabbitmqctl set_user_tags admin administrator

# 列出所有用户
rabbitmqctl list_users

# 清除用户密码(禁用密码登录)
rabbitmqctl clear_password <username>

生产环境用户设置

# 1. 删除默认 guest 用户
rabbitmqctl delete_user guest

# 2. 创建管理员用户
rabbitmqctl add_user admin SecureP@ssw0rd!
rabbitmqctl set_user_tags admin administrator
rabbitmqctl set_permissions -p / admin ".*" ".*" ".*"

# 3. 创建应用用户(最小权限)
rabbitmqctl add_user order_service OrderSvc123
rabbitmqctl set_user_tags order_service none
rabbitmqctl set_permissions -p /order order_service "^order\." "^order\." "^order\."

# 4. 创建监控用户
rabbitmqctl add_user monitor MonitorP@ss
rabbitmqctl set_user_tags monitor monitoring
rabbitmqctl set_permissions -p / monitor "" "" ".*"

🔐 权限控制

权限模型

权限格式: configure, write, read
- configure: 创建/删除队列、交换机的权限
- write: 发布消息的权限
- read: 消费消息、绑定队列的权限

正则表达式匹配资源名称
".*" = 所有资源
"^order\." = 以 order. 开头的资源
"" = 无权限

权限配置示例

# 完全权限
rabbitmqctl set_permissions -p / admin ".*" ".*" ".*"

# 只读权限(只能消费,不能发布或创建)
rabbitmqctl set_permissions -p / reader "" "" ".*"

# 只写权限(只能发布,不能消费)
rabbitmqctl set_permissions -p / writer "" ".*" ""

# 特定队列权限
rabbitmqctl set_permissions -p / order_service \
  "^order\." "^order\." "^order\."

# 查看权限
rabbitmqctl list_permissions -p /

# 查看用户权限
rabbitmqctl list_user_permissions admin

# 清除权限
rabbitmqctl clear_permissions -p / <username>

虚拟主机隔离

# 创建虚拟主机
rabbitmqctl add_vhost /production
rabbitmqctl add_vhost /staging
rabbitmqctl add_vhost /development

# 为不同环境设置权限
rabbitmqctl set_permissions -p /production prod_user ".*" ".*" ".*"
rabbitmqctl set_permissions -p /staging stage_user ".*" ".*" ".*"

# 删除虚拟主机
rabbitmqctl delete_vhost /development

# 列出虚拟主机
rabbitmqctl list_vhosts

🔒 TLS/SSL 加密

生成证书

# 1. 创建 CA 证书
mkdir -p /etc/rabbitmq/ssl
cd /etc/rabbitmq/ssl

# 生成 CA 私钥
openssl genrsa -out ca.key 4096

# 生成 CA 证书
openssl req -x509 -new -nodes -key ca.key -sha256 -days 3650 \
  -out ca.crt -subj "/CN=RabbitMQ-CA"

# 2. 生成服务器证书
openssl genrsa -out server.key 2048

# 生成证书签名请求
openssl req -new -key server.key -out server.csr \
  -subj "/CN=rabbitmq.example.com"

# 用 CA 签名
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key \
  -CAcreateserial -out server.crt -days 365 -sha256

# 3. 生成客户端证书(可选,用于双向认证)
openssl genrsa -out client.key 2048
openssl req -new -key client.key -out client.csr \
  -subj "/CN=rabbitmq-client"
openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key \
  -CAcreateserial -out client.crt -days 365 -sha256

# 设置权限
chown -R rabbitmq:rabbitmq /etc/rabbitmq/ssl
chmod 400 /etc/rabbitmq/ssl/*.key
chmod 444 /etc/rabbitmq/ssl/*.crt

RabbitMQ TLS 配置

%% /etc/rabbitmq/rabbitmq.conf

# 禁用非 TLS 端口(可选)
# listeners.tcp = none

# 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 = true

# TLS 版本(只允许 TLS 1.2+ssl_options.versions.1 = tlsv1.2
ssl_options.versions.2 = tlsv1.3

# 加密套件
ssl_options.ciphers.1 = TLS_AES_256_GCM_SHA384
ssl_options.ciphers.2 = TLS_CHACHA20_POLY1305_SHA256
ssl_options.ciphers.3 = ECDHE-RSA-AES256-GCM-SHA384

# 管理界面 HTTPS
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

Java 客户端 TLS 配置

package com.example.rabbitmq.config;

import com.rabbitmq.client.ConnectionFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
import java.io.FileInputStream;
import java.security.KeyStore;

@Configuration
public class RabbitMQTlsConfig {
    
    @Bean
    public ConnectionFactory connectionFactory() throws Exception {
        ConnectionFactory factory = new ConnectionFactory();
        factory.setHost("rabbitmq.example.com");
        factory.setPort(5671);  // TLS 端口
        factory.setUsername("admin");
        factory.setPassword("password");
        
        // 配置 TLS
        factory.useSslProtocol(createSSLContext());
        
        // 验证主机名
        factory.enableHostnameVerification();
        
        return factory;
    }
    
    private SSLContext createSSLContext() throws Exception {
        // 加载信任库(CA 证书)
        KeyStore trustStore = KeyStore.getInstance("PKCS12");
        try (FileInputStream fis = new FileInputStream("/path/to/truststore.p12")) {
            trustStore.load(fis, "truststorePassword".toCharArray());
        }
        
        TrustManagerFactory tmf = TrustManagerFactory.getInstance(
                TrustManagerFactory.getDefaultAlgorithm()
        );
        tmf.init(trustStore);
        
        // 加载密钥库(客户端证书,双向认证时需要)
        KeyStore keyStore = KeyStore.getInstance("PKCS12");
        try (FileInputStream fis = new FileInputStream("/path/to/keystore.p12")) {
            keyStore.load(fis, "keystorePassword".toCharArray());
        }
        
        KeyManagerFactory kmf = KeyManagerFactory.getInstance(
                KeyManagerFactory.getDefaultAlgorithm()
        );
        kmf.init(keyStore, "keyPassword".toCharArray());
        
        // 创建 SSLContext
        SSLContext sslContext = SSLContext.getInstance("TLSv1.2");
        sslContext.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
        
        return sslContext;
    }
}

Spring Boot TLS 配置

spring:
  rabbitmq:
    host: rabbitmq.example.com
    port: 5671
    username: admin
    password: password
    ssl:
      enabled: true
      key-store: classpath:client.p12
      key-store-password: keystorePassword
      key-store-type: PKCS12
      trust-store: classpath:truststore.p12
      trust-store-password: truststorePassword
      trust-store-type: PKCS12
      verify-hostname: true

🛡️ 安全最佳实践

1. 网络安全

# 使用防火墙限制访问
# 只允许应用服务器访问 RabbitMQ

# iptables 示例
iptables -A INPUT -p tcp -s 10.0.0.0/24 --dport 5672 -j ACCEPT
iptables -A INPUT -p tcp -s 10.0.0.0/24 --dport 5671 -j ACCEPT
iptables -A INPUT -p tcp --dport 5672 -j DROP
iptables -A INPUT -p tcp --dport 5671 -j DROP

# 限制管理界面访问
iptables -A INPUT -p tcp -s 10.0.0.100 --dport 15672 -j ACCEPT
iptables -A INPUT -p tcp --dport 15672 -j DROP

2. 配置文件安全

%% rabbitmq.conf

# 禁用 guest 用户远程访问(默认已禁用)
loopback_users.guest = true

# 禁用未加密连接
listeners.tcp = none

# 只监听内部网络
listeners.ssl.default = 5671
listeners.ssl.local = 127.0.0.1:5671

# 设置连接超时
heartbeat = 60
connection_max = 1000

# 限制帧大小
frame_max = 131072

3. 审计日志

%% rabbitmq.conf

# 启用详细日志
log.file.level = info
log.console.level = warning

# 配置日志文件
log.file = /var/log/rabbitmq/rabbit.log
log.file.rotation.date = $D0
log.file.rotation.count = 7

4. 密码策略

// 使用强密码
public class PasswordValidator {
    
    public static boolean isStrong(String password) {
        // 至少 12 位
        if (password.length() < 12) return false;
        
        // 包含大小写、数字、特殊字符
        boolean hasUpper = password.matches(".*[A-Z].*");
        boolean hasLower = password.matches(".*[a-z].*");
        boolean hasDigit = password.matches(".*\\d.*");
        boolean hasSpecial = password.matches(".*[!@#$%^&*(),.?\":{}|<>].*");
        
        return hasUpper && hasLower && hasDigit && hasSpecial;
    }
}

5. 定期安全检查

#!/bin/bash
# security-check.sh

echo "=== RabbitMQ 安全检查 ==="

# 检查 guest 用户是否存在
if rabbitmqctl list_users | grep -q "guest"; then
    echo "⚠️  警告: guest 用户仍然存在"
fi

# 检查非 TLS 连接
if netstat -tlnp | grep -q ":5672 "; then
    echo "⚠️  警告: 非加密端口 5672 开放"
fi

# 检查用户权限
echo "📋 用户权限列表:"
rabbitmqctl list_permissions -p /

# 检查连接
echo "📋 当前连接:"
rabbitmqctl list_connections user peer_host peer_port ssl

🔑 外部认证

LDAP 认证

%% rabbitmq.conf

# 启用 LDAP 认证
auth_backends.1 = ldap

# LDAP 服务器配置
auth_ldap.servers.1 = ldap.example.com
auth_ldap.port = 389
auth_ldap.use_ssl = false

# 用户 DN 模式
auth_ldap.user_dn_pattern = cn=${username},ou=users,dc=example,dc=com

# 日志级别
auth_ldap.log = true

OAuth 2.0 认证

%% rabbitmq.conf

# 启用 OAuth 2.0
auth_backends.1 = rabbit_auth_backend_oauth2

# OAuth 配置
auth_oauth2.resource_server_id = rabbitmq
auth_oauth2.additional_scopes_key = scope

📝 本章小结

安全领域措施
用户管理删除 guest,创建最小权限用户
权限控制使用正则限制资源访问
网络隔离虚拟主机隔离,防火墙限制
通信加密TLS 1.2+,禁用非加密连接
审计日志启用详细日志,定期检查
密码策略强密码,定期更换

安全检查清单

  • [ ] 删除默认 guest 用户
  • [ ] 创建专用应用用户
  • [ ] 配置最小权限
  • [ ] 启用 TLS 加密
  • [ ] 禁用非加密端口
  • [ ] 配置防火墙规则
  • [ ] 启用审计日志
  • [ ] 定期检查和更新

下一步

安全配置完成后,让我们学习 Federation & Shovel 实现跨数据中心复制!