Skip to content

RabbitMQ 用户管理

概述

RabbitMQ 用户管理是消息队列安全体系的基础。通过合理的用户管理,可以控制谁可以访问消息队列、能执行什么操作。本文档详细介绍 RabbitMQ 用户的创建、修改、删除以及用户标签(Tags)的使用方法。

核心知识点

用户体系架构

RabbitMQ 用户体系
├── 用户(User)
│   ├── 用户名(Username)
│   ├── 密码(Password)
│   └── 用户标签(Tags)
├── 权限(Permissions)
│   ├── 配置权限(Configure)
│   ├── 写权限(Write)
│   └── 读权限(Read)
└── 虚拟主机(Virtual Host)
    └── 用户权限绑定到 vhost

用户标签(Tags)

用户标签决定了用户在管理界面中的角色和可见性:

标签说明权限范围
administrator管理员完全管理权限,可管理用户、策略等
monitoring监控者可查看所有配置和统计信息
policymaker策略制定者可查看、创建、删除策略
management管理者可查看自己有权限的虚拟主机
impersonator模拟者可模拟其他用户(高级功能)
无标签普通用户只能通过 AMQP 访问,无法登录管理界面

默认用户

RabbitMQ 安装后默认创建:

用户名密码标签访问限制
guestguestadministrator默认仅允许本地访问

密码哈希算法

RabbitMQ 支持多种密码哈希算法:

算法安全性推荐度
SHA-256⭐⭐⭐⭐⭐
SHA-512⭐⭐⭐⭐⭐
MD5低(已过时)
SHA-1低(已过时)

配置示例

rabbitmqctl 命令示例

bash
# ========================================
# 用户查询操作
# ========================================

# 列出所有用户
rabbitmqctl list_users

# 列出用户及其标签
rabbitmqctl list_users -q

# 查看用户权限
rabbitmqctl list_permissions
rabbitmqctl list_user_permissions username

# ========================================
# 用户创建操作
# ========================================

# 创建用户
rabbitmqctl add_user username password

# 创建用户并设置标签
rabbitmqctl add_user admin admin123
rabbitmqctl set_user_tags admin administrator

# 创建带多个标签的用户
rabbitmqctl add_user ops_user ops123
rabbitmqctl set_user_tags ops_user monitoring policymaker

# ========================================
# 用户修改操作
# ========================================

# 修改密码
rabbitmqctl change_password username new_password

# 清除密码(禁止登录)
rabbitmqctl clear_password username

# 设置用户标签
rabbitmqctl set_user_tags username administrator

# 设置多个标签
rabbitmqctl set_user_tags username monitoring policymaker

# 清除用户标签
rabbitmqctl set_user_tags username

# ========================================
# 用户删除操作
# ========================================

# 删除用户
rabbitmqctl delete_user username

# ========================================
# 权限管理
# ========================================

# 设置用户权限
# 格式:set_permissions [-p vhost] user conf write read
rabbitmqctl set_permissions -p / username ".*" ".*" ".*"

# 设置特定虚拟主机权限
rabbitmqctl set_permissions -p /vhost1 username "^queue-.*" "^exchange-.*" ".*"

# 清除用户权限
rabbitmqctl clear_permissions -p / username

# ========================================
# 批量操作示例
# ========================================

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

# 创建应用用户
rabbitmqctl add_user app_user AppPass456!
rabbitmqctl set_permissions -p /production app_user "^app-.*" "^app-.*" "^app-.*"

# 创建只读监控用户
rabbitmqctl add_user monitor MonitorPass789!
rabbitmqctl set_user_tags monitor monitoring
rabbitmqctl set_permissions -p / monitor "" "" ".*"

rabbitmq.conf 用户配置

ini
# ========================================
# 默认用户配置
# ========================================

# 默认用户名(首次启动时创建)
# 生产环境建议修改
default_user = admin
default_pass = ${RABBITMQ_DEFAULT_PASS}

# 默认虚拟主机
default_vhost = /

# ========================================
# 认证后端配置
# ========================================

# 默认使用内部数据库
auth_backends.1 = internal

