Apache RocketMQ ACL 2.0 全新升级

  1. 统一主体模型的抽象:为了实现不同实体的访问控制和权限管理,设计了统一的主体接口,允许系统中多个实例作为资源访问的主体。用户作为访问资源的主体之一,按照该模型实现了主体的接口。这为未来新实体类型的权限适配提供了扩展能力。
  2. 角色分级与权限赋予:
  • 超级用户:为了简化管理流程,超级用户被自动授予了全部权限,无需单独配置,从而简化了系统的初始化和日常的运维管理工作。
  • 普通用户:普通用户的权限则需要明确授权。ACL 2.0 提供了相关的权限管理工具,可以根据组织的政策和安全需求,为普通用户赋予合适的权限。

3.支持用户状态管理:为了应对可能出现的安全风险,比如用户密码泄露,ACL 2.0 提供了用户的启用与禁用功能。当发生安全事件,可以通过禁用用户状态,快速进行止血,从而达到阻止非法访问的目的。

认证流程

客户端流程:

  1. 客户端在构建 RPC 请求时,检查是否设置了用户名和密码,若未配置,则直接发送请求;
  2. 若已配置,则使用预设的加密算法对请求参数进行加密处理,并生成对应的数字签名(Signature)。
  3. 在请求中附加用户名和 Signature,并将其发送至服务端以进行身份验证。

服务端流程:

  1. 服务端接收到请求后,首先检查是否开启认证,若未开启,则不校验直接通过;若已开启了,则进入下一步。
  2. 服务端对请求进行认证相关的参数进行解析和组装,获取包括用户名和 Signature 等信息。
  3. 通过用户名在本地库中查询用户相关信息,用户不存在,则返回处理无;用户存在,则进入下一步。
  4. 获取用户密码,采用相同的加密算法对请求进行加密生成 Signature,并和客户端传递的 Signature 进行比对,若两者一致,则认证成功,不一致,则认证失败。

授权(Authorization)

核心概念

授权作为一种安全机制,旨在确定访问请求者是否拥有对特定资源进行操作的权限。简而言之,授权就是在资源被访问之前回答“谁在何种环境下对哪些资源执行何种操作”这个问题。

基于“属性的访问控制(ABAC)”模型,RocketMQ ACL 2.0 涵盖了以下一系列的核心概念。在系统实现中,都会以以下概念作为指导,完成整个权限管理和授权机制的设计和实现。

权限模型

基于属性的访问控制(ABAC)模型的核心概念,ACL 2.0 对权限模型做了精心的设计,要点如下:

向后兼容的权限策略:默认情况下,ACL 2.0 只匹配和检验用户自定义的权限,若未找到匹配项,则视为无权限访问资源。但考虑到 ACL 1.0 中,存在默认权限的设置,允许对未匹配资源进行“无权限访问”和“有权限访问”的默认判定。因此,我们针对默认权限策略进行了兼容,确保 ACL 1.0 到 ACL 2.0 的无缝迁移。

灵活的资源匹配模式:在资源类型方面,ACL 2.0 支持了集群(Cluster)、命名空间(Namespace)、主题(Topic)、消费者组(Group)等类型,用于对不同类型的资源进行访问控制。在资源名称方面,引入了完全匹配(LITERAL)、前缀匹配(PREFIXED),以及通配符匹配(ANY)三种模式,方便用户根据资源的命名规范和结构,快速设定统一的访问规则,简化权限的管理。

精细的资源操作类型:在消息的发送和消费的接口方面,分别定义为 PUB 和 SUB 这两种操作。在集群和资源的管理的接口方面,分别定义为 CREATE、UPDATE、DELETE、LIST、GET 五种操作。通过这种操作类型的细化,可以帮助用户在资源的操作层面,无需关心具体的接口定义,简化对操作的理解和配置。

坚实的访问环境校验:在请求访问的环境方面,ACL 2.0 加入了客户端请求 IP 来源的校验,这个校验控制在每个资源的级别,可以精确到对每个资源进行控制。IP 来源可以是特定的 IP 地址或者是一个 IP 段,来满足不同粒度的 IP 访问控制,为系统的安全性增添一道坚实的防线。

