【RocketMQ】RocketMQ ACL动手实践与踩坑记录


本文主要介绍RocketMQ ACL的服务端、客户端配置,实践中踩过的一些坑,以及个人觉得目前RocketMQ ACL不完善的地方。借鉴了丁威老师的 《RocketMQ ACL使用指南》

介绍

什么是ACL

RocketMQ在4.4.0版本开始支持ACL。ACL是Access Control List的简称,俗称访问控制列表。访问控制,基本上会涉及到用户、资源、权限、角色等概念,那在RocketMQ中上述会对应哪些对象呢?

  • 用户:用户是访问控制的基础要素,也不难理解,RocketMQ ACL必然也会引入用户的概念,即支持用户名、密码
  • 资源:资源,需要保护的对象,在RocketMQ中,消息发送涉及的Topic、消息消费涉及的消费组,应该进行保护,故可以抽象成资源
  • 权限:针对资源,能进行的操作
  • 角色:RocketMQ中,只定义两种角色:是否是管理员

另外,RocketMQ还支持按照客户端IP进行白名单设置。

基本流程

权限控制(ACL)主要为RocketMQ提供Topic资源级别的用户访问控制。用户在使用RocketMQ权限控制时,可以在Client客户端通过 RPCHook注入AccessKey和SecretKey签名;同时,将对应的权限控制属性(包括Topic访问权限、IP白名单和AccessKey和SecretKey签名等)设置plain_acl.yml的配置文件中。Broker端对AccessKey所拥有的权限进行校验,校验不过,抛出异常;

配置ACL

示例

globalWhiteRemoteAddresses:

accounts:
- accessKey: RocketMQ
  secretKey: 12345678
  whiteRemoteAddress:
  admin: false
  defaultTopicPerm: DENY
  defaultGroupPerm: DENY
  topicPerms:
  - test-deny=DENY
  - test-pubsub=PUB|SUB
  - test-sub=SUB
  - test-pub=PUB
  - zhurunhua-test=PUB|SUB
  groupPerms:
  - group-deny=DENY
  - group-pubsub=PUB|SUB
  - group-sub=SUB
  - group-pub=PUB
  - zhurunhua-test=PUB|SUB
  
- accessKey: zhurunhua
  secretKey: zhurunhua
  whiteRemoteAddress: 
  # if it is admin, it could access all resources
  admin: true

ACL配置文件

ACL默认的配置文件名:plain_acl.yml,需要放在{ROCKETMQ_HOME}/config目录下,可以通过环境变量的方式改变:

java -Drocketmq.acl.plain.file=

下面对其配置项一一介绍。

globalWhiteRemoteAddresses

全局白名单,其类型为数组,即支持多个配置。其支持的配置格式如下:

  • 空 表示不设置白名单,该条规则默认返回false。
  • “*” 表示全部匹配,该条规则直接返回true,将会阻断其他规则的判断,请慎重使用。
  • 192.168.0.{100,101} 多地址配置模式,ip地址的最后一组,使用{},大括号中多个ip地址,用英文逗号(,)隔开。
  • 192.168.1.100,192.168.2.100 直接使用,分隔,配置多个ip地址。
  • 192.168.*.* 或192.168.100-200.10-20 每个IP段使用 “*” 或"-"表示范围。

注意,如果配置了全局白名单,即使account没配置权限,只要客户端IP在白名单里,也有权限,即权限配置会以全局白名单优先,需要慎重配置。

accounts

配置用户信息,该类型为数组类型。拥有accessKey、secretKey、whiteRemoteAddress、admin、defaultTopicPerm、defaultGroupPerm、topicPerms、groupPerms子元素。

accessKey

登录用户名,长度必须大于6个字符。

secretKey

登录密码。长度必须大于6个字符。

whiteRemoteAddress

用户级别的IP地址白名单。其类型为一个字符串,其配置规则与globalWhiteRemoteAddresses,但只能配置一条规则。

admin

boolean类型,设置是否是admin。如下权限只有admin=true时才有权限执行。

  • UPDATE_AND_CREATE_TOPIC 更新或创建主题。
  • UPDATE_BROKER_CONFIG 更新Broker配置。
  • DELETE_TOPIC_IN_BROKER 删除主题。
  • UPDATE_AND_CREATE_SUBSCRIPTIONGROUP 更新或创建订阅组信息。
  • DELETE_SUBSCRIPTIONGROUP 删除订阅组信息。

defaultTopicPerm

默认topic权限。该值默认为DENY(拒绝)。

defaultGroupPerm

默认消费组权限,该值默认为DENY(拒绝),建议值为SUB。

topicPerms

设置topic的权限。其类型为数组,其可选择值在下节介绍。

groupPerms