# 可以配置 LDAP 等外部认证
# auth_backends.1 = ldap
# auth_backends.2 = internal

# ========================================
# 密码策略配置
# ========================================

# 密码哈希算法
# 可选:sha256, sha512, md5, sha1
password_hashing_module = rabbit_password_hashing_sha256

# ========================================
# 访问控制
# ========================================

# 限制 guest 用户只能本地访问
# loopback_users = guest

# 允许所有用户远程访问
loopback_users = none

advanced.config 高级用户配置

erlang
[
  {rabbit, [
    %% 密码哈希算法
    {password_hashing_module, rabbit_password_hashing_sha256},
    
    %% 默认用户标签
    {default_user_tags, [administrator]},
    
    %% 认证后端
    {auth_backends, [rabbit_auth_backend_internal]},
    
    %% 用户认证超时
    {auth_attempt_timeout, 10000},
    
    %% 内部认证缓存
    {auth_backend_internal_cache, [{ttl, 300000}]}
  ]},
  
  {rabbitmq_auth_backend_ldap, [
    {servers, ["ldap.example.com"]},
    {user_dn_pattern, "cn=${username},ou=People,dc=example,dc=com"},
    {use_ssl, true},
    {port, 636},
    {log, false},
    {group_lookup_base, "ou=Groups,dc=example,dc=com"},
    {group_lookup_attribute, "memberUid"},
    {vhost_mappings, [
      {<<"vhost1">>, [{<<"groups">>, [<<"rabbitmq-users">>]}]}
    ]}
  ]}
].

PHP 代码示例

用户管理类

php
<?php

class RabbitMQUserManager
{
    private string $host;
    private int $apiPort;
    private string $username;
    private string $password;

    public function __construct(
        string $host = 'localhost',
        int $apiPort = 15672,
        string $username = 'guest',
        string $password = 'guest'
    ) {
        $this->host = $host;
        $this->apiPort = $apiPort;
        $this->username = $username;
        $this->password = $password;
    }

    private function request(string $endpoint, string $method = 'GET', array $data = []): array
    {
        $url = "http://{$this->host}:{$this->apiPort}/api/{$endpoint}";
        
        $ch = curl_init();
        curl_setopt_array($ch, [
            CURLOPT_URL => $url,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_USERPWD => "{$this->username}:{$this->password}",
            CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
            CURLOPT_CUSTOMREQUEST => $method,
        ]);
        
        if (!empty($data) && in_array($method, ['PUT', 'POST'])) {
            curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
        }
        
        $response = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $error = curl_error($ch);
        curl_close($ch);
        
        return [
            'status' => $httpCode,
            'data' => json_decode($response, true),
            'error' => $error,
        ];
    }

    public function listUsers(): array
    {
        $response = $this->request('users');
        
        if ($response['status'] !== 200) {
            throw new RuntimeException("获取用户列表失败: " . ($response['error'] ?? 'Unknown error'));
        }
        
        return $response['data'];
    }

    public function getUser(string $username): ?array
    {
        $response = $this->request("users/{$username}");
        
        if ($response['status'] === 404) {
            return null;
        }
        
        if ($response['status'] !== 200) {
            throw new RuntimeException("获取用户失败: " . ($response['error'] ?? 'Unknown error'));
        }
        
        return $response['data'];
    }

    public function createUser(string $username, string $password, array $tags = []): bool
    {
        $data = [
            'password' => $password,
            'tags' => implode(',', $tags),
        ];
        
        $response = $this->request("users/{$username}", 'PUT', $data);
        
        return $response['status'] === 201 || $response['status'] === 204;
    }

    public function updateUserPassword(string $username, string $newPassword): bool
    {
        $user = $this->getUser($username);
        if (!$user) {
            throw new RuntimeException("用户不存在: {$username}");
        }
        
        $data = [
            'password' => $newPassword,
            'tags' => $user['tags'],
        ];
        
        $response = $this->request("users/{$username}", 'PUT', $data);
        
        return $response['status'] === 204;
    }

