mirror of
https://github.com/zhwei820/learn.lianglianglee.com.git
synced 2025-09-25 04:36:41 +08:00
1145 lines
33 KiB
HTML
1145 lines
33 KiB
HTML
<!DOCTYPE html>
|
||
|
||
<!-- saved from url=(0046)https://kaiiiz.github.io/hexo-theme-book-demo/ -->
|
||
|
||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||
|
||
<head>
|
||
|
||
<head>
|
||
|
||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||
|
||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1.0, user-scalable=no">
|
||
|
||
<link rel="icon" href="/static/favicon.png">
|
||
|
||
<title>33 Kafka认证机制用哪家?.md.html</title>
|
||
|
||
<!-- Spectre.css framework -->
|
||
|
||
<link rel="stylesheet" href="/static/index.css">
|
||
|
||
<!-- theme css & js -->
|
||
|
||
<meta name="generator" content="Hexo 4.2.0">
|
||
|
||
</head>
|
||
|
||
|
||
|
||
<body>
|
||
|
||
|
||
|
||
<div class="book-container">
|
||
|
||
<div class="book-sidebar">
|
||
|
||
<div class="book-brand">
|
||
|
||
<a href="/">
|
||
|
||
<img src="/static/favicon.png">
|
||
|
||
<span>技术文章摘抄</span>
|
||
|
||
</a>
|
||
|
||
</div>
|
||
|
||
<div class="book-menu uncollapsible">
|
||
|
||
<ul class="uncollapsible">
|
||
|
||
<li><a href="/" class="current-tab">首页</a></li>
|
||
|
||
</ul>
|
||
|
||
|
||
|
||
<ul class="uncollapsible">
|
||
|
||
<li><a href="../">上一级</a></li>
|
||
|
||
</ul>
|
||
|
||
|
||
|
||
<ul class="uncollapsible">
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/Kafka核心技术与实战/00 开篇词 为什么要学习Kafka?.md.html">00 开篇词 为什么要学习Kafka?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/Kafka核心技术与实战/01 消息引擎系统ABC.md.html">01 消息引擎系统ABC.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/Kafka核心技术与实战/02 一篇文章带你快速搞定Kafka术语.md.html">02 一篇文章带你快速搞定Kafka术语.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/Kafka核心技术与实战/03 Kafka只是消息引擎系统吗?.md.html">03 Kafka只是消息引擎系统吗?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/Kafka核心技术与实战/04 我应该选择哪种Kafka?.md.html">04 我应该选择哪种Kafka?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/Kafka核心技术与实战/05 聊聊Kafka的版本号.md.html">05 聊聊Kafka的版本号.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/Kafka核心技术与实战/06 Kafka线上集群部署方案怎么做?.md.html">06 Kafka线上集群部署方案怎么做?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/Kafka核心技术与实战/07 最最最重要的集群参数配置(上).md.html">07 最最最重要的集群参数配置(上).md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/Kafka核心技术与实战/08 最最最重要的集群参数配置(下).md.html">08 最最最重要的集群参数配置(下).md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/Kafka核心技术与实战/09 生产者消息分区机制原理剖析.md.html">09 生产者消息分区机制原理剖析.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/Kafka核心技术与实战/10 生产者压缩算法面面观.md.html">10 生产者压缩算法面面观.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/Kafka核心技术与实战/11 无消息丢失配置怎么实现?.md.html">11 无消息丢失配置怎么实现?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/Kafka核心技术与实战/12 客户端都有哪些不常见但是很高级的功能?.md.html">12 客户端都有哪些不常见但是很高级的功能?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/Kafka核心技术与实战/13 Java生产者是如何管理TCP连接的?.md.html">13 Java生产者是如何管理TCP连接的?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/Kafka核心技术与实战/14 幂等生产者和事务生产者是一回事吗?.md.html">14 幂等生产者和事务生产者是一回事吗?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/Kafka核心技术与实战/15 消费者组到底是什么?.md.html">15 消费者组到底是什么?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/Kafka核心技术与实战/16 揭开神秘的“位移主题”面纱.md.html">16 揭开神秘的“位移主题”面纱.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/Kafka核心技术与实战/17 消费者组重平衡能避免吗?.md.html">17 消费者组重平衡能避免吗?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/Kafka核心技术与实战/18 Kafka中位移提交那些事儿.md.html">18 Kafka中位移提交那些事儿.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/Kafka核心技术与实战/19 CommitFailedException异常怎么处理?.md.html">19 CommitFailedException异常怎么处理?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/Kafka核心技术与实战/20 多线程开发消费者实例.md.html">20 多线程开发消费者实例.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/Kafka核心技术与实战/21 Java 消费者是如何管理TCP连接的.md.html">21 Java 消费者是如何管理TCP连接的.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/Kafka核心技术与实战/22 消费者组消费进度监控都怎么实现?.md.html">22 消费者组消费进度监控都怎么实现?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/Kafka核心技术与实战/23 Kafka副本机制详解.md.html">23 Kafka副本机制详解.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/Kafka核心技术与实战/24 请求是怎么被处理的?.md.html">24 请求是怎么被处理的?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/Kafka核心技术与实战/25 消费者组重平衡全流程解析.md.html">25 消费者组重平衡全流程解析.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/Kafka核心技术与实战/26 你一定不能错过的Kafka控制器.md.html">26 你一定不能错过的Kafka控制器.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/Kafka核心技术与实战/27 关于高水位和Leader Epoch的讨论.md.html">27 关于高水位和Leader Epoch的讨论.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/Kafka核心技术与实战/28 主题管理知多少.md.html">28 主题管理知多少.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/Kafka核心技术与实战/29 Kafka动态配置了解下?.md.html">29 Kafka动态配置了解下?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/Kafka核心技术与实战/30 怎么重设消费者组位移?.md.html">30 怎么重设消费者组位移?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/Kafka核心技术与实战/31 常见工具脚本大汇总.md.html">31 常见工具脚本大汇总.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/Kafka核心技术与实战/32 KafkaAdminClient:Kafka的运维利器.md.html">32 KafkaAdminClient:Kafka的运维利器.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
<a class="current-tab" href="/专栏/Kafka核心技术与实战/33 Kafka认证机制用哪家?.md.html">33 Kafka认证机制用哪家?.md.html</a>
|
||
|
||
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/Kafka核心技术与实战/34 云环境下的授权该怎么做?.md.html">34 云环境下的授权该怎么做?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/Kafka核心技术与实战/35 跨集群备份解决方案MirrorMaker.md.html">35 跨集群备份解决方案MirrorMaker.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/Kafka核心技术与实战/36 你应该怎么监控Kafka?.md.html">36 你应该怎么监控Kafka?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/Kafka核心技术与实战/37 主流的Kafka监控框架.md.html">37 主流的Kafka监控框架.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/Kafka核心技术与实战/38 调优Kafka,你做到了吗?.md.html">38 调优Kafka,你做到了吗?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/Kafka核心技术与实战/39 从0搭建基于Kafka的企业级实时日志流处理平台.md.html">39 从0搭建基于Kafka的企业级实时日志流处理平台.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/Kafka核心技术与实战/40 Kafka Streams与其他流处理平台的差异在哪里?.md.html">40 Kafka Streams与其他流处理平台的差异在哪里?.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/Kafka核心技术与实战/41 Kafka Streams DSL开发实例.md.html">41 Kafka Streams DSL开发实例.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/Kafka核心技术与实战/42 Kafka Streams在金融领域的应用.md.html">42 Kafka Streams在金融领域的应用.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/Kafka核心技术与实战/加餐 搭建开发环境、阅读源码方法、经典学习资料大揭秘.md.html">加餐 搭建开发环境、阅读源码方法、经典学习资料大揭秘.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
<li>
|
||
|
||
|
||
|
||
|
||
|
||
<a href="/专栏/Kafka核心技术与实战/结束语 以梦为马,莫负韶华!.md.html">结束语 以梦为马,莫负韶华!.md.html</a>
|
||
|
||
|
||
|
||
</li>
|
||
|
||
</ul>
|
||
|
||
|
||
|
||
</div>
|
||
|
||
</div>
|
||
|
||
|
||
|
||
<div class="sidebar-toggle" onclick="sidebar_toggle()" onmouseover="add_inner()" onmouseleave="remove_inner()">
|
||
|
||
<div class="sidebar-toggle-inner"></div>
|
||
|
||
</div>
|
||
|
||
|
||
|
||
<script>
|
||
|
||
function add_inner() {
|
||
|
||
let inner = document.querySelector('.sidebar-toggle-inner')
|
||
|
||
inner.classList.add('show')
|
||
|
||
}
|
||
|
||
|
||
|
||
function remove_inner() {
|
||
|
||
let inner = document.querySelector('.sidebar-toggle-inner')
|
||
|
||
inner.classList.remove('show')
|
||
|
||
}
|
||
|
||
|
||
|
||
function sidebar_toggle() {
|
||
|
||
let sidebar_toggle = document.querySelector('.sidebar-toggle')
|
||
|
||
let sidebar = document.querySelector('.book-sidebar')
|
||
|
||
let content = document.querySelector('.off-canvas-content')
|
||
|
||
if (sidebar_toggle.classList.contains('extend')) { // show
|
||
|
||
sidebar_toggle.classList.remove('extend')
|
||
|
||
sidebar.classList.remove('hide')
|
||
|
||
content.classList.remove('extend')
|
||
|
||
} else { // hide
|
||
|
||
sidebar_toggle.classList.add('extend')
|
||
|
||
sidebar.classList.add('hide')
|
||
|
||
content.classList.add('extend')
|
||
|
||
}
|
||
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
function open_sidebar() {
|
||
|
||
let sidebar = document.querySelector('.book-sidebar')
|
||
|
||
let overlay = document.querySelector('.off-canvas-overlay')
|
||
|
||
sidebar.classList.add('show')
|
||
|
||
overlay.classList.add('show')
|
||
|
||
}
|
||
|
||
function hide_canvas() {
|
||
|
||
let sidebar = document.querySelector('.book-sidebar')
|
||
|
||
let overlay = document.querySelector('.off-canvas-overlay')
|
||
|
||
sidebar.classList.remove('show')
|
||
|
||
overlay.classList.remove('show')
|
||
|
||
}
|
||
|
||
|
||
|
||
</script>
|
||
|
||
|
||
|
||
<div class="off-canvas-content">
|
||
|
||
<div class="columns">
|
||
|
||
<div class="column col-12 col-lg-12">
|
||
|
||
<div class="book-navbar">
|
||
|
||
<!-- For Responsive Layout -->
|
||
|
||
<header class="navbar">
|
||
|
||
<section class="navbar-section">
|
||
|
||
<a onclick="open_sidebar()">
|
||
|
||
<i class="icon icon-menu"></i>
|
||
|
||
</a>
|
||
|
||
</section>
|
||
|
||
</header>
|
||
|
||
</div>
|
||
|
||
<div class="book-content" style="max-width: 960px; margin: 0 auto;
|
||
|
||
overflow-x: auto;
|
||
|
||
overflow-y: hidden;">
|
||
|
||
<div class="book-post">
|
||
|
||
<p id="tip" align="center"></p>
|
||
|
||
<div><h1>33 Kafka认证机制用哪家?</h1>
|
||
|
||
<p>你好,我是胡夕。今天我要和你分享的主题是:Kafka 的认证机制。</p>
|
||
|
||
<h2>什么是认证机制?</h2>
|
||
|
||
<p>所谓认证,又称“验证”“鉴权”,英文是 authentication,是指通过一定的手段,完成对用户身份的确认。认证的主要目的是确认当前声称为某种身份的用户确实是所声称的用户。</p>
|
||
|
||
<p>在计算机领域,经常和认证搞混的一个术语就是授权,英文是 authorization。授权一般是指对信息安全或计算机安全相关的资源定义与授予相应的访问权限。</p>
|
||
|
||
<p>举个简单的例子来区分下两者:认证要解决的是你要证明你是谁的问题,授权要解决的则是你能做什么的问题。</p>
|
||
|
||
<p>在 Kafka 中,认证和授权是两套独立的安全配置。我们今天主要讨论 Kafka 的认证机制,在专栏的下一讲内容中,我们将讨论授权机制。</p>
|
||
|
||
<h2>Kafka 认证机制</h2>
|
||
|
||
<p>自 0.9.0.0 版本开始,Kafka 正式引入了认证机制,用于实现基础的安全用户认证,这是将 Kafka 上云或进行多租户管理的必要步骤。截止到当前最新的 2.3 版本,Kafka 支持基于 SSL 和基于 SASL 的安全认证机制。</p>
|
||
|
||
<p><strong>基于 SSL 的认证主要是指 Broker 和客户端的双路认证</strong>(2-way authentication)。通常来说,SSL 加密(Encryption)已经启用了单向认证,即客户端认证 Broker 的证书(Certificate)。如果要做 SSL 认证,那么我们要启用双路认证,也就是说 Broker 也要认证客户端的证书。</p>
|
||
|
||
<p>对了,你可能会说,SSL 不是已经过时了吗?现在都叫 TLS(Transport Layer Security)了吧?但是,Kafka 的源码中依然是使用 SSL 而不是 TLS 来表示这类东西的。不过,今天出现的所有 SSL 字眼,你都可以认为它们是和 TLS 等价的。</p>
|
||
|
||
<p>Kafka 还支持通过 SASL 做客户端认证。<strong>SASL 是提供认证和数据安全服务的框架</strong>。Kafka 支持的 SASL 机制有 5 种,它们分别是在不同版本中被引入的,你需要根据你自己使用的 Kafka 版本,来选择该版本所支持的认证机制。</p>
|
||
|
||
<ol>
|
||
|
||
<li>GSSAPI:也就是 Kerberos 使用的安全接口,是在 0.9 版本中被引入的。</li>
|
||
|
||
<li>PLAIN:是使用简单的用户名 / 密码认证的机制,在 0.10 版本中被引入。</li>
|
||
|
||
<li>SCRAM:主要用于解决 PLAIN 机制安全问题的新机制,是在 0.10.2 版本中被引入的。</li>
|
||
|
||
<li>OAUTHBEARER:是基于 OAuth 2 认证框架的新机制,在 2.0 版本中被引进。</li>
|
||
|
||
<li>Delegation Token:补充现有 SASL 机制的轻量级认证机制,是在 1.1.0 版本被引入的。</li>
|
||
|
||
</ol>
|
||
|
||
<h2>认证机制的比较</h2>
|
||
|
||
<p>Kafka 为我们提供了这么多种认证机制,在实际使用过程中,我们应该如何选择合适的认证框架呢?下面我们就来比较一下。</p>
|
||
|
||
<p>目前来看,使用 SSL 做信道加密的情况更多一些,但使用 SSL 实现认证不如使用 SASL。毕竟,SASL 能够支持你选择不同的实现机制,如 GSSAPI、SCRAM、PLAIN 等。因此,我的建议是<strong>你可以使用 SSL 来做通信加密,使用 SASL 来做 Kafka 的认证实现</strong>。</p>
|
||
|
||
<p>SASL 下又细分了很多种认证机制,我们应该如何选择呢?</p>
|
||
|
||
<p>SASL/GSSAPI 主要是给 Kerberos 使用的。如果你的公司已经做了 Kerberos 认证(比如使用 Active Directory),那么使用 GSSAPI 是最方便的了。因为你不需要额外地搭建 Kerberos,只要让你们的 Kerberos 管理员给每个 Broker 和要访问 Kafka 集群的操作系统用户申请 principal 就好了。总之,<strong>GSSAPI 适用于本身已经做了 Kerberos 认证的场景,这样的话,SASL/GSSAPI 可以实现无缝集成</strong>。</p>
|
||
|
||
<p>而 SASL/PLAIN,就像前面说到的,它是一个简单的用户名 / 密码认证机制,通常与 SSL 加密搭配使用。注意,这里的 PLAIN 和 PLAINTEXT 是两回事。<strong>PLAIN 在这里是一种认证机制,而 PLAINTEXT 说的是未使用 SSL 时的明文传输</strong>。对于一些小公司而言,搭建公司级的 Kerberos 可能并没有什么必要,他们的用户系统也不复杂,特别是访问 Kafka 集群的用户可能不是很多。对于 SASL/PLAIN 而言,这就是一个非常合适的应用场景。<strong>总体来说,SASL/PLAIN 的配置和运维成本相对较小,适合于小型公司中的 Kafka 集群</strong>。</p>
|
||
|
||
<p>但是,SASL/PLAIN 有这样一个弊端:它不能动态地增减认证用户,你必须重启 Kafka 集群才能令变更生效。为什么呢?这是因为所有认证用户信息全部保存在静态文件中,所以只能重启 Broker,才能重新加载变更后的静态文件。</p>
|
||
|
||
<p>我们知道,重启集群在很多场景下都是令人不爽的,即使是轮替式升级(Rolling Upgrade)。SASL/SCRAM 就解决了这样的问题。它通过将认证用户信息保存在 ZooKeeper 的方式,避免了动态修改需要重启 Broker 的弊端。在实际使用过程中,你可以使用 Kafka 提供的命令动态地创建和删除用户,无需重启整个集群。因此,<strong>如果你打算使用 SASL/PLAIN,不妨改用 SASL/SCRAM 试试。不过要注意的是,后者是 0.10.2 版本引入的。你至少要升级到这个版本后才能使用</strong>。</p>
|
||
|
||
<p>SASL/OAUTHBEARER 是 2.0 版本引入的新认证机制,主要是为了实现与 OAuth 2 框架的集成。OAuth 是一个开发标准,允许用户授权第三方应用访问该用户在某网站上的资源,而无需将用户名和密码提供给第三方应用。Kafka 不提倡单纯使用 OAUTHBEARER,因为它生成的不安全的 JSON Web Token,必须配以 SSL 加密才能用在生产环境中。当然,鉴于它是 2.0 版本才推出来的,而且目前没有太多的实际使用案例,我们可以先观望一段时间,再酌情将其应用于生产环境中。</p>
|
||
|
||
<p>Delegation Token 是在 1.1 版本引入的,它是一种轻量级的认证机制,主要目的是补充现有的 SASL 或 SSL 认证。如果要使用 Delegation Token,你需要先配置好 SASL 认证,然后再利用 Kafka 提供的 API 去获取对应的 Delegation Token。这样,Broker 和客户端在做认证的时候,可以直接使用这个 token,不用每次都去 KDC 获取对应的 ticket(Kerberos 认证)或传输 Keystore 文件(SSL 认证)。</p>
|
||
|
||
<p>为了方便你更好地理解和记忆,我把这些认证机制汇总在下面的表格里了。你可以对照着表格,进行一下区分。</p>
|
||
|
||
<p><img src="assets/4a52c2eb1ae631697b5ec3d298f7333d.jpg" alt="img" /></p>
|
||
|
||
<h2>SASL/SCRAM-SHA-256 配置实例</h2>
|
||
|
||
<p>接下来,我给出 SASL/SCRAM 的一个配置实例,来说明一下如何在 Kafka 集群中开启认证。其他认证机制的设置方法也是类似的,比如它们都涉及认证用户的创建、Broker 端以及 Client 端特定参数的配置等。</p>
|
||
|
||
<p>我的测试环境是本地 Mac 上的两个 Broker 组成的 Kafka 集群,连接端口分别是 9092 和 9093。</p>
|
||
|
||
<h3>第 1 步:创建用户</h3>
|
||
|
||
<p>配置 SASL/SCRAM 的第一步,是创建能否连接 Kafka 集群的用户。在本次测试中,我会创建 3 个用户,分别是 admin 用户、writer 用户和 reader 用户。admin 用户用于实现 Broker 间通信,writer 用户用于生产消息,reader 用户用于消费消息。</p>
|
||
|
||
<p>我们使用下面这 3 条命令,分别来创建它们。</p>
|
||
|
||
<pre><code>$ cd kafka_2.12-2.3.0/
|
||
|
||
$ bin/kafka-configs.sh --zookeeper localhost:2181 --alter --add-config 'SCRAM-SHA-256=[password=admin],SCRAM-SHA-512=[password=admin]' --entity-type users --entity-name admin
|
||
|
||
Completed Updating config for entity: user-principal 'admin'.
|
||
|
||
$ bin/kafka-configs.sh --zookeeper localhost:2181 --alter --add-config 'SCRAM-SHA-256=[password=writer],SCRAM-SHA-512=[password=writer]' --entity-type users --entity-name writer
|
||
|
||
Completed Updating config for entity: user-principal 'writer'.
|
||
|
||
$ bin/kafka-configs.sh --zookeeper localhost:2181 --alter --add-config 'SCRAM-SHA-256=[password=reader],SCRAM-SHA-512=[password=reader]' --entity-type users --entity-name reader
|
||
|
||
Completed Updating config for entity: user-principal 'reader'.
|
||
|
||
</code></pre>
|
||
|
||
<p>在专栏前面,我们提到过,kafka-configs 脚本是用来设置主题级别参数的。其实,它的功能还有很多。比如在这个例子中,我们使用它来创建 SASL/SCRAM 认证中的用户信息。我们可以使用下列命令来查看刚才创建的用户数据。</p>
|
||
|
||
<pre><code>$ bin/kafka-configs.sh --zookeeper localhost:2181 --describe --entity-type users --entity-name writer
|
||
|
||
Configs for user-principal 'writer' are SCRAM-SHA-512=salt=MWt6OGplZHF6YnF5bmEyam9jamRwdWlqZWQ=,stored_key=hR7+vgeCEz61OmnMezsqKQkJwMCAoTTxw2jftYiXCHxDfaaQU7+9/dYBq8bFuTio832mTHk89B4Yh9frj/ampw==,server_key=C0k6J+9/InYRohogXb3HOlG7s84EXAs/iw0jGOnnQAt4jxQODRzeGxNm+18HZFyPn7qF9JmAqgtcU7hgA74zfA==,iterations=4096,SCRAM-SHA-256=salt=MWV0cDFtbXY5Nm5icWloajdnbjljZ3JqeGs=,stored_key=sKjmeZe4sXTAnUTL1CQC7DkMtC+mqKtRY0heEHvRyPk=,server_key=kW7CC3PBj+JRGtCOtIbAMefL8aiL8ZrUgF5tfomsWVA=,iterations=4096
|
||
|
||
</code></pre>
|
||
|
||
<p>这段命令包含了 writer 用户加密算法 SCRAM-SHA-256 以及 SCRAM-SHA-512 对应的盐值 (Salt)、ServerKey 和 StoreKey。这些都是 SCRAM 机制的术语,我们不需要了解它们的含义,因为它们并不影响我们接下来的配置。</p>
|
||
|
||
<h3>第 2 步:创建 JAAS 文件</h3>
|
||
|
||
<p>配置了用户之后,我们需要为每个 Broker 创建一个对应的 JAAS 文件。因为本例中的两个 Broker 实例是在一台机器上,所以我只创建了一份 JAAS 文件。但是你要切记,在实际场景中,你需要为每台单独的物理 Broker 机器都创建一份 JAAS 文件。</p>
|
||
|
||
<p>JAAS 的文件内容如下:</p>
|
||
|
||
<pre><code>KafkaServer {
|
||
|
||
org.apache.kafka.common.security.scram.ScramLoginModule required
|
||
|
||
username="admin"
|
||
|
||
password="admin";
|
||
|
||
};
|
||
|
||
</code></pre>
|
||
|
||
<p>关于这个文件内容,你需要注意以下两点:</p>
|
||
|
||
<ul>
|
||
|
||
<li>不要忘记最后一行和倒数第二行结尾处的分号;</li>
|
||
|
||
<li>JAAS 文件中不需要任何空格键。</li>
|
||
|
||
</ul>
|
||
|
||
<p>这里,我们使用 admin 用户实现 Broker 之间的通信。接下来,我们来配置 Broker 的 server.properties 文件,下面这些内容,是需要单独配置的:</p>
|
||
|
||
<pre><code>sasl.enabled.mechanisms=SCRAM-SHA-256
|
||
|
||
sasl.mechanism.inter.broker.protocol=SCRAM-SHA-256
|
||
|
||
security.inter.broker.protocol=SASL_PLAINTEXT
|
||
|
||
listeners=SASL_PLAINTEXT://localhost:9092
|
||
|
||
</code></pre>
|
||
|
||
<p>第 1 项内容表明开启 SCRAM 认证机制,并启用 SHA-256 算法;第 2 项的意思是为 Broker 间通信也开启 SCRAM 认证,同样使用 SHA-256 算法;第 3 项表示 Broker 间通信不配置 SSL,本例中我们不演示 SSL 的配置;最后 1 项是设置 listeners 使用 SASL_PLAINTEXT,依然是不使用 SSL。</p>
|
||
|
||
<p>另一台 Broker 的配置基本和它类似,只是要使用不同的端口,在这个例子中,端口是 9093。</p>
|
||
|
||
<h3>第 3 步:启动 Broker</h3>
|
||
|
||
<p>现在我们分别启动这两个 Broker。在启动时,你需要指定 JAAS 文件的位置,如下所示:</p>
|
||
|
||
<pre><code>$KAFKA_OPTS=-Djava.security.auth.login.config=<your_path>/kafka-broker.jaas bin/kafka-server-start.sh config/server1.properties
|
||
|
||
......
|
||
|
||
[2019-07-02 13:30:34,822] INFO Kafka commitId: fc1aaa116b661c8a (org.apache.kafka.common.utils.AppInfoParser)
|
||
|
||
[2019-07-02 13:30:34,822] INFO Kafka startTimeMs: 1562045434820 (org.apache.kafka.common.utils.AppInfoParser)
|
||
|
||
[2019-07-02 13:30:34,823] INFO [KafkaServer id=0] started (kafka.server.KafkaServer)
|
||
|
||
$KAFKA_OPTS=-Djava.security.auth.login.config=<your_path>/kafka-broker.jaas bin/kafka-server-start.sh config/server2.properties
|
||
|
||
......
|
||
|
||
[2019-07-02 13:32:31,976] INFO Kafka commitId: fc1aaa116b661c8a (org.apache.kafka.common.utils.AppInfoParser)
|
||
|
||
[2019-07-02 13:32:31,976] INFO Kafka startTimeMs: 1562045551973 (org.apache.kafka.common.utils.AppInfoParser)
|
||
|
||
[2019-07-02 13:32:31,978] INFO [KafkaServer id=1] started (kafka.server.KafkaServer)
|
||
|
||
</code></pre>
|
||
|
||
<p>此时,两台 Broker 都已经成功启动了。</p>
|
||
|
||
<h3>第 4 步:发送消息</h3>
|
||
|
||
<p>在创建好测试主题之后,我们使用 kafka-console-producer 脚本来尝试发送消息。由于启用了认证,客户端需要做一些相应的配置。我们创建一个名为 producer.conf 的配置文件,内容如下:</p>
|
||
|
||
<pre><code>security.protocol=SASL_PLAINTEXT
|
||
|
||
sasl.mechanism=SCRAM-SHA-256
|
||
|
||
sasl.jaas.config=org.apache.kafka.common.security.scram.ScramLoginModule required username="writer" password="writer";
|
||
|
||
</code></pre>
|
||
|
||
<p>之后运行 Console Producer 程序:</p>
|
||
|
||
<pre><code>$ bin/kafka-console-producer.sh --broker-list localhost:9092,localhost:9093 --topic test --producer.config <your_path>/producer.conf
|
||
|
||
>hello, world
|
||
|
||
>
|
||
|
||
</code></pre>
|
||
|
||
<p>可以看到,Console Producer 程序发送消息成功。</p>
|
||
|
||
<h3>第 5 步:消费消息</h3>
|
||
|
||
<p>接下来,我们使用 Console Consumer 程序来消费一下刚刚生产的消息。同样地,我们需要为 kafka-console-consumer 脚本创建一个名为 consumer.conf 的脚本,内容如下:</p>
|
||
|
||
<pre><code>security.protocol=SASL_PLAINTEXT
|
||
|
||
sasl.mechanism=SCRAM-SHA-256
|
||
|
||
sasl.jaas.config=org.apache.kafka.common.security.scram.ScramLoginModule required username="reader" password="reader";
|
||
|
||
</code></pre>
|
||
|
||
<p>之后运行 Console Consumer 程序:</p>
|
||
|
||
<pre><code>$ bin/kafka-console-consumer.sh --bootstrap-server localhost:9092,localhost:9093 --topic test --from-beginning --consumer.config <your_path>/consumer.conf
|
||
|
||
hello, world
|
||
|
||
</code></pre>
|
||
|
||
<p>很显然,我们是可以正常消费的。</p>
|
||
|
||
<h3>第 6 步:动态增减用户</h3>
|
||
|
||
<p>最后,我们来演示 SASL/SCRAM 动态增减用户的场景。假设我删除了 writer 用户,同时又添加了一个新用户:new_writer,那么,我们需要执行的命令如下:</p>
|
||
|
||
<pre><code>$ bin/kafka-configs.sh --zookeeper localhost:2181 --alter --delete-config 'SCRAM-SHA-256' --entity-type users --entity-name writer
|
||
|
||
Completed Updating config for entity: user-principal 'writer'.
|
||
|
||
|
||
|
||
$ bin/kafka-configs.sh --zookeeper localhost:2181 --alter --delete-config 'SCRAM-SHA-512' --entity-type users --entity-name writer
|
||
|
||
Completed Updating config for entity: user-principal 'writer'.
|
||
|
||
|
||
|
||
$ bin/kafka-configs.sh --zookeeper localhost:2181 --alter --add-config 'SCRAM-SHA-256=[iterations=8192,password=new_writer]' --entity-type users --entity-name new_writer
|
||
|
||
Completed Updating config for entity: user-principal 'new_writer'.
|
||
|
||
</code></pre>
|
||
|
||
<p>现在,我们依然使用刚才的 producer.conf 来验证,以确认 Console Producer 程序不能发送消息。</p>
|
||
|
||
<pre><code>$ bin/kafka-console-producer.sh --broker-list localhost:9092,localhost:9093 --topic test --producer.config /Users/huxi/testenv/producer.conf
|
||
|
||
>[2019-07-02 13:54:29,695] ERROR [Producer clientId=console-producer] Connection to node -1 (localhost/127.0.0.1:9092) failed authentication due to: Authentication failed during authentication due to invalid credentials with SASL mechanism SCRAM-SHA-256 (org.apache.kafka.clients.NetworkClient)
|
||
|
||
......
|
||
|
||
</code></pre>
|
||
|
||
<p>很显然,此时 Console Producer 已经不能发送消息了。因为它使用的 producer.conf 文件指定的是已经被删除的 writer 用户。如果我们修改 producer.conf 的内容,改为指定新创建的 new_writer 用户,结果如下:</p>
|
||
|
||
<pre><code>$ bin/kafka-console-producer.sh --broker-list localhost:9092,localhost:9093 --topic test --producer.config <your_path>/producer.conf
|
||
|
||
>Good!
|
||
|
||
</code></pre>
|
||
|
||
<p>现在,Console Producer 可以正常发送消息了。</p>
|
||
|
||
<p>这个过程完整地展示了 SASL/SCRAM 是如何在不重启 Broker 的情况下增减用户的。</p>
|
||
|
||
<p>至此,SASL/SCRAM 配置就完成了。在专栏下一讲中,我会详细介绍一下如何赋予 writer 和 reader 用户不同的权限。</p>
|
||
|
||
<h2>小结</h2>
|
||
|
||
<p>好了,我们来小结一下。今天,我们讨论了 Kafka 目前提供的几种认证机制,我给出了它们各自的优劣势以及推荐使用建议。其实,在真实的使用场景中,认证和授权往往是结合在一起使用的。在专栏下一讲中,我会详细向你介绍 Kafka 的授权机制,即 ACL 机制,敬请期待。</p>
|
||
|
||
<p><img src="assets/af705cb98a2f46acd45b184ec201005c.jpg" alt="img" /></p>
|
||
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<div>
|
||
|
||
<div style="float: left">
|
||
|
||
<a href="/专栏/Kafka核心技术与实战/32 KafkaAdminClient:Kafka的运维利器.md.html">上一页</a>
|
||
|
||
</div>
|
||
|
||
<div style="float: right">
|
||
|
||
<a href="/专栏/Kafka核心技术与实战/34 云环境下的授权该怎么做?.md.html">下一页</a>
|
||
|
||
</div>
|
||
|
||
</div>
|
||
|
||
|
||
|
||
</div>
|
||
|
||
</div>
|
||
|
||
</div>
|
||
|
||
</div>
|
||
|
||
|
||
|
||
<a class="off-canvas-overlay" onclick="hide_canvas()"></a>
|
||
|
||
</div>
|
||
|
||
<script defer src="https://static.cloudflareinsights.com/beacon.min.js/v652eace1692a40cfa3763df669d7439c1639079717194" integrity="sha512-Gi7xpJR8tSkrpF7aordPZQlW2DLtzUlZcumS8dMQjwDHEnw9I7ZLyiOj/6tZStRBGtGgN6ceN6cMH8z7etPGlw==" data-cf-beacon='{"rayId":"709972154aac3d60","version":"2021.12.0","r":1,"token":"1f5d475227ce4f0089a7cff1ab17c0f5","si":100}' crossorigin="anonymous"></script>
|
||
|
||
</body>
|
||
|
||
<!-- Global site tag (gtag.js) - Google Analytics -->
|
||
|
||
<script async src="https://www.googletagmanager.com/gtag/js?id=G-NPSEEVD756"></script>
|
||
|
||
<script>
|
||
|
||
window.dataLayer = window.dataLayer || [];
|
||
|
||
|
||
|
||
function gtag() {
|
||
|
||
dataLayer.push(arguments);
|
||
|
||
}
|
||
|
||
|
||
|
||
gtag('js', new Date());
|
||
|
||
gtag('config', 'G-NPSEEVD756');
|
||
|
||
var path = window.location.pathname
|
||
|
||
var cookie = getCookie("lastPath");
|
||
|
||
console.log(path)
|
||
|
||
if (path.replace("/", "") === "") {
|
||
|
||
if (cookie.replace("/", "") !== "") {
|
||
|
||
console.log(cookie)
|
||
|
||
document.getElementById("tip").innerHTML = "<a href='" + cookie + "'>跳转到上次进度</a>"
|
||
|
||
}
|
||
|
||
} else {
|
||
|
||
setCookie("lastPath", path)
|
||
|
||
}
|
||
|
||
|
||
|
||
function setCookie(cname, cvalue) {
|
||
|
||
var d = new Date();
|
||
|
||
d.setTime(d.getTime() + (180 * 24 * 60 * 60 * 1000));
|
||
|
||
var expires = "expires=" + d.toGMTString();
|
||
|
||
document.cookie = cname + "=" + cvalue + "; " + expires + ";path = /";
|
||
|
||
}
|
||
|
||
|
||
|
||
function getCookie(cname) {
|
||
|
||
var name = cname + "=";
|
||
|
||
var ca = document.cookie.split(';');
|
||
|
||
for (var i = 0; i < ca.length; i++) {
|
||
|
||
var c = ca[i].trim();
|
||
|
||
if (c.indexOf(name) === 0) return c.substring(name.length, c.length);
|
||
|
||
}
|
||
|
||
return "";
|
||
|
||
}
|
||
|
||
|
||
|
||
</script>
|
||
|
||
|
||
|
||
</html>
|
||
|