Apache Pulsar学习笔记12: 开启基于JWT的身份认证
2021-11-04
Pulsar支持可插拔的身份认证和授权机制,Pulsar Proxy或者Pulsar Broker都支持该机制。认证和授权机制一起保证了客户端对Pulsar Topic、命名空间、租户的访问权限。
默认情况下,Pulsar并不会启用加密、身份认证和授权机制。之前我们使用pulsar-admin
,pulsar-client
等命令行工具,使用Java或Go语言开发的Consumer和Produmer,访问使用docker容器启动的单机Pulsar时,都未用到任何身份认证信息。
也就是说,Pulsar的默认配置是完全开放状态的,任何人都可以访问它。因此,必须启用Pulsar的认证和授权机制,为Pulsar各个组件开启安全防护。
本节先学习Pulsar的认证机制。
身份认证相关的概念 #
角色(Role): 在Pulsar中角色标识就是一个字符串,例如admin
, app1
,每个角色都标识了一个或多个Pulsar客户端。角色标识是身份认证和授权的主体(subject)。
身份认证提供者(Authentication Provider): Pulsar使用身份认证提供者来建立客户端的身份,然后将角色Token分配给该客户端。 当前Pulsar支持以下身份验证提供者:
- TLS认证
- Athenz
- Kerberos
- JWT认证
本节将只学习如何为Pulsar开启基于JWT的身份认证。
开启JWT Token认证 #
JWT支持通过两种不同的秘钥生成和验证Token:
- 对称秘钥:
- 使用单个Secret key来生成和验证Token
- 非对称秘钥:包含由私钥和公钥组成的一对密钥
- 使用Private key生成Token
- 使用Public key验证Token
这里使用非对称秘钥即公钥和私钥的形式。首先要由Pulsar的系统管理员生成密钥对。 在Pulsar的安装目录里使用下面的命令生成密钥对:
1bin/pulsar tokens create-key-pair --output-private-key ./conf/jwt-private.key --output-public-key ./conf/jwt-public.key
这里生成密钥对jwt-private.key
和jwt-public.key
到了Pulsar安装目录的conf目录下,注意需要把jwt-private.key
保存到一个安全的位置,确保只有管理员才能能使用它来创建新的Token。
jwt-public.key
则会分发给所有的Broker,Broker将用它来验证Token。
先使用私钥来创建一个管理员用户的Token:
1bin/pulsar tokens create --private-key ./conf/jwt-private.key --subject admin
2eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJhZG1pbiJ9.ZTR5pCrUXZ083QUvtW9wq5Otrh8PvLpi5L8xWJKVlgWS_U9PDjNStgQFLyx1cv7xlfEPwi3ep41MyMdDXWLzVvY_UolfPPpNpUiGHbdwchqgQ3bkdUubAoF4FxXNj22UweRDB_Jp_gz1VDc_4fiN85kjLgD7cS6XUM-D1Banq6Ll2GL532YJQkjAXk7DlWiWAYZIJP8tzNSGmlx8NzxwjFya1SxC-G3zsztfmkLFBYY6woHuBWAY62cJemHu9hRIj1qTagW5O3UIjtab92Ir44mT_YudfYcQA4g4k6eMeHSSny_k9v76x3WqTmUV4TImEUQN8ZfIYFrDTx92HVsVvQ
再使用私钥来创建一个普通用户的Token:
1bin/pulsar tokens create --private-key ./conf/jwt-private.key --subject test-user
2
3eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJ0ZXN0LXVzZXIifQ.ZXbMZ4OTXgJFN5tmw8jLd43spaiDYjbd4lmGTLd2_ge0C3V_lVsyv1VSGC5NNn5cik1rkQTS6dRHQ_GzczCCNNdvKr2z5zEFnCdqO8dRtFXliXALMwpno7epctKHa9TvRzozkmYw3zIKCXdjK9WEKkROyiJmqpCrKUOqXiEYH_oFMgBGAacy8VAkjSQlU8BhXGPhnKvLNolH41XRIkHP5EMcxaOC7NPQjDD-oucH2iCnz4AftBhGmredNBzReztZYN0-RvHCS-dwWwwrqO1Zxlnh1BfTSQblEkTMtaG_qiqRNg_gD6CGCp2oJdcv_p2pndgPmgPIuYpIGpgVP_HXGQ
注意这里的subject就是前面说的角色
。另外创建token的时候还可以通过--expiry-time
参数为token设置一个有效期,例如bin/pulsar tokens create --private-key ./conf/jwt-private.key --subject test-user --expiry-time 1y
将创建一年有效期的Token。
上面的命令虽然已经创建了一个Token,但是Token本身并不会关联任何权限。Pulsar中的权限是和角色相关联的,可以使用pulsar-admin
对角色(即Token中的主体)进行授权,例如下面的命令对普通用户test-user
进行授权,允许test-user
对my-tenant/my-namespace
下的topic执行produce和consume操作:
1bin/pulsar-admin namespaces grant-permission my-tenant/my-namespace --role test-user --actions produce,consume
在创建了Token,并对Token中的主体进行授权之后,就可以在Broker上开启认证了。要让Broker开启认证只需要在broker.conf
配置文件中添加如下的配置:
1# 启用认证和鉴权
2authenticationEnabled=true
3authorizationEnabled=true
4authenticationRefreshCheckSeconds=60
5authenticationProviders=org.apache.pulsar.broker.authentication.AuthenticationProviderToken
6
7# 设置Broker自身的认证, Broker连接其他Broker时用到
8brokerClientAuthenticationPlugin=org.apache.pulsar.client.impl.auth.AuthenticationToken
9brokerClientAuthenticationParameters={"token":"eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJhZG1pbiJ9.ZTR5pCrUXZ083QUvtW9wq5Otrh8PvLpi5L8xWJKVlgWS_U9PDjNStgQFLyx1cv7xlfEPwi3ep41MyMdDXWLzVvY_UolfPPpNpUiGHbdwchqgQ3bkdUubAoF4FxXNj22UweRDB_Jp_gz1VDc_4fiN85kjLgD7cS6XUM-D1Banq6Ll2GL532YJQkjAXk7DlWiWAYZIJP8tzNSGmlx8NzxwjFya1SxC-G3zsztfmkLFBYY6woHuBWAY62cJemHu9hRIj1qTagW5O3UIjtab92Ir44mT_YudfYcQA4g4k6eMeHSSny_k9v76x3WqTmUV4TImEUQN8ZfIYFrDTx92HVsVvQ"}
10
11authenticateOriginalAuthData=true
12
13superUserRoles=admin
14tokenPublicKey=/pulsar/conf/jwt-public.key
上面的第9行配置的token为前面创建的admin的token,
superUserRoles
指定admin
用户为超级用户
注意集群部署的Pulsar,在Broker上开启认证修改的是各个Broker节点的broker.conf
配置文件,对于使用docker容器启动的单机Pulsar,需要修改的配置文件是standalone.conf
。
配置命令行工具 #
上面为broker开启认证以后,再使用pulsar-admin
就会报认证授权失败的错误,例如下面查看命名空间权限配置的命令:
1bin/pulsar-admin namespaces permissions my-tenant/my-namespace
2
3HTTP 401 Unauthorized
4Reason: HTTP 401 Unauthorized
需要在client.conf
中做如下配置:
1webServiceUrl=http://localhost:8080/
2brokerServiceUrl=pulsar://localhost:6650/
3authPlugin=org.apache.pulsar.client.impl.auth.AuthenticationToken
4authParams=token:eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJhZG1pbiJ9.ZTR5pCrUXZ083QUvtW9wq5Otrh8PvLpi5L8xWJKVlgWS_U9PDjNStgQFLyx1cv7xlfEPwi3ep41MyMdDXWLzVvY_UolfPPpNpUiGHbdwchqgQ3bkdUubAoF4FxXNj22UweRDB_Jp_gz1VDc_4fiN85kjLgD7cS6XUM-D1Banq6Ll2GL532YJQkjAXk7DlWiWAYZIJP8tzNSGmlx8NzxwjFya1SxC-G3zsztfmkLFBYY6woHuBWAY62cJemHu9hRIj1qTagW5O3UIjtab92Ir44mT_YudfYcQA4g4k6eMeHSSny_k9v76x3WqTmUV4TImEUQN8ZfIYFrDTx92HVsVvQ
因为这里是为命令行工具pulsar-admin
访问身份,所以authParams
中的token配置的是admin的token。
再次使用查看命名空间权限配置的命令测试,可以正常使用了:
1bin/pulsar-admin namespaces permissions my-tenant/my-namespace
2"test-user [produce, consume]"
Pulsar的Java和Go客户端 #
Broker开启JWT认证后,在使用各个编程语言创建Pulsar Client时,就需要设置具体的Token了。
Java的示例代码如下:
1PulsarClient client = PulsarClient.builder()
2 .serviceUrl("pulsar://broker.example.com:6650/")
3 .authentication(
4 AuthenticationFactory.token("eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJ0ZXN0LXVzZXIifQ.ZXbMZ4OTXgJFN5tmw8jLd43spaiDYjbd4lmGTLd2_ge0C3V_lVsyv1VSGC5NNn5cik1rkQTS6dRHQ_GzczCCNNdvKr2z5zEFnCdqO8dRtFXliXALMwpno7epctKHa9TvRzozkmYw3zIKCXdjK9WEKkROyiJmqpCrKUOqXiEYH_oFMgBGAacy8VAkjSQlU8BhXGPhnKvLNolH41XRIkHP5EMcxaOC7NPQjDD-oucH2iCnz4AftBhGmredNBzReztZYN0-RvHCS-dwWwwrqO1Zxlnh1BfTSQblEkTMtaG_qiqRNg_gD6CGCp2oJdcv_p2pndgPmgPIuYpIGpgVP_HXGQ"))
5 .build();
Go的示例代码如下:
1client, err := NewClient(ClientOptions{
2 URL: "pulsar://localhost:6650",
3 Authentication: NewAuthenticationToken("eyJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJ0ZXN0LXVzZXIifQ.ZXbMZ4OTXgJFN5tmw8jLd43spaiDYjbd4lmGTLd2_ge0C3V_lVsyv1VSGC5NNn5cik1rkQTS6dRHQ_GzczCCNNdvKr2z5zEFnCdqO8dRtFXliXALMwpno7epctKHa9TvRzozkmYw3zIKCXdjK9WEKkROyiJmqpCrKUOqXiEYH_oFMgBGAacy8VAkjSQlU8BhXGPhnKvLNolH41XRIkHP5EMcxaOC7NPQjDD-oucH2iCnz4AftBhGmredNBzReztZYN0-RvHCS-dwWwwrqO1Zxlnh1BfTSQblEkTMtaG_qiqRNg_gD6CGCp2oJdcv_p2pndgPmgPIuYpIGpgVP_HXGQ"),
4})