授权流程

客户端流程:

  1. 客户端在构建 RPC 请求时,构建本次调用的接口入参,接口对应权限背后的操作定义。
  2. 客户端在接口入参中设置本次访问的资源信息,然后将用户和资源等参数传递到服务端。

服务端流程:

  1. 服务端在收到请求后,首先检查是否开启授权,若未开启,则不校验直接通过;若已开启了,则进入下一步。
  2. 服务端对请求中和授权相关的参数进行解析和组装,这些数据包括用户信息、访问的资源、执行的操作,以及请求的环境等。
  3. 通过用户名在本地数据存储中查询用户相关信息,若用户不存在,则返回错误;若用户存在,则进入下一步。
  4. 判断当前用户是否是超级用户,若超级用户,则直接通过请求,无需做授权检查,若普通用户,则进入下一步进行详细的授权检查。
  5. 根据用户名获取相关的授权策略列表,并对本次请求的资源、操作,以及环境进行匹配,同时按照优先级进行排序。
  6. 根据优先级最高的授权策略做出决策,若授权策略允许该操作,则返回授权成功,若拒绝该操作,则返回无权限错误。

授权参数的解析

在 ACL 2.0 中,更具操作类型和请求频率,对授权相关参数(包括资源、操作等)的解析进行了优化。

1. 硬编码方式解析

对于消息发送和消费这类接口,参数相对较为复杂,且请求频次也相对较高。考虑到解析的便捷性和性能上的要求,采用硬编码的方式进行解析。

2. 注解方式解析

对于大量的管控接口,采用硬编码的方式工作量巨大,且这些接口调用频次较低,对性能要求不高,所以采用注解的方式进行解析,提高编码效率。

权限策略优先级

在权限策略匹配方面,由于支持了模糊的资源匹配模式,可能出现同一个资源对应多个权限策略。因此,需要一套优先级的机制来确定最终使用哪一套权限策略。

假设配置了以下授权策略,按照以上优先级资源的匹配情况如下:

认证授权策略

出于安全和性能的权衡和考虑,RocketMQ ACL 2.0 为认证和授权提供了两种策略:无状态认证授权策略(Stateless)和有状态认证授权策略(Stateful)。

无状态认证授权策略(Stateless): 在这种策略下,每个请求都会经过独立的认证和授权过程,不依赖于任何先前的会话和状态信息。这种严格的策略可以保证更高级别的安全保证。对权限进行变更,可以更加实时的反应在随后的请求中,无需任何等待。然而,这种策略在高吞吐的场景中可能会导致显著的性能负担,如增加系统 CPU 的使用率以及请求的耗时。

有状态认证授权策略(Stateful): 在这种策略下,同一个客户端连接,相同资源以及相同的操作下,第一次请求会经过完整的认证和授权,后续请求则不再进行重复认证和授权。这种方法可以有效地降低性能小号,减少请求的耗时,特别适合吞吐量较高的场景。但是,这种策略可能引入了安全上的妥协,对权限的变更也无法做到实时的生效。

在这两者策略的选择上,需要权衡系统的安全性要求和性能需求。如果系统对安全性的要求很高,并且可以容忍一定的性能损耗,那么无状态认证授权策略可能是更好的选择。相反,如果系统需要处理大量的并发请求,且可以在一定程度上放宽安全要求,那么有状态认证授权策略可能更合适。在实际部署时,还应该结合具体的业务场景和安全要求来做出决策。

插件化机制

为了适应未来持续发展的认证鉴权方式,以及满足用户针对特定场景的定制需求,RocketMQ ACL 2.0 在多个环节上提供了灵活性和可扩展性。

认证和授权策略的扩展:默认情况下,RocketMQ ACL 2.0 提供了无状态认证授权策略(Stateless)和有状态认证授权策略(Stateful),以满足绝大多数用户对安全和性能的要求。但是,后续仍然可以探索出更优的策略,来兼顾安全和性能之间的平衡。

