用户认证功能,是一个成熟组件不可或缺的功能。在0.9版本以前kafka是没有用户认证模块的(或者说只有SSL),好在kafka0.9版本以后逐渐发布了多种用户认证功能,弥补了这一缺陷(这里仅介绍SASL)。

本篇会先介绍当前kafka的四种认证方式,然后过一遍部署SASL/PLAIN认证功能的流程。最后再介绍如如何使用kafka2.x新推出的callback api,对SASL/PLAIN功能进行二次开发。

kafka 2.x用户认证方式小结

需要先明确的一点是,用户认证和权限控制是两码事。用户认证是确认这个用户能否访问当前的系统,而权限控制是控制用户对当前系统中各种资源的访问权限。用户认证就是今天要讲的内容,而kafka的权限控制,则是对应bin/kafka-acls.sh工具所提供的一系列功能,这里不详细展开。

标题特地说明kafka2.x是因为kafka2.0的时候推出一种新的用户认证方式,SASL/OAUTHBEARER,在此前的版本是不存在这个东西的。那么加上这个之后,kafka目前共有4种常见的认证方式。

  • SASL/GSSAPI(kerberos):kafka0.9版本推出,即借助kerberos实现用户认证,如果公司恰好有kerberos环境,那么用这个是比较合适的。
  • SASL/PLAIN:kafka0.10推出,非常简单,简单得有些鸡肋,不建议生产环境使用,除非对这个功能二次开发,这也是我后面要讲的。
  • SASL/SCRAM:kafka0.10推出,全名Salted Challenge Response Authentication Mechanism,为解决SASL/PLAIN的不足而生,缺点可能是某些客户端并不支持这种方式认证登陆(使用比较复杂)。
  • SASL/OAUTHBEARER:kafka2.0推出,实现较为复杂,目前业内应该较少实践。

其实除了上述四种用户认证功能之外,还有一个叫Delegation Token的东西。这个东西说一个轻量级的工具,是对现有SASL的一个补充,能够提高用户认证的性能(主要针对Kerberos的认证方式)。算是比较高级的用法,一般也用不到,所以也不会多介绍,有兴趣可以看这里Authentication using Delegation Tokens

SASL/GSSAPI

如果已经有kerberos的环境,那么会比较适合使用这种方式,只需要让管理员分配好principal和对应的keytab,然后在配置中添加对应的选项就可以了。需要注意的是,一般采用这种方案的话,zookeeper也需要配置kerberos认证。

SASL/PLAIN

这种方式其实就是一个用户名/密码的认证方式,不过它有很多缺陷,比如用户名密码是存储在文件中,不能动态添加,明文等等!这些特性决定了它比较鸡肋,但好处是足够简单,这使得我们可以方便地对它进行二次开发。本篇文章后续会介绍SASL/PLAIN的部署方式和二次开发的例子(基于kafka2.x)。

SASL/SCRAM

针对PLAIN方式的不足而提供的另一种认证方式。这种方式的用户名/密码是存储中zookeeper的,因此能够支持动态添加用户。该种认证方式还会使用sha256或sha512对密码加密,安全性相对会高一些。

而且配置起来和SASL/PLAIN差不多同样简单,添加用户/密码的命令官网也有提供,个人比较推荐使用这种方式。不过有些客户端是不支持这个方式认证登陆的,比如python的kafka客户端,这点需要提前调研好。

具体的部署方法官网或网上有很多,这里不多介绍,贴下官网的Authentication using SASL/SCRAM

SASL/OAUTHBEARER

SASL/OAUTHBEARER是基于OAUTH2.0的一个新的认证框架,这里先说下什么是OAUTH吧,引用维基百科。

OAuth是一个开放标准,允许用户让第三方应用访问该用户在某一网站上存储的私密的资源(如照片,视频,联系人列表),而无需将用户名和密码提供给第三方应用。而 OAUTH2.0算是OAUTH的一个加强版。

说白了,SASL/OAUTHBEARER就是一套让用户使用第三方认证工具认证的标准,通常是需要自己实现一些token认证和创建的接口,所以会比较繁琐。

详情可以通过这个kip了解KIP-255

说了这么多,接下来就说实战了,先介绍下如何配置SASL/PLAIN。

SASL/PLAIN实例(配置及客户端)

broker配置