设置消费组的权限。其类型为数组,其可选择值在下节介绍。可以为每一消费组配置不一样的权限。

RocketMQ ACL权限可选值

  • DENY 拒绝。
  • PUB 拥有发送权限。
  • SUB 拥有订阅权限。
  • ALL 拥有发送订阅权限
    但是如果要配置即有PUB权限又有SUB权限,需要写成:PUB|SUB或SUB|PUB

实践

使用介绍

开启ACL

除了在plain_acl.yml中添加相关配置之外,还需要在每个broker的broker.conf中开启ACL,加一个配置即可

 aclEnable=true

客户端使用

开启ACL之后,客户端需要通过钩子函数设置用户名密码

Producer

@Slf4j
public class TestAclProducer {
    
    
    public static void main(String[] args) throws MQClientException, InterruptedException {
    
    
        DefaultMQProducer producer = new DefaultMQProducer("zhurunhua-test", getAclRPCHook());
        producer.setNamesrvAddr("172.24.29.215:9976");
        producer.start();
            try {
    
    
                Message msg = new Message("test-pubsub",
                        "TagA",
                        "OrderID188",
                        "Hello world".getBytes(RemotingHelper.DEFAULT_CHARSET));
                SendResult sendResult = producer.send(msg);
                System.out.printf("%s%n", sendResult);
            } catch (Exception e) {
    
    
                log.error("", e);
            }
        producer.shutdown();
    }

    static RPCHook getAclRPCHook() {
    
    
        //normal
        return new AclClientRPCHook(new SessionCredentials("test-user-1", "12345678"));
        //admin
//        return new AclClientRPCHook(new SessionCredentials("zhurunhua", "zhurunhua"));
    }
}

Consumer

public class TestAclConsumer {
    
    
    public static void main(String[] args) throws InterruptedException, MQClientException {
    
    
        DefaultMQPushConsumer consumer = new DefaultMQPushConsumer("group-sub", getAclRPCHook(), new AllocateMessageQueueAveragely());
        consumer.setConsumeFromWhere(ConsumeFromWhere.CONSUME_FROM_FIRST_OFFSET);
        consumer.subscribe("test-pubsub", "*");
        consumer.setNamesrvAddr("172.24.29.215:9976");
        consumer.registerMessageListener((MessageListenerConcurrently) (msgs, context) -> {
    
    
            System.out.printf("%s Receive New Messages: %s %n", Thread.currentThread().getName(), msgs);
            return ConsumeConcurrentlyStatus.CONSUME_SUCCESS;
        });
        consumer.start();
        System.out.printf("Consumer Started.%n");
    }

    static RPCHook getAclRPCHook() {
    
    
        return new AclClientRPCHook(new SessionCredentials("test-user-1", "12345678"));
    }

}

如果对对指定Topic没有配置制定的权限,会报下面的错误

注意事项

1、组权限只是针对消费者的

通过修改不同的权限,验证对生产者和消费者的影响

验证结果是:topicPerm对生产和消费都起作用,而groupPerm只是针对消费的,对生产是没影响的。

globalWhiteRemoteAddresses:

accounts:
- accessKey: RocketMQ
  secretKey: 12345678
  whiteRemoteAddress:
  admin: false
  defaultTopicPerm: DENY
  # 这个对生产者不生效
  defaultGroupPerm: DENY
  topicPerms:
  # 生产报错、消费不报错也不消费
  - test-deny=DENY
  # 生产消费正常
  - test-pubsub=PUB|SUB
  # 消费正常、生产报错
  - test-sub=SUB
  # 生产正常、消费不报错也不消费
  - test-pub=PUB
  - zhurunhua-test=PUB|SUB
  groupPerms:
  # 如果对Topic有生产消费的权限:
  # 消费不报错,但是不消费、可以正常生产
  - group-deny=DENY
  # 生产消费正常
  - group-pubsub=PUB|SUB
  # 生产消费正常
  - group-sub=SUB
  # 生产正常、消费不报错,但是不消费
  - group-pub=PUB
  - zhurunhua-test=PUB|SUB
  
- accessKey: zhurunhua
  secretKey: zhurunhua
  whiteRemoteAddress: 
  # if it is admin, it could access all resources
  admin: true

2、支持热更新,有watch方法会监听文件改变(500ms一次,比对文件md5值)

3、消费者组需要先创建(通过console或管理命令),否则消费者不报错也不消费;

4、如果ACL与高可用部署(Master/Slave架构)同时启用,那么需要在Broker Master节点的plain_acl.yml配置文件中,设置全局白名单信息,即为将Slave节点的ip地址设置至Master节点plain_acl.yml配置文件的全局白名单中;