认证和授权方式的扩展:当前,在认证方面,市场上已经沉淀了多种成熟的实现,RocketMQ 目前只实现了其中一种,通过插件化的能力进行预留,未来可以轻松的引入更多的认证机制。在授权方面,RocketMQ 基于 ABAC 模型实现了一套主流的授权方式,以适应广泛的用户需求。但也提供了插件化的能力,方便未来能适配出更多贴合未来发展的解决方案。

认证和授权流程的编排:基于责任链设计模式,RocketMQ ACL 2.0 对其默认的认证和授权流程进行了灵活的编排。用户可以扩展或重写这些责任链节点,从而能够定制针对其具体业务场景的认证和授权逻辑。

用户和权限存储的扩展:RocketMQ 默认采用 RocksDB 在 Broker 节点上本地存储用户和权限数据。然而,通过实现预定义的接口,用户可以轻松地将这些数据迁移至任何第三方服务或存储系统中,从而优化其架构设计和操作效率。

审计日志

审计日志,用于记录和监控所有关于认证和授权的访问控制操作。通过升级日志,我们可以追踪到每一个访问的请求,确保系统的可靠性和安全性,同时,它也有助于问题的排查,进行安全的升级和满足合规的要求。

RocketMQ ACL 2.0 对认证和授权相关的审计日志都进行了支持,格式如下:

认证日志

# 认证成功日志
[AUTHENTICATION] User:rocketmq is authenticated success with Signature = eMX/+tH/7Bc0TObtDYMcK9Ls+gg=.

# 认证失败日志
[AUTHENTICATION] User:rocketmq is authenticated failed with Signature = eMX/+tH/7Bc0TObtDYMcK9Ls+xx=.

授权日志

# 授权成功日志
[AUTHORIZATION] Subject = User:rocketmq is Allow Action = Pub from sourceIp = 192.168.0.2 on resource = Topic:TP-TEST for request = 10.

# 授权失败日志
[AUTHORIZATION] Subject = User:rocketmq is Deny Action = Sub from sourceIp = 192.168.0.2 on resource = Topic:GID-TEST for request = 10.

配置与使用

部署架构

在部署架构方面,RocketMQ 提供了两种部署形态,分别是存算一体架构和存算分离架构。

存算一体架构

在 RocketMQ 存算一体架构中,Broker 组件同时承担了计算和存储的职责,并对外提供服务,接收所有客户端的访问请求。因此,由 Broker 组件承担认证和授权的重要角色。此外,Broker 组件还负责认证和授权相关的元数据的维护和存储。

存算分离架构

在 RocketMQ 存算分离架构中,存储由 Broker 组件负责,计算由 Proxy 组件负责,所有的对外请求都是由 Proxy 对外进行服务。因此,请求的认证和授权都由 Proxy 组件承担。Broker 承担元数据存储,为 Proxy 组件提供所需的认证和授权元数据的查询和管理服务。

集群配置

认证配置

参数列表

想要在服务端开启认证功能,相关的参数和使用案例主要包含如下:

Broker 配置

authenticationEnabled = true
authenticationProvider = org.apache.rocketmq.auth.authentication.provider.DefaultAuthenticationProvider
initAuthenticationUser = {"username":"rocketmq","password":"12345678"}
innerClientAuthenticationCredentials = {"accessKey":"rocketmq","secretKey":"12345678"}
authenticationMetadataProvider = org.apache.rocketmq.auth.authentication.provider.LocalAuthenticationMetadataProvider

Proxy 配置

{
  "authenticationEnabled": true,
  "authenticationProvider": "org.apache.rocketmq.auth.authentication.provider.DefaultAuthenticationProvider",
  "authenticationMetadataProvider": "org.apache.rocketmq.proxy.auth.ProxyAuthenticationMetadataProvider",
  "innerClientAuthenticationCredentials": "{\"accessKey\":\"rocketmq\", \"secretKey\":\"12345678\"}"
}

