RocketMQ作为一款优秀的中间件,应用领域非常广泛,金融、电商、电信、医疗、社科、安保等不同的领域都有其大规模的应用,无疑安全性很受质疑,因为内部没有安全相关的业务模块,消息的发送和消费得不到很好的安全管控需要业务方自己去封装安全模块,无形中增加了使用成本。在RocketMQ4.4.0版本升级中加入了ACL权限管控,这个功能的完善直接推动了RocketMQ在各个领域的推广使用,特别是金融、电商、安保等安全要求较高的领域。
1、简单使用
1.1、ACL是什么
ACL是access control list的简称,俗称访问控制列表。访问控制,基本上会涉及到用户、资源、权限、角色等概念,那在RocketMQ中上述会对应哪些对象呢?
用户:用户是访问控制的基础要素,RocketMQ ACL必然也会引入用户的概念,即支持用户名、密码。 资源:需要保护的对象,消息发送涉及的Topic、消息消费涉及的消费组,应该进行保护,故可以抽象成资源。 权限:针对资源,能进行的操作。 角色:RocketMQ中,只定义两种角色:是否是管理员。
1.2、RocketMQ中配置ACL
acl默认的配置文件名:plain_acl.yml,需要放在${ROCKETMQ_HOME}/store/config目录下
需要使用acl必须在服务端开启此功能,在Broker的配置文件中配置,aclEnable = true开启此功能
配置plain_acl.yml文件
globalWhiteRemoteAddresses:
- 10.10.15.*
- 192.168.0.*
accounts:
- accessKey: RocketMQ
secretKey: 12345678
whiteRemoteAddress:
admin: false
defaultTopicPerm: DENY
defaultGroupPerm: SUB
topicPerms:
- topicA=DENY
- topicB=PUB|SUB
- topicC=SUB
groupPerms:
# the group should convert to retry topic
- groupA=DENY
- groupB=PUB|SUB
- groupC=SUB
- accessKey: rocketmq2
secretKey: 12345678
whiteRemoteAddress: 192.168.1.*
# if it is admin, it could access all resources
admin: true
下面我们介绍一下plain_acl.yml文件中相关的参数含义及使用
字段 | 取值 | 含义 |
---|---|---|
globalWhiteRemoteAddresses | *;192.168.*.*;192.168.0.1 | 全局IP白名单 |
accessKey | 字符串 | Access Key 用户名 |
secretKey | 字符串 | Secret Key 密码 |
whiteRemoteAddress | *;192.168.*.*;192.168.0.1 | 用户IP白名单 |
admin | true;false | 是否管理员账户 |
defaultTopicPerm | DENY;PUB;SUB;PUB|SUB | 默认的Topic权限 |
defaultGroupPerm | DENY;PUB;SUB;PUB|SUB | 默认的ConsumerGroup权限 |
topicPerms | topic=权限 | 各个Topic的权限 |
groupPerms | group=权限 | 各个ConsumerGroup的权限 |
权限标识符的含义
权限 | 含义 |
---|---|
DENY | 拒绝 |
ANY | PUB 或者 SUB 权限 |
PUB | 发送权限 |
SUB | 订阅权限 |
处理流程
特殊的请求例如 UPDATE_AND_CREATE_TOPIC 等,只能由 admin 账户进行操作;
对于某个资源,如果有显性配置权限,则采用配置的权限;如果没有显性配置权限,则采用默认的权限
RocketMQ的权限控制存储的默认实现是基于yml配置文件。用户可以动态修改权限控制定义的属性,而不需重新启动Broker服务节点
如果ACL与高可用部署(Master/Slave架构)同时启用,那么需要在Broker Master节点的${ROCKETMQ_HOME}/store/conf/plain_acl.yml配置文件中 设置全局白名单信息,即为将Slave节点的ip地址设置至Master节点plain_acl.yml配置文件的全局白名单中
1.3、代码示例
1.3.1、生产者代码
public class AclProducer {
public static void main(String[] args) throws MQClientException, InterruptedException {
DefaultMQProducer producer = new DefaultMQProducer("please_rename_unique_group_name", getAclRPCHook());
producer.setNamesrvAddr("10.10.15.246:9876;10.10.15.247:9876");
producer.start();
for (int i = 0; i < 10; i++) {
try {
Message msg = new Message("topicA" ,"TagA" , ("Hello RocketMQ " + i).getBytes(RemotingHelper.DEFAULT_CHARSET));
SendResult sendResult = producer.send(msg);
System.out.printf("%s%n", sendResult);
} catch (Exception e)