globalWhiteRemoteAddresses:
# 所有Slave的IP
- 172.24.29.{
    
    213,215}
accounts:
- accessKey: zhurunhua
  secretKey: zhurunhua
  whiteRemoteAddress: 
  # if it is admin, it could access all resources
  admin: true

5、如果ACL与高可用部署(多副本Dledger架构)同时启用,由于出现节点宕机时,Dledger Group组内会自动选主,那么就需要将Dledger Group组内所有Broker节点的plain_acl.yml配置文件的白名单设置所有Broker节点的ip地址。

globalWhiteRemoteAddresses:
# 所有Broker的IP
- 172.24.29.*
accounts:
- accessKey: zhurunhua
  secretKey: zhurunhua
  whiteRemoteAddress: 
  # if it is admin, it could access all resources
  admin: true

6、使用管理命令mqadmin updateAclConfig可以修改集群的ACL

创建ACL:

./mqadmin updateAclConfig -n 172.24.29.215:9976 -c rocketmq-test -a test-user-1 -s 12345678 -t test-deny=DENY,test-sub=SUB,test-pub=PUB,zhurunhua-test=DENY
RocketMQLog:WARN No appenders could be found for logger (io.netty.util.internal.PlatformDependent0).
RocketMQLog:WARN Please initialize the logger system properly.
create or update plain access config to 172.24.29.215:30911 success.
create or update plain access config to 172.24.29.213:30915 success.

修改ACL:

./mqadmin updateAclConfig -n 172.24.29.215:9976 -c rocketmq-test -a test-user-1 -g group-deny=DENY,group-sub=SUB,group-pub=PUB,group-pubsub=PUB,zhurunhua-test=DENY

注意:

  • 如果参数中带符号,如nameserver地址中的分号( ; )、权限分隔的竖线( | ),将参数用单引号包裹即可
  • 使用-c指定集群名称时,只会修改所有Master节点的ACL配置文件,代码中会根据集群名称查询master集合
  • 使用-b指定broker地址,每次只能设置一个broker地址,如:
./mqadmin updateAclConfig -n 172.24.29.215:9976 -b '172.24.29.215:30911' -a test-user-2 -s 12345678 -t 'zhurunhua-test=PUB|SUB'

请看源码:

拿到-b的参数之后,只做了trim,直接将addr传给了执行的方法

  • 如果我发现我某个topic或者group的权限分配错了,想单独修改某个topic或者group,实践证明是不行的,只会做全量修改,如下:
./mqadmin updateAclConfig -n 172.24.29.215:9976 -c rocketmq-test -a test-user-1 -g 'group-pubsub=PUB|SUB'


如果要做增量修改,必须先拿到之前的,再在此基础上修改

7、开启ACL之后,console需要配置accessKey和secretKey

accessKey和secretKey需要按plain_acl.yml中的配置

也可以通过jvm参数的方式指定accessKey和secretKey

java -server -Xms1024m -Xmx1024m -XX:NewSize=512m -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=70 -XX:+PrintGCDetails -XX:+PrintHeapAtGC -XX:ThreadStackSize=512 -Xloggc:/neworiental/rocketmq-test/rocketmq-console/logs/gc.log -jar /neworiental/rocketmq-test/rocketmq-console/rocketmq-console-ng-2.0.0.jar --rocketmq.config.accessKey=zhurunhua --rocketmq.config.secretKey=zhurunhua
  • 上面这种通过加accessKey和secretKey的方式,如果配置的accessKey不是admin,在console执行一些管理操作的时候,会报错,包括:删除topic、查看集群状态、添加/删除消费组、发送消息等,只有一些查看权限。

还有最简单粗暴的方法,就是将console的IP加到plain_acl.yml的全局白名单中。

存在的问题

  • 使用命令修改ACL列表时,如果使用-c,只会更新所有Master的数据,所有的slave都不会同步ACL变更,如果slave切换为主,ACL数据就会失效,所以最好是使用-b,修改每一个broker的ACL文件
  • console对ACL的支持不灵活,如果配置了非admin用户,不能根据用户的权限适配页面功能和数据,只是会在页面操作时报错,如果配置了admin用户,拥有所有权限,只能提供给管理员使用
  • accessKey和secretKey明文展示,一定程度上存在安全问题
  • acl相关的配置,是从本地文件load的,修改时需要每个Broker都做修改,这样的好处是省去了配置中心或者注册中心的依赖,但是修改起来比较繁琐,尤其是针对规模比较大的集群
  • 吐槽一点,官方文档过于简单,很多东西需要自己实践、查看源码才知道如何正确使用

参考:

https://blog.csdn.net/prestigeding/article/details/94317946

Guess you like

Origin blog.csdn.net/sinat_14840559/article/details/116302400