授权配置

参数列表

想要在服务端开启授权功能,相关的参数和使用案例主要包含如下:

Broker 配置

authorizationEnabled = true
authorizationProvider = org.apache.rocketmq.auth.authorization.provider.DefaultAuthorizationProvider
authorizationMetadataProvider = org.apache.rocketmq.auth.authorization.provider.LocalAuthorizationMetadataProvider

Proxy 配置

{
  "authorizationEnabled": true,
  "authorizationProvider": "org.apache.rocketmq.auth.authorization.provider.DefaultAuthorizationProvider",
  "authorizationMetadataProvider": "org.apache.rocketmq.proxy.auth.ProxyAuthorizationMetadataProvider"
}

如何使用

命令行使用

用户管理

关于 ACL 用户的管理,相关的接口定义和使用案例如下。

接口定义

使用案例

# 创建用户
sh mqadmin createUser -n 127.0.0.1:9876 -c DefaultCluster -u rocketmq -p rocketmq
# 创建用户,指定用户类型
sh mqadmin createUser -n 127.0.0.1:9876 -c DefaultCluster -u rocketmq -p rocketmq -t Super
# 更新用户
sh mqadmin updateUser -n 127.0.0.1:9876 -c DefaultCluster -u rocketmq -p 12345678
# 删除用户
sh mqadmin deleteUser -n 127.0.0.1:9876 -c DefaultCluster -u rocketmq
# 查询用户详情
sh mqadmin getUser -n 127.0.0.1:9876 -c DefaultCluster -u rocketmq
# 查询用户列表
sh mqadmin listUser -n 127.0.0.1:9876 -c DefaultCluster
# 查询用户列表,带过滤条件
sh mqadmin listUser -n 127.0.0.1:9876 -c DefaultCluster -f mq

ACL 管理

关于 ACL 授权的管理,相关的接口定义和使用案例如下。

接口定义

使用案例

# 创建授权
sh mqadmin createAcl -n 127.0.0.1:9876 -c DefaultCluster -s User:rocketmq -r Topic:*,Group:* -a Pub,Sub -i 192.168.1.0/24 -d Allow
# 更新授权
sh mqadmin updateAcl -n 127.0.0.1:9876 -c DefaultCluster -s User:rocketmq -r Topic:*,Group:* -a Pub,Sub -i 192.168.1.0/24 -d Deny
# 删除授权
sh mqadmin deleteAcl -n 127.0.0.1:9876 -c DefaultCluster -s User:rocketmq
# 删除授权,指定资源
sh mqadmin deleteAcl -n 127.0.0.1:9876 -c DefaultCluster -s User:rocketmq -r Topic:*
# 查询授权列表
sh mqadmin listAcl -n 127.0.0.1:9876 -c DefaultCluster
# 查询授权列表,带过滤条件
sh mqadmin listAcl -n 127.0.0.1:9876 -c DefaultCluster -s User:rocketmq -r Topic:*
# 查询授权详情
sh mqadmin getAcl -n 127.0.0.1:9876 -c DefaultCluster -s User:rocketmq

客户端使用

关于 ACL 的使用,ACL 2.0 和 ACL 1.0 的使用方式一样,没有任何区别,具体参考官方案例。

消息发送

ClientServiceProvider provider = ClientServiceProvider.loadService();
StaticSessionCredentialsProvider sessionCredentialsProvider = 
  new StaticSessionCredentialsProvider(ACCESS_KEY, SECRET_KEY);
ClientConfiguration clientConfiguration = ClientConfiguration.newBuilder()
    .setEndpoints(ENDPOINTS)
    .setCredentialProvider(sessionCredentialsProvider)
    .build();
Producer producer = provider.newProducerBuilder()
    .setClientConfiguration(clientConfiguration)
    .setTopics(TOPICS)
    .build();

消息消费

展开阅读全文

本文系作者在时代Java发表,未经许可,不得转载。

如有侵权,请联系nowjava@qq.com删除。

编辑于

关注时代Java

关注时代Java