    public function updateUserTags(string $username, array $tags): bool
    {
        $user = $this->getUser($username);
        if (!$user) {
            throw new RuntimeException("用户不存在: {$username}");
        }
        
        $data = [
            'password_hash' => $user['password_hash'],
            'tags' => implode(',', $tags),
        ];
        
        $response = $this->request("users/{$username}", 'PUT', $data);
        
        return $response['status'] === 204;
    }

    public function deleteUser(string $username): bool
    {
        $response = $this->request("users/{$username}", 'DELETE');
        
        return $response['status'] === 204;
    }

    public function getUserPermissions(string $username): array
    {
        $response = $this->request("users/{$username}/permissions");
        
        if ($response['status'] !== 200) {
            return [];
        }
        
        return $response['data'];
    }

    public function printUserList(): void
    {
        $users = $this->listUsers();
        
        echo "RabbitMQ 用户列表\n";
        echo str_repeat("=", 60) . "\n";
        echo sprintf("%-20s %-30s %s\n", '用户名', '标签', '密码哈希');
        echo str_repeat("-", 60) . "\n";
        
        foreach ($users as $user) {
            $name = $user['name'];
            $tags = $user['tags'] ?? '无';
            $hash = substr($user['password_hash'] ?? '', 0, 20) . '...';
            echo sprintf("%-20s %-30s %s\n", $name, $tags, $hash);
        }
    }
}

// 使用示例
$manager = new RabbitMQUserManager('localhost', 15672, 'admin', 'password');

// 创建管理员用户
$manager->createUser('new_admin', 'SecurePass123!', ['administrator']);

// 创建监控用户
$manager->createUser('monitor', 'MonitorPass456!', ['monitoring']);

// 创建应用用户
$manager->createUser('app_user', 'AppPass789!', []);

// 打印用户列表
$manager->printUserList();

权限管理类

php
<?php

class RabbitMQPermissionManager
{
    private RabbitMQUserManager $userManager;
    private string $host;
    private int $apiPort;
    private string $username;
    private string $password;

    public function __construct(
        string $host = 'localhost',
        int $apiPort = 15672,
        string $username = 'guest',
        string $password = 'guest'
    ) {
        $this->host = $host;
        $this->apiPort = $apiPort;
        $this->username = $username;
        $this->password = $password;
        $this->userManager = new RabbitMQUserManager($host, $apiPort, $username, $password);
    }

    private function request(string $endpoint, string $method = 'GET', array $data = []): array
    {
        $url = "http://{$this->host}:{$this->apiPort}/api/{$endpoint}";
        
        $ch = curl_init();
        curl_setopt_array($ch, [
            CURLOPT_URL => $url,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_USERPWD => "{$this->username}:{$this->password}",
            CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
            CURLOPT_CUSTOMREQUEST => $method,
        ]);
        
        if (!empty($data)) {
            curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
        }
        
        $response = curl_exec($ch);
        $httpCode = curl_getinfo($ch, CURLONECTINFO_HTTP_CODE);
        curl_close($ch);
        
        return [
            'status' => $httpCode,
            'data' => json_decode($response, true),
        ];
    }

    public function setPermission(
        string $username,
        string $vhost,
        string $configure = '.*',
        string $write = '.*',
        string $read = '.*'
    ): bool {
        $data = [
            'configure' => $configure,
            'write' => $write,
            'read' => $read,
        ];
        
        $vhostEncoded = urlencode($vhost);
        $response = $this->request("permissions/{$vhostEncoded}/{$username}", 'PUT', $data);
        
        return $response['status'] === 204;
    }

    public function clearPermission(string $username, string $vhost = '/'): bool
    {
        $vhostEncoded = urlencode($vhost);
        $response = $this->request("permissions/{$vhostEncoded}/{$username}", 'DELETE');
        
        return $response['status'] === 204;
    }

    public function listPermissions(string $vhost = null): array
    {
        $endpoint = $vhost ? "vhosts/{$vhost}/permissions" : 'permissions';
        $response = $this->request($endpoint);
        
        return $response['data'] ?? [];
    }

