升级到 Pulsar3.0 后深入了解 JWT 鉴权
背景
最近在测试将 Pulsar
2.11.2 升级到 3.0.1
的过程中碰到一个鉴权问题,正好借着这个问题充分了解下 Pulsar
的鉴权机制是如何运转的。
Pulsar 支持 Namespace/Topic
级别的鉴权,在生产环境中往往会使用 topic
级别的鉴权,从而防止消息泄露或者其他因为权限管控不严格而导致的问题。
我们会在创建 topic
的时候为 topic
绑定一个应用,这样就只能由这个应用发送消息,其他的应用尝试发送消息的时候会遇到 401 鉴权的异常。
同理,对于订阅者也可以关联指定的应用,从而使得只有规定的应用可以消费消息。
鉴权流程
以上的两个功能本质上都是通过 Pulsar
的 admin-API
实现的。
这里关键的就是 role
,在我们的场景下通常是一个应用的 AppId
,只要是一个和项目唯一绑定的 ID
即可。
这只是授权的一步,整个鉴权流程图如下:
详细步骤
生成公私钥
bin/pulsar tokens create-key-pair --output-private-key my-private.key --output-public-key my-public.key
将公钥分发到 broker
的节点上,鉴权的时候 broker
会使用公钥进行验证。
而私钥通常是管理员单独保存起来用于在后续的步骤为客户端生成 token
使用私钥生成 token
之后我们便可以使用这个私钥生成 token
了:
bin/pulsar tokens create --private-key file:///path/to/my-private.key \
--subject 123456
eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJhZG1pbiJ9
其中的
subject
和本文长提到的role
相等
使用 subject 授权
只是单纯生成了 token
其实并没有什么作用,还得将 subject
(role) 与 topic
进行授权绑定。
也就是上图的这个步骤。
这里创建的
admin
客户端也得使用一个superRole
角色的token
才有权限进行授权。
superRole
使用在broker.conf
中进行配置。
客户端使用 token 接入 broker
PulsarClient client = PulsarClient.builder()
.serviceUrl("pulsar://broker.example.com:6650/")
.authentication(AuthenticationFactory.token("eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJKb2UifQ.ipevRNuRP6HflG8cFKnmUPtypruRC4fb1DWtoLL62SY"))
.build();
使用刚才私钥生成的 token 接入 broker 才能生产或者消费数据。
originalPrincipal cannot be a proxy role
这些流程正常都没啥问题,但直到我升级了 Pulsar3.0
后客户端直接就连不上了。
在 broker
中看到了 WARN
的警告日志:
cannot specify originalPrincipal when connecting without valid proxy role
之后在 3.0 的升级日志中看到相关的 Issue。
从这个 PR 相关的代码和变更的文档可以得知:
升级到 3.0 之后风险校验等级提高了,proxyRole
这个字段需要在 broker
中进行指定(之前的版本不需要强制填写)。
因为我们使用了 Proxy 组件,所有的请求都需要从 proxy 中转一次,这个 proxyRole 是为了告诉 broker:只有使用了 proxyRole
作为 token
的 Proxy
才能访问 broker,这样保证了 broker
的安全。
superUserRoles: broker-admin,admin,proxy-admin
proxyRoles: proxy-admin
以上是我的配置,我的 Proxy 配置的也是 proxy-admin
这个 token,所以理论上是没有问题的,但依然鉴权失败了,查看 broker 的日志后拿到以下日志:
Illegal combination of role [proxy-admin] and originalPrincipal [proxy-admin]: originalPrincipal cannot be a proxy role.
排查了许久依然没有太多头绪,所以我提了相关的 issue:
https://github.com/apache/pulsar/issues/21583
之后我咨询了 Pulsar
的 PMC @Technoboy 在他的提示下发现我在测试的时候使用的是 proxy-admin
,正好和 proxyRoles
相等。
阅读源码和这个 PR
的 comment
之后得知:
也就是说客户端不能使用和 proxyRole
相同的角色进行连接,这个角色应当也只能给 Proxy
使用,这样的安全性才会高。
所以这个 Comment 还在讨论这是一个 breaking change?
还是一个增强补丁。
因为合并这个 PR 后对没有使用 proxyRole
的客户端将无法连接,同时也可能出现我这种 proxyRole
就是客户端使用的角色,这种情况也会鉴权失败。
所以我换了一个 superRole 角色就可以了,比如换成了 admin
。
但其实即便是放到我们的生产系统,只要配置了
proxyRole
也不会有问题,因为我们应用所使用的 role 都是不这里的superUserRole
,全部都是使用AppId
生成的。
token 不一致
但也有一个疑惑,我在换为存放在 configmap
中的 admin token 之前(测试环境使用的是 helm 安装集群,所以这些 token 都是存放在 configmap 中的),
为了验证是否只要非 proxyRole
的 superRole
都可以使用,我就自己使用了私钥重新生成了一个 admin
的 token
。
bin/pulsar tokens create --private-key file:///pulsar/private/private.key --subject admin
这样生成的 token
也是可以使用的,但是我将 token 复制出来之后却发现 helm 生成的 token
与我用 pulsar
命令行生成的 token
并不相同。
为了搞清楚为什么 token 不同但鉴权依然可以通过的原因,之后我将 token decode之后知道了原因:
原来是 Header 不同从而导致最终的 token 不同,helm 生成的 token
中多了一个 typ 字段。
之后我检查了 helm 安装的流程,发现原来 helm 的脚本中使用的并不是 Java 的命令行工具:
${PULSARCTL_BIN} token create -a RS256 --private-key-file ${privatekeytmpfile} --subject ${role} 2&> ${tokentmpfile}
这个 PULSARCTL_BIN
是一个由 Go 写的命令行工具,我查看了其中的源码,才知道 Go 的 JWT 工具会自带一个 header。
https://github.com/streamnative/pulsarctl
而 Java
是没有这个逻辑的,但也只是加了 header
,payload
的值都是相同的。
这样也就解释了为什么 token
不同但确依然能使用的原因。
升级到 Pulsar3.0 后深入了解 JWT 鉴权的更多相关文章
- xcode7.3 升级 xcode8.0 后权限设置问题(升级xcode 8.0 后构建版本不显示问题)
xcode7.3 升级 xcode8.0 后权限设置问题(升级xcode 8.0 后构建版本不显示问题) 前两天为了适配 iOS10 的系统 我将xcode 7.3 升级到了 xcode 8.0 但是 ...
- thinkjs升级到3.0后的图片上传
似乎当thinkjs升级到3.0后,才接手了一个项目.只是在实际运用过程中,还是发现了与2.2的些许差别——今天先分享关于图片上传的一些问题. 1.上传文件,我们选择了jQuery的插件:http:/ ...
- springboot升级到2.0后context-path配置不起作用
springboot升级到2.0后,context-path配置不起作用,改成了: server.servlet.context-path=/projname
- Android Studio 升级到3.0后出现编译错误\.gradle\caches\transforms-1\files-1.1\*****-release.aar
Android Studio 升级到3.0后出现各种编译问题,其中有一个问题是关于资源找不到的问题,百度了半天,也没有相关的文章 C:\Users.gradle\caches\transforms-1 ...
- HTTP基本认证和JWT鉴权
一.HTTP基本认证 Basic Authentication——当浏览器访问使用基本认证的网站的时候, 浏览器会提示你输入用户名和密码. http auth的过程: · 客户端发送http请求 · ...
- Spring Boot 鉴权之—— JWT 鉴权
第一:什么是JWT鉴权 1. JWT即JSON Web Tokens,是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519),他可以用来安全的传递信息,因为传递的信息是 ...
- JWT鉴权
一.HTTP基本认证 Basic Authentication--当浏览器访问使用基本认证的网站的时候, 浏览器会提示你输入用户名和密码. http auth的过程: 客户端发送http请求 服务器发 ...
- jwt鉴权学习 (php示例代码)
前段时间听朋友讲起 jwt鉴权,博主我是一脸懵逼,通过朋友坚持不懈的讲解,我终于听懂了,jwt就是登陆token校验嘛 然而事情并不是博主想象的那么简单,在一个艳阳高照,晴空万里的夜晚,博主手贱百度了 ...
- 关于Android Studio升级到2.0后和Gradle插件不兼容的问题
今天升级AS到2.0后,用AS在真机上调试,发现报了如下错误: This version of Android Studio is incompatible with the Gradle Plugi ...
- springboot 升级到2.0后 context-path 配置 不起作用,不生效 不管用 皆是因为版本改动导致的在这里记录一下
不知不觉,新的项目已经将springboot升级为2.0版本了.刚开始没有配置server.contextpath,默认的“/”,然后今天放到自己的服务器上,所以就要规范名称. 结果,失败了,无论我 ...
随机推荐
- 没有显示器可用的电脑找IP
一台在手边没有显示器可用的电脑找IP记录 问题 老大给我一台服务器(在我前面的工位)让我自己玩,但是不知道IP地址,我本来想用自己的显示器连上,结果两个DHMI口试过都没反应,不知道ip地址就没法连上 ...
- SpringBoot 启动流程分析(寻找扩展点)
1.SpringBoot maven 依赖版本 <?xml version="1.0" encoding="UTF-8"?> <project ...
- Vue笔记(一)
1. Vue.js是什么? 1). 一位华裔前Google工程师(尤雨溪)开发的前端js库 2). 作用: 动态构建用户界面 3). 特点: * 遵循MVVM模式 * 编码简洁, 体积小, 运行效率高 ...
- 使用TypeScript类型注解,编写更干净的JS代码
TypeScript 可以看作是 JavaScript 的超集,不仅包含了 JavaScript 的所有内容,还拓展了语法.规定了类型约束,使得我们可以编写更干净.完整的代码. 类型注解 TypeSc ...
- Apache solr XML 实体注入漏洞(CVE-2017-12629)
描述: Apache Solr 是一个开源的搜索服务器.Solr 使用 Java 语言开发,主要基于 HTTP 和 Apache Lucene 实现.原理大致是文档通过Http利用XML加到一个搜索集 ...
- quarkus依赖注入之十三:其他重要知识点大串讲(终篇)
欢迎访问我的GitHub 这里分类和汇总了欣宸的全部原创(含配套源码):https://github.com/zq2599/blog_demos 本篇概览 本篇是<quarkus依赖注入> ...
- shopee根据ID取商品详情 API
item_get-根据ID取商品详情 注册开通 shopee.item_get 公共参数 名称 类型 必须 描述 key String 是 调用key(必须以GET方式拼接在URL中) secr ...
- CodeForces 1187E Tree Painting
题意:给定一棵\(n\)个点的树 初始全是白点 要求你做\(n\)步操作,每一次选定一个与一个黑点相隔一条边的白点,将它染成黑点,然后获得该白点被染色前所在的白色联通块大小的权值. 第一次操作可以任意 ...
- 国内镜像安装Python解释器及扩展包
一.下载Python解释器 1.下载地址 官网(下载速度很慢):Welcome to Python.org 淘宝镜像(推荐):CNPM Binaries Mirror (npmmirror.com) ...
- Tcp/Ip协议 A类B类C类D类 地址
TCP(传输控制协议):负责和远程主机连接 Ip(网际协议):负责寻址,使报文发送到其该在的地方 Ip地址:是TCP/IP的网络层用以标识网络中主机的逻辑地址,可以唯一标识Interent中的一台主 ...