kafka_server_jaas.conf

这里简单介绍下SASL/PLAIN的部署方式,另外除了SASL/OAUTHBEARER,其他几种应该也是类似的部署方式,基本都是大同小异。

PS:本配置版本适用于kafka2.x,且无需配置zk认证

kafka的用户认证,是基于java的jaas。所以我们需要先添加jaas服务端的配置文件。在kafka_home/config/kafka_server_jaas.conf中添加以下配置信息:

KafkaServer {
org.apache.kafka.common.security.plain.PlainLoginModule required
username="admin"
password="admin-secret"
user_admin="admin-secret"
user_alice="alice-secret";
};

注意最后一个属性后面需要加封号!配置是不难理解的,第一行指定PlainLoginModule,算是声明这是一个SASL/PLAIN的认证类型,如果是其他的,那么就需要reqired其他的类。usernamepassword则是用于集群内部broker的认证用的。

这里会让人疑惑的,应该是user_adminuser_alice这两个属性了。这个其实是用来定义用户名和密码的,形式是这样:user_userName=password。所以这里其实是定义了用户admin和用户alice到密码。

这一点可以在源码的PlainServerCallbackHandler类中找到对应的信息,kafka源码中显示,对用户认证的时候,就会到jaas配置文件中,通过user_username属性获取对应username用户的密码,再进行校验。当然这样也导致了该配置文件只有重启才会生效,即无法动态添加用户。

说回来,写完配置后,需要在kafka的配置中添加jaas文件的路径。在kafka_home/bin/kafka-run-class.sh中,找到下面的配置,修改KAFKA_OPTS到配置信息。

# Generic jvm settings you want to add
if [ -z "$KAFKA_OPTS" ]; then
KAFKA_OPTS=""
fi

将上述到KAFKA_OPTS修改为

KAFKA_OPTS="-Djava.security.auth.login.config=kafka_home/config/kafka_server_jaas.conf"

server.properties

然后修改kafka_home/config/server.properties

listeners=SASL_PLAINTEXT://host.name:port
security.inter.broker.protocol=SASL_PLAINTEXT
sasl.mechanism.inter.broker.protocol=PLAIN
sasl.enabled.mechanisms=PLAIN

其中SASL_PLAINTEXT的意思,是明文传输的意思,如果是SSL,那么应该是SASL_SSL。

这样就算是配置好kafka broker了,接下来启动kafka,观察输出日志,没有错误一般就没问题了。

客户端配置

以producer为例,只需要在kafka_home/config/producer.properties中添加jaas认证信息,以及用户名密码:

sasl.jaas.config=org.apache.kafka.common.security.plain.PlainLoginModule required \
username="alice" \
password="alice-secret"; security.protocol=SASL_SSL
sasl.mechanism=PLAIN

然后使用console producer验证:

bin/kafka-console-producer.sh --broker-list kafka:9092 --topic test --producer.config config/producer.properties

一般能够发送数据就说明部署完成了~

自定义SASL/PLAIN认证(二次开发)

前面小节介绍了kafka sasl_plain的部署方式,但这种方式的诸多弊病决定了它并不适合用于生产环境。这里我们先介绍kafka2的新认证接口,然后演示下如何使用新的api自定义。

kafka2新的callback接口介绍

这一api提出的背景,是因为最开始的api(即SaslServer),不方便对用户认证进行拓展。这个问题在开发SASL/SCRAM功能的时候尤其突出。按官方的说法,要添加SASL/SCRAM功能,需要重写SaslServer类。

所以官方重写了这方面的功能,使用回调的方式实现了这部分的功能模块。使得开发者可以方便得对用户认证模块进行拓展或修改。

并且新增加了四个自定义认证的配置,分别是:

  • sasl客户端类:sasl.client.callback.handler.class
  • sasl服务端类:sasl.server.callback.handler.class
  • login类:sasl.login.class
  • login回调类:sasl.login.callback.handler.class

这几个配置默认都是null,需要填写的内容是自定义的类的路径+名称。我们这次只需要关注sasl服务端类的配置,即sasl.server.callback.handler.class

这部分的内容具体是在KIP-86

自定义sasl/plain功能

先详细介绍下sasl.server.callback.handler.class配置。这个配置在使用的时候,需要以小写方式指定SASL的类型。举个例子,如果是SASL_PLAINTEXT,那么就需要这样:

listener.name.sasl_plaintext.plain.sasl.server.callback.handler.class=com.example.CustomPlainCallbackHandler

即以listener.name.sasl_plaintext.plain.sasl开头。然后在kafka中,SASL_PLAINTEXT默认实现的callback handler是PlainServerCallbackHandler,实现了AuthenticateCallbackHandler接口。这个的逻辑其实还蛮简单的,我们可以看看它重点的方法和代码。

public class PlainServerCallbackHandler implements AuthenticateCallbackHandler {

    private static final String JAAS_USER_PREFIX = "user_";
//jaas配置信息,初始化一次,这就是为什么plain无法添加用户
private List<AppConfigurationEntry> jaasConfigEntries; @Override
public void configure(Map<String, ?> configs, String mechanism, List<AppConfigurationEntry> jaasConfigEntries) {
this.jaasConfigEntries = jaasConfigEntries;
} //核心类,获取用户密码后,调用authenticate方法
@Override
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
String username = null;
for (Callback callback: callbacks) {
if (callback instanceof NameCallback)
username = ((NameCallback) callback).getDefaultName();
else if (callback instanceof PlainAuthenticateCallback) {
PlainAuthenticateCallback plainCallback = (PlainAuthenticateCallback) callback;
boolean authenticated = authenticate(username, plainCallback.password());
plainCallback.authenticated(authenticated);
} else
throw new UnsupportedCallbackException(callback);
}
} //用户密码是通过获取jaas文件的属性,属性名就是JAAS_USER_PREFIX变量当前缀+username
protected boolean authenticate(String username, char[] password) throws IOException {
if (username == null)
return false;
else {
String expectedPassword = JaasContext.configEntryOption(jaasConfigEntries,
JAAS_USER_PREFIX + username,
PlainLoginModule.class.getName());
return expectedPassword != null && Arrays.equals(password, expectedPassword.toCharArray());
}
} @Override
public void close() throws KafkaException {
} }

前面说plain方式不支持动态添加用户,user_username验证密码,看代码就一清二楚。既然知道这个后,那要自定义校验逻辑就很简单了。

只需要继承PlainServerCallbackHandler这个类,然后重写authenticate方法实现自己的逻辑就实现自定义了。

比如我想让用户名和密码相同的就验证通过,那么可以这样:

public class MyPlainServerCallbackHandler extends PlainServerCallbackHandler{
@Override
protected boolean authenticate(String username, char[] password) throws IOException {
if (username == null)
return false;
else {
return expectedPassword != null && Arrays.equals(password, username.toCharArray());
}
}
}

然后中server.properpose中添加server callback信息,就可以了

listener.name.sasl_plaintext.plain.sasl.server.callback.handler.class=com.example.MyPlainServerCallbackHandler

对了,几得重新编译打包,替换掉kafka-client掉jar包,如果修改了一些全局信息(比如build.gradle引入新的依赖),那最好kafka全套jar包都换一下。

以上,如果觉得有用,不妨点个赞吧~