    public function createApplicationUser(
        string $username,
        string $password,
        string $vhost,
        string $resourcePattern = '^app-.*'
    ): bool {
        $this->userManager->createUser($username, $password, []);
        
        return $this->setPermission(
            $username,
            $vhost,
            $resourcePattern,
            $resourcePattern,
            $resourcePattern
        );
    }

    public function createReadOnlyUser(
        string $username,
        string $password,
        string $vhost
    ): bool {
        $this->userManager->createUser($username, $password, ['monitoring']);
        
        return $this->setPermission(
            $username,
            $vhost,
            '',
            '',
            '.*'
        );
    }

    public function printPermissions(): void
    {
        $permissions = $this->listPermissions();
        
        echo "RabbitMQ 权限列表\n";
        echo str_repeat("=", 80) . "\n";
        echo sprintf("%-15s %-10s %-15s %-15s %-15s\n", 
            '用户', '虚拟主机', '配置', '写', '读');
        echo str_repeat("-", 80) . "\n";
        
        foreach ($permissions as $perm) {
            echo sprintf("%-15s %-10s %-15s %-15s %-15s\n",
                $perm['user'],
                $perm['vhost'],
                $perm['configure'] ?: '(无)',
                $perm['write'] ?: '(无)',
                $perm['read'] ?: '(无)'
            );
        }
    }
}

// 使用示例
$permManager = new RabbitMQPermissionManager('localhost', 15672, 'admin', 'password');

// 创建应用用户并设置权限
$permManager->createApplicationUser('order_service', 'OrderPass123', '/production', '^order-.*');

// 创建只读监控用户
$permManager->createReadOnlyUser('monitor_user', 'MonitorPass456', '/');

// 打印权限列表
$permManager->printPermissions();

批量用户管理脚本

php
<?php

class RabbitMQBatchUserManager
{
    private RabbitMQUserManager $userManager;
    private RabbitMQPermissionManager $permManager;

    public function __construct(
        string $host = 'localhost',
        int $apiPort = 15672,
        string $adminUser = 'guest',
        string $adminPass = 'guest'
    ) {
        $this->userManager = new RabbitMQUserManager($host, $apiPort, $adminUser, $adminPass);
        $this->permManager = new RabbitMQPermissionManager($host, $apiPort, $adminUser, $adminPass);
    }

    public function setupFromConfig(array $config): array
    {
        $results = [
            'created' => [],
            'updated' => [],
            'failed' => [],
        ];

        foreach ($config['users'] as $userConfig) {
            try {
                $username = $userConfig['username'];
                $password = $userConfig['password'];
                $tags = $userConfig['tags'] ?? [];

                $existing = $this->userManager->getUser($username);
                
                if ($existing) {
                    if (!empty($userConfig['update_password'])) {
                        $this->userManager->updateUserPassword($username, $password);
                    }
                    $this->userManager->updateUserTags($username, $tags);
                    $results['updated'][] = $username;
                } else {
                    $this->userManager->createUser($username, $password, $tags);
                    $results['created'][] = $username;
                }

                if (!empty($userConfig['permissions'])) {
                    foreach ($userConfig['permissions'] as $permConfig) {
                        $this->permManager->setPermission(
                            $username,
                            $permConfig['vhost'] ?? '/',
                            $permConfig['configure'] ?? '.*',
                            $permConfig['write'] ?? '.*',
                            $permConfig['read'] ?? '.*'
                        );
                    }
                }
            } catch (Exception $e) {
                $results['failed'][] = [
                    'username' => $username ?? 'unknown',
                    'error' => $e->getMessage(),
                ];
            }
        }

        return $results;
    }

    public function exportConfig(): array
    {
        $users = $this->userManager->listUsers();
        $permissions = $this->permManager->listPermissions();

        $config = [
            'users' => [],
        ];

        foreach ($users as $user) {
            $userConfig = [
                'username' => $user['name'],
                'tags' => array_filter(explode(',', $user['tags'] ?? '')),
                'permissions' => [],
            ];

            foreach ($permissions as $perm) {
                if ($perm['user'] === $user['name']) {
                    $userConfig['permissions'][] = [
                        'vhost' => $perm['vhost'],
                        'configure' => $perm['configure'],
                        'write' => $perm['write'],
                        'read' => $perm['read'],
                    ];
                }
            }

            $config['users'][] = $userConfig;
        }

        return $config;
    }
}

// 使用示例
$config = [
    'users' => [
        [
            'username' => 'admin',
            'password' => 'AdminPass123!',
            'tags' => ['administrator'],
            'permissions' => [
                ['vhost' => '/', 'configure' => '.*', 'write' => '.*', 'read' => '.*']
            ]
        ],
        [
            'username' => 'order_service',
            'password' => 'OrderPass456!',
            'tags' => [],
            'permissions' => [
                ['vhost' => '/production', 'configure' => '^order-.*', 'write' => '^order-.*', 'read' => '^order-.*']
            ]
        ],
        [
            'username' => 'monitor',
            'password' => 'MonitorPass789!',
            'tags' => ['monitoring'],
            'permissions' => [
                ['vhost' => '/', 'configure' => '', 'write' => '', 'read' => '.*']
            ]
        ],
    ],
];

$batchManager = new RabbitMQBatchUserManager('localhost', 15672, 'admin', 'password');
$results = $batchManager->setupFromConfig($config);

print_r($results);

实际应用场景

场景一:微服务用户管理

php
<?php

class MicroserviceUserSetup
{
    private RabbitMQUserManager $userManager;
    private RabbitMQPermissionManager $permManager;

    public function __construct(RabbitMQUserManager $userManager, RabbitMQPermissionManager $permManager)
    {
        $this->userManager = $userManager;
        $this->permManager = $permManager;
    }

    public function setupServiceUser(string $serviceName, string $vhost): array
    {
        $username = "{$serviceName}_user";
        $password = $this->generateSecurePassword();
        $pattern = "^{$serviceName}-.*";

        $this->userManager->createUser($username, $password);
        $this->permManager->setPermission($username, $vhost, $pattern, $pattern, $pattern);

        return [
            'username' => $username,
            'password' => $password,
            'vhost' => $vhost,
            'pattern' => $pattern,
        ];
    }

    private function generateSecurePassword(int $length = 24): string
    {
        $chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*';
        return substr(str_shuffle(str_repeat($chars, ceil($length / strlen($chars)))), 0, $length);
    }
}

// 使用示例
$setup = new MicroserviceUserSetup($userManager, $permManager);
$credentials = $setup->setupServiceUser('payment', '/production');
echo "服务用户创建成功:\n";
print_r($credentials);

场景二:环境隔离用户配置

bash
#!/bin/bash
# setup-users.sh

# 开发环境用户
rabbitmqctl add_user dev_user DevPass123
rabbitmqctl set_permissions -p /dev dev_user ".*" ".*" ".*"

# 测试环境用户
rabbitmqctl add_user test_user TestPass456
rabbitmqctl set_permissions -p /test test_user ".*" ".*" ".*"

# 生产环境用户
rabbitmqctl add_user prod_user ProdPass789
rabbitmqctl set_permissions -p /production prod_user "^app-.*" "^app-.*" "^app-.*"

# 监控用户
rabbitmqctl add_user monitor MonitorPass000
rabbitmqctl set_user_tags monitor monitoring
rabbitmqctl set_permissions -p / monitor "" "" ".*"
rabbitmqctl set_permissions -p /dev monitor "" "" ".*"
rabbitmqctl set_permissions -p /test monitor "" "" ".*"
rabbitmqctl set_permissions -p /production monitor "" "" ".*"

场景三:定期密码轮换

php
<?php

class PasswordRotationManager
{
    private RabbitMQUserManager $userManager;
    private array $excludeUsers = ['guest', 'admin'];