kafka SASL认证介绍及自定义SASL PLAIN认证功能的更多相关文章

  1. {Django基础九之中间件} 一 前戏 二 中间件介绍 三 自定义中间件 四 中间件的执行流程 五 中间件版登陆认证

    Django基础九之中间件 本节目录 一 前戏 二 中间件介绍 三 自定义中间件 四 中间件的执行流程 五 中间件版登陆认证 六 xxx 七 xxx 八 xxx 一 前戏 我们在前面的课程中已经学会了 ...

  2. Shrio认证详解+自定义Realm

    Authentication(身份认证)是Shiro权限控制的第一步,用来告诉系统你就是你. 在提交认证的时候,我们需要给系统提交两个信息: Principals:是一个表示用户的唯一属性,可以是用户 ...

  3. SpringSecurity——基于Spring、SpringMVC和MyBatis自定义SpringSecurity权限认证规则

    本文转自:https://www.cnblogs.com/weilu2/p/springsecurity_custom_decision_metadata.html 本文在SpringMVC和MyBa ...

  4. 任务31:课时介绍 & 任务32:Cookie-based认证介绍 &任务33:34课 :AccountController复制过来没有移除[Authorize]标签

    任务31:课时介绍 cookie-based网站这边的认证 jwt基于移动端和前后端分离的项目,jwt有一些独特的优势 jwt在asp.net core中的实现机制,了解实现机制并进行扩展.比如非标准 ...

  5. Shiro入门学习---使用自定义Realm完成认证|练气中期

    写在前面 在上一篇文章<shiro认证流程源码分析--练气初期>当中,我们简单分析了一下shiro的认证流程.不难发现,如果我们需要使用其他数据源的信息完成认证操作,我们需要自定义Real ...

  6. Keycloak 13 自定义用户身份认证流程(User Storage SPI)

    Keycloak 版本:13.0.0 介绍 Keycloak 是为现代应用程序和服务提供的一个开源的身份和访问管理的解决方案. Keycloak 在测试环境可以使用内嵌数据库,生产环境需要重新配置数据 ...

  7. #研发解决方案介绍#IdCenter(内部统一认证系统)

    郑昀 基于朱传志的设计文档 最后更新于2014/11/13 关键词:LDAP.认证.权限分配.IdCenter. 本文档适用人员:研发   曾经一个IT内部系统配一套帐号体系和授权   线上生产环境里 ...

  8. 基于HTTP 协议认证介绍与实现

    导言 一直对http 的头认证有兴趣,就是路由器的那种弹出对话框输入账号密码怎么实现一直不明白,最近,翻了一下http 协议,发现这是一个RFC 2617的实现,所以写篇文章介绍一下吧. Http基本 ...

  9. cas sso单点登录系列3_cas-server端配置认证方式实践(数据源+自定义java类认证)

    转:http://blog.csdn.net/ae6623/article/details/8851801 本篇将讲解cas-server端的认证方式 1.最简单的认证,用户名和密码一致就登录成功 2 ...

随机推荐

  1. django—模型相关

    配置数据库信息 1.settings配置 DATABASES = {     "default": {         "ENGINE": "djan ...

  2. pip安装与使用

    介绍 pip是python包管理工具,提供了对python包的查找,下载,安装,卸载功能. 安装 检查是否安装 pip --version 安装 curl https://bootstrap.pypa ...

  3. Linux下使用select延时

    在LINUX用户态的情况下,如果想要延时的话,可以使用用sleep函数,但是在一些情况下,需要更小单位的延时,ms/us 也是要的.用循环获取到的延时是不精确的. sleep是不准确,这个函数是可以中 ...

  4. Linux 打开core dump功能

    系统打开core dump功能 在终端中输入命令 ulimit -c ,输出的结果为 0,说明默认是关闭 core dump 的,即当程序异常终止时,也不会生成 core dump 文件: 使用命令  ...

  5. Parcelable使用(二)

    简单的Activity间数据传递用Intent,复杂的用Parcelable,举个栗子第一个activity写入Parcel的String类型的name和int类型的age,第二个activity取出 ...

  6. day76:luffy:项目前端环境搭建&轮播图的实现

    目录 1.项目前端环境搭建 1.创建项目目录 2.前端初始化全局变量和全局方法 3.跨域CORS 4.axios配置 2.轮播图功能的实现 1.安装依赖模块 2.上传文件相关配置 3.注册home子应 ...

  7. E. Enemy is weak 解析(思維、離散化、BIT、線段樹)

    Codeforce 61 E. Enemy is weak 解析(思維.離散化.BIT.線段樹) 今天我們來看看CF61E 題目連結 題目 給一個數列\(a\),求有多少\((i,j,k)\),\(i ...

  8. 深入了解Redis(8)-高可用方案

    生产环境中的redis基本都是多节点部署,本文只讨论redis高可用的三种方案,不涉及实际操作. 一.主从复制(一主一从,一主多从,级联结构) (图来源于网络) 一个Master,两个Slave,Sl ...

  9. 关于spring @scope("prorotype") 和 @aspectj 一起用的问题

    前段时间听别人说prototype 模式的bean用@Aspectj做AOP会导致内存泄漏, 于是自己研究了下总结出几点 1.aspectj  如果是采用javac 编译  会动态产生代理类 代理类是 ...

  10. js-同步和异步

    js异步 学习js开发,无论是前端开发还是node.js,都避免不了要接触异步编程这个问题,就和其它大多数以多线程同步为主的编程语言不同,js的主要设计是单线程异步模型.正因为js天生的与众不同,才使 ...