    public function rotateAllPasswords(): array
    {
        $results = [];
        $users = $this->userManager->listUsers();

        foreach ($users as $user) {
            $username = $user['name'];
            
            if (in_array($username, $this->excludeUsers)) {
                $results[$username] = 'skipped';
                continue;
            }

            $newPassword = $this->generatePassword();
            
            try {
                $this->userManager->updateUserPassword($username, $newPassword);
                $results[$username] = [
                    'status' => 'success',
                    'new_password' => $newPassword,
                ];
            } catch (Exception $e) {
                $results[$username] = [
                    'status' => 'failed',
                    'error' => $e->getMessage(),
                ];
            }
        }

        return $results;
    }

    private function generatePassword(): string
    {
        return bin2hex(random_bytes(16));
    }
}

常见问题与解决方案

问题一:忘记管理员密码

解决方案

bash
# 方法一:使用 rabbitmqctl 重置密码
rabbitmqctl change_password admin NewPassword123

# 方法二:创建新管理员
rabbitmqctl add_user new_admin NewAdminPass123
rabbitmqctl set_user_tags new_admin administrator
rabbitmqctl set_permissions -p / new_admin ".*" ".*" ".*"

# 方法三:重置整个用户数据库(慎用)
rabbitmqctl stop_app
rabbitmqctl reset
rabbitmqctl start_app

问题二:guest 用户无法远程访问

原因分析

  • 默认配置限制 guest 用户只能本地访问

解决方案

ini
# 方法一:创建新用户(推荐)
# rabbitmq.conf
default_user = admin
default_pass = SecurePassword

# 方法二:允许 guest 远程访问(不推荐)
loopback_users = none

问题三:用户权限不生效

原因分析

  • 正则表达式格式错误
  • 虚拟主机名称错误
  • 权限未正确设置

解决方案

bash
# 检查当前权限
rabbitmqctl list_user_permissions username

# 验证正则表达式
# 正确格式:以 ^ 开头,以 $ 结尾
rabbitmqctl set_permissions -p / username "^queue\..*" "^exchange\..*" ".*"

# 注意转义特殊字符
rabbitmqctl set_permissions -p /vhost1 username "^app\\.queue\\..*" ".*" ".*"

最佳实践建议

1. 用户命名规范

命名格式:{service}_{environment}_{role}

示例:
- order_prod_producer    # 订单服务生产环境生产者
- order_prod_consumer    # 订单服务生产环境消费者
- payment_test_admin     # 支付服务测试环境管理员
- monitor_all            # 全局监控用户

2. 密码安全策略

php
<?php

class SecurePasswordGenerator
{
    public static function generate(int $length = 24): string
    {
        $lowercase = 'abcdefghijklmnopqrstuvwxyz';
        $uppercase = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
        $numbers = '0123456789';
        $special = '!@#$%^&*()_+-=[]{}|;:,.<>?';
        
        $password = '';
        $password .= $lowercase[random_int(0, strlen($lowercase) - 1)];
        $password .= $uppercase[random_int(0, strlen($uppercase) - 1)];
        $password .= $numbers[random_int(0, strlen($numbers) - 1)];
        $password .= $special[random_int(0, strlen($special) - 1)];
        
        $allChars = $lowercase . $uppercase . $numbers . $special;
        for ($i = 4; $i < $length; $i++) {
            $password .= $allChars[random_int(0, strlen($allChars) - 1)];
        }
        
        return str_shuffle($password);
    }
}

3. 最小权限原则

bash
# 生产者:只需要写权限
rabbitmqctl set_permissions -p / producer "" "^exchange-.*" ""

# 消费者:只需要读权限
rabbitmqctl set_permissions -p / consumer "" "" "^queue-.*"

# 管理服务:需要配置和读权限
rabbitmqctl set_permissions -p / manager "^queue-.*" "" "^queue-.*"

4. 用户审计日志

php
<?php

class UserAuditLogger
{
    private string $logFile;

    public function logUserChange(string $action, string $username, array $details = []): void
    {
        $entry = [
            'timestamp' => date('Y-m-d H:i:s'),
            'action' => $action,
            'username' => $username,
            'details' => $details,
            'ip' => $_SERVER['REMOTE_ADDR'] ?? 'cli',
        ];

        file_put_contents(
            $this->logFile,
            json_encode($entry) . "\n",
            FILE_APPEND
        );
    }
}

相关链接