Kerberos:更安全的网络认证协议

简介

Kerberos 是一种网络认证协议,主要用于特定的场景下,代替传统的token方式,以一种更繁琐,但更安全的方式来认证用户信息。它通过票据 (ticket) 机制,确保用户在网络中与服务之间进行加密通信,并且避免了密码在网络中传输。Kerberos 的设计目标是通过可信的第三方(即 Key Distribution Center, KDC)管理用户身份,提供单点登录 (SSO) 和安全的认证方式。

Kerberos认证机制

身份验证

相较于传统的输入账号密码返回token的方式,Kerberos提供了一个更加安全的机制:

首先,Kerberos的核心功能依赖于KDC服务器完成。需要通过验证客户端用户信息来保证数据安全的的服务,不在接收账号密码来验证客户端身份。而是由管理员手动将KDC密钥,复制到目标服务及客户端,目标服务和客户端在通过密钥文件向KDC服务器发送请求,请求票据。KDC服务器在完成用户身份验证时,会返回一个功能类似于token的信息,他被称作票据。客户端也可以通过数据密码来获取TGT,不过部分服务驱动不支持。

Kerberos第一次需要携带管理员配置的密钥来向KDC服务器请求授予票据(TGT)。在客户端获得了TGT后,会在次向票据授予服务器(TGS)发送请求,由TGS来验证TGT内部包含的用户信息,来返回当前用户权限内的目标服务器的验证票据。

TGS服务器是KDC服务器的一部分。

票据验证

Kerberos还会验证当前客户端的其他信息,来保证票据在传输过程中的安全性,包括:

  • 票据授予票据 (TGT) 的验证:TGS在处理客户端请求时,会验证TGT的完整性,以及根据TGT内记录的用户信息,来分配对应的权限票据。

  • 服务票据的验证:服务端在接收到客户端的请求时,会检查票据的正确性和过期时间,来完成对客户端的用户验证。

  • 身份的双向验证(可选) :Kerberos 支持双向身份验证,其实用对成加密的方式,客户端和服务器都会互相验证对方身份,防止其他中间者试图破解票据。

  • 服务端根据票据信息进一步验证:票据中存储着Kerberos中保存的用户信息,目标服务器通过解密,可以根据获取到票据中的信息,进一步对用户权限进行控制

  • 加密强度和协议验证:KDC 和客户端在认证过程中会协商使用的加密算法。Kerberos 支持多种加密算法(如 AES、DES 等),并会验证使用的加密强度是否符合安全要求。通常,系统管理员可以配置 KDC 只接受某些强度的加密算法。

  • 重放攻击的防护:Kerberos 通过多个机制防止重放攻击,包括Kerberos客户端在请求头中添加时间戳密文,服务验证请求头的时间戳和当前服务器的时间差,是否在允许范围内。一个票据同时只能在一个回话使用,不能在两个会话中同时使用。票据中包含客户端的 IP 地址等网络信息,防止票据在其他设备上被仿造。

重放攻击是指攻击者利用已经发送的数据,在此向目标服务器发送,伪装自己为已经验证完成的客户端端身份。通过对时间戳加密,并且判断时间差,可以有效的防止这一攻击。

kerberos架构

kerberos内部通过领域来分割多个系统,当一个主题通过密钥获取TGT后,他可以通过这个TGT获取这个领域中,当前主题权限范围内的所有其他主体的票据(权限控制在acl_files配置的文件中修改,后面会说),不过他无法获取其他的领域的票据,因为多个领域之间的TGT是不互通的。

不过我们可以对多个领域之间进行单向信任或双向信任,比如说一个服务系统,想要利用另一个服务系统的功能,我们只需要把两个领域进行互相信任即可,这样两者的TGT就可以互通,在一个领域内通过密钥获取主体的TGT,可以在两个领域中随意获取所有主体的票据。

在一个领域中通过主体来区分多个服务,比如说我想讲Kafka集群和redis集群来增加认证机制,那么我就要在kerberos中来添加对应的两个主题。例如kafka/admin@EXAMPLE.com,redis/admin@EXAMPLE.com,这就是两个主题,其中第一个名字是角色,他决定了这个主体拥有了什么权限,而第二个名字是当前角色的实例,用于区分多个相同权限和领域的主体。

通过领域和主题,我们可以实现更加精细的客户端权限认证控制。整体架构如下:

Kerberos基本使用

1. 安装 Kerberos 服务

bash 复制代码
yum install krb5-server krb5-libs krb5-workstation

2. 配置 Kerberos 配置文件

修改 /etc/krb5.conf 文件来配置 Kerberos 服务。内容如下:

[logging]
 default = FILE:/var/log/krb5libs.log
 kdc = FILE:/var/log/krb5kdc.log
 admin_server = FILE:/var/log/kadmind.log

[libdefaults]
 dns_lookup_realm = false
 ticket_lifetime = 24h
 renew_lifetime = 7d
 forwardable = true
 rdns = false
 pkinit_anchors = FILE:/etc/pki/tls/certs/ca-bundle.crt
 #默认领域:未指定领域的主体会默认指向这个领域
 default_realm = EXAMPLE.COM
 #Kerberos 默认的缓存票据存储位置
 default_ccache_name = KEYRING:persistent:%{uid}

[realms]
 #配置领域的KDC服务器(kdc)地址,和KDC管理服务(admin_server)的地址
 EXAMPLE.COM = {
  #这里我们为了方便,直接使用了ip,管理其他服务时,一定要写成域名
  kdc = 192.168.166.21
  admin_server = 192.168.166.21
 }
 #可以配置多个领域
  EXAMPLE2.COM = {
  kdc = 192.168.166.21
  admin_server = 192.168.166.21
 }
 
[domain_realm]
 #以.example.com结尾会匹配到这个领域
 .example.com = EXAMPLE.COM
 #精确匹配example.com
 example.com = EXAMPLE.COM

3. 配置 KDC

KDC 的配置文件通常位于 /var/kerberos/krb5kdc/kdc.conf。配置内容如下:

#KDC服务器全句默认配置
[kdcdefaults]
 #kdc监听端口端口,默认值就是 88
 kdc_ports = 88
 #kdctcp连接端口
 kdc_tcp_ports = 88
 
#配置领域局部配置
[realms]
 EXAMPLE.COM = {
  #kdc监听端口端口
  kdc_port = 88
  #票据的最大有效时间
  max_life = 24h
  #票据的最大可续展时间
  max_renewable_life = 7d
  #主密钥(Master Key)的存储文件
  key_stash_file = /var/kerberos/krb5kdc/.k5.EXAMPLE.COM
  #存储主体信息的数据库文件路径
  database_name = /var/kerberos/krb5kdc/principal
  #主密钥的加密类型。这里使用了 aes256-cts,即 256 位 AES 加密算法
  master_key_type = aes256-cts
  #管理员访问控制列表 (ACL) 文件的路径
  acl_file = /var/kerberos/krb5kdc/kadm5.acl
  #密码字典文件的路径
  dict_file = /usr/share/dict/words
  #keytab 文件路径
  admin_keytab = /var/kerberos/krb5kdc/kadm5.keytab
  #支持的加密类型
  supported_enctypes = aes256-cts:normal aes128-cts:normal des3-hmac-sha1:normal arcfour-hmac:normal camellia256-cts:normal camellia128-cts:normal des-hmac-sha1:normal des-cbc-md5:normal des-cbc-crc:normal
 }
  #可以配置多个领域
  EXAMPLE2.COM = {
  kdc_port = 88
  max_life = 24h
  max_renewable_life = 24
  key_stash_file = /var/kerberos/krb5kdc/.k5.EXAMPLE2.COM
  database_name = /var/kerberos/krb5kdc/2
  master_key_type = aes256-cts
  acl_file = /var/kerberos/krb5kdc/2.acl
  dict_file = /usr/share/dict/2
  admin_keytab = /var/kerberos/krb5kdc/2.keytab
  supported_enctypes = aes256-cts:normal aes128-cts:normal des3-hmac-sha1:normal arcfour-hmac:normal camellia256-cts:normal camellia128-cts:normal des-hmac-sha1:normal des-cbc-md5:normal des-cbc-crc:normal
 }

在如上配置中,出现了很多难以理解的概念,我在下面进行统一解释:

在 [kdcdefaults] 中的配置是默认配置,当 [realms] 内地领域配置没有明确指定的配置,就会采用默认配置替代。

票据续展允许用户在票据的初始有效期到期之前,通过续展来延长票据的有效期,而不必重新输入用户名和密码。和token刷新过期时间类似,不过最长时间不能超过max_renewable_life配置的最长可续展时间,我们的配置中配置的是7天,也就是7天一过便无法在进行续展。

主密钥是KDC服务器对自身数据库进行加密解密的密钥。

管理员访问控制列表文件指定了哪些用户或组可以进行 KDC 管理操作,如添加、删除 Kerberos 主体等。

密码字典使用来生成一切初始密码,以及检查密码强度使用的。

keytab文件包含了 KDC 管理服务的密钥。该文件用于远程管理 Kerberos 实例,通过 kadmin 工具进行管理操作。

4. 初始化 Kerberos 数据库

通过如下命令初始化数据库

kdb5_util create -s -r <领域名>

可以省略-r,用来初始化默认领域,结果如下:

通过-r指定领域,结果如下:

进入目标目录,可以看到数据库文件初始化成功,内容如下:

5. 设置管理员权限

上文中我们提到acl_file配置是指定管理员访问控制列表文件的文件路径,我们可以通过管理员访问控制列表文件来设置KDC管理服务用户的权限,不过在管理权限之前,我们必须设置一个拥有全部权限的管理员,这个文件的默认内容如下:

其中前面是匹配主体的匹配字符串,后面是权限,可以看到一切以admin为实例名的主体都可以获取*也就是全部的权限。我们也可以自定义规则。

6. 启动 Kerberos 服务

完成以上的配置我们就可以启动服务了,由于kerberos是为其他服务来添加认证服务的,其他服务依赖于kerberos服务本身,所以我们最好将其设置为开机自启,命令如下:

sudo systemctl start krb5kdc
sudo systemctl start kadmin
sudo systemctl enable krb5kdc
sudo systemctl enable kadmin

其中krb5kdc时KDC服务器,而kadmin则是管理服务

7. 添加管理员用户

我们之前配置了管理员访问控制列表文件的配置,并且启动了管理服务,那么现在就可以通过管理服务来添加管理员账号,命令如下:

#进入交互终端
kadmin.local
#添加管理员主体
addprinc admin/admin

结果如下:

8. 测试服务功能

首先通过kinit来获取票据

kinit admin/admin

通过klist查看票据

klist

成功后结果如下:

Kerberos集成Kafka服务

kerberos虽然已经搭建成功,并成功获取票据,可是他该如何和其他服务结合使用呢,这里我们以Kafka举例

1. 搭建kafka集群

Kafka集群搭建文章

2. 修改hosts文件

kerberos的主题匹配极度依赖于域名,所以我们一定要将所有的服务地址存到域名中来管理,即使是在同一台主机。

/etc/hosts:

192.168.166.51   www.kdc.com
192.168.166.51   www.kadmin.com
192.168.166.51   www.kafka.com  

3. 修改Kerberos领域配置

krb5.conf 是 Kerberos 客户端和 KDC(Key Distribution Center)都需要的配置文件,它用于定义 Kerberos 领域、KDC 地址、管理服务器地址以及 Kerberos 客户端如何与 KDC 进行交互。所以在kerberos服务的主机,以及客户端,Kafka服务的主机,都需要读取这个配置文件。不过我们是在一个主机上进行测试的,所以不用额外创建。

/etc/krb5.conf

# Configuration snippets may be placed in this directory as well
includedir /etc/krb5.conf.d/

[logging]
 default = FILE:/var/log/krb5libs.log
 default = FILE:/var/log/krb5libs.log
 kdc = FILE:/var/log/krb5kdc.log
 admin_server = FILE:/var/log/kadmind.log

[libdefaults]
 dns_lookup_realm = false
 ticket_lifetime = 24h
 renew_lifetime = 7d
 forwardable = true
 rdns = false
 pkinit_anchors = FILE:/etc/pki/tls/certs/ca-bundle.crt
 default_realm = KAFKA.COM
 default_ccache_name = KEYRING:persistent:%{uid}

[realms]
 KAFKA.COM = {
  kdc = www.kdc.com
  admin_server = www.kadmin.com
 }

[domain_realm]
 .kafka.com = KAFKA.COM
 www.kafka.com = KAFKA.COM

kdc.conf 是 Kerberos KDC 服务器的配置文件,用于配置 KDC 服务的行为,例如票据的有效期、领域的策略、加密类型等。这个文件只需要在运行 KDC 服务 的机器上配置。

/var/kerberos/krb5kdc/kdc.conf

[kdcdefaults]
 kdc_ports = 88
 kdc_tcp_ports = 88

[realms]
 KAFKA.COM = {
  #kdc监听端口端口
  kdc_port = 88
  #票据的最大有效时间
  max_life = 24h
  #票据的最大可续展时间
  max_renewable_life = 7d
  #主密钥(Master Key)的存储文件
  key_stash_file = /var/kerberos/krb5kdc/.k5.EXAMPLE.COM
  #存储主体信息的数据库文件路径
  database_name = /var/kerberos/krb5kdc/principal
  #主密钥的加密类型。这里使用了 aes256-cts,即 256 位 AES 加密算法
  master_key_type = aes256-cts
  #管理员访问控制列表 (ACL) 文件的路径
  acl_file = /var/kerberos/krb5kdc/kadm5.acl
  #密码字典文件的路径

4. 初始化Kerberos领域的数据库

kdb5_util create -s -r KAFKA.COM

结果如下:

更改配置后要重新初始化一个新的仓库,不知道为什么,但是我更改配置后重启,断开服务器连接,各种方法都尝试了,都没有更改成功,重新初始化数据库后才成功。

5. 在kerberos中创建kafka服务的主体

#进入终端
kadmin.local
#创建主题,生成随机密钥
addprinc -randkey kafka/www.kafka.com@KAFKA.COM

这个地方中间的实例一定要用域名,客户端在获取TGT后,再次获取票据时不会发送完整的主体名,而是只发送第一部分的服务名,第二部分是根据请求的域名来填充的。

成功结果如下

6. 导出密钥文件

#进入终端
kadmin.local
#导出密钥生成密钥文件
ktadd -k /var/kerberos/krb5kdc/kafka.keytab kafka/www.kafka.com@KAFKA.COM

成功结果如下:

7. 启动Kerberos服务

sudo systemctl start krb5kdc
sudo systemctl start kadmin
#设置开机自启
sudo systemctl enable krb5kdc
sudo systemctl enable kadmin

8. 修改Kafka的配置文件

listeners 配置中启用 SASL_PLAINTEXT 或 SASL_SSL:

listeners=SASL_PLAINTEXT://:9092
inter.broker.listener.name=SASL_PLAINTEXT

配置 SASL 的 Kerberos 认证机制:

sasl.mechanism.inter.broker.protocol=GSSAPI
sasl.enabled.mechanisms=GSSAPI

为 Kerberos 认证指定相关的命令和参数:

kerberos.kinit.cmd=/usr/bin/kinit
kerberos.min.time.before.relogin=60000

9. 创建 Kafka Broker 的 JAAS 配置文件

KRaft 模式下,您依然需要为 Kafka Broker 配置 JAAS 文件,并将之前导出的密钥文件保存在keyTab配置项指定的目录。创建或修改 Kafka Broker 的 JAAS 文件,例如 kafka_server_jaas.conf

KafkaServer {
  com.sun.security.auth.module.Krb5LoginModule required
  useKeyTab=true
  keyTab="/var/kerberos/krb5kdc/kafka.keytab"
  storeKey=true
  useTicketCache=false
  principal="kafka/www.kafka.com@KAFKA.COM"
  #注意只有最后一行的结尾有分号
  serviceName="kafka";
};

10. 将JAAS配置文件路径导入当前命令行的环境变量

java命令的启动参数,用于Kafka启动时能够寻找到kafka_server_jaas.conf文件的位置,我们也可以将这个参数直接放在Kafka的启动脚本第一行。

我的文件路径是/etc/kafka/kafka_server_jaas.conf,所以我的命令如下

bash 复制代码
export KAFKA_OPTS="-Djava.security.auth.login.config=/etc/kafka/kafka_server_jaas.conf"

11. 获取TGT

通过kinit,指定密钥文件路径和主体名来获取TGT,命令如下

kinit -k -t /var/kerberos/krb5kdc/kafka.keytab kafka/www.kafka.com@REALM

通过klist可以查看我们的票据是否获取成功,结果如下:

可以看到还有过期时间,以及可续展时间。

12. 启动Kafka

正常启动,没什么好说的。

./bin/kafka-server-start.sh ./config/kraft/server.properties

13. 测试

1. 直接创建主题

当我们直接创建主题

./bin/kafka-topics.sh --create --topic test-topic --bootstrap-server 192.168.166.51:9092 --replication-factor 1 --partitions 1

得到结果如下:

可以看我们无法创建主题,可以证明此时Kafka已经没办法正常访问,现在我们需要将创建主题的命令也是用和Kafka服务一样的协议配置,并且携带票据,才能够访问。

2. 创建配置文件

创建配置文件 /kafka/config/kraft/client.properties内容如下:

security.protocol=SASL_PLAINTEXT
sasl.mechanism=GSSAPI
sasl.kerberos.service.name=kafka

sasl.kerberos.service.name配置是配置服务名,客户端在向KDC请求票据时,KDC服务器会将客户端传递的服务名,拼接上客户端请求的域名,以及领域,组成一个主题,这样可以不仅可以区分客户端请求不同的服务,还能根据客户端请求域名的不同,查询不同的主题,分配给不同客户端不同的权限。

实际生产中,服务不应该和客户端使用同一个主体,应该每一种权限的客户端一个主体,服务自己一个主体,然后通过acl分配给客户端主体不同服务的权限,来达到让客户端可以访问服务的目的,还能对客户端进行权限控制。不过我们这里主要是测试功能,所以服务和客户端使用一个主体,方便一些。

3. 创建 客户端 的 JAAS 配置文件

和服务一样,客户端想要获取票据,叶需要创建一个JAAS配置文件/etc/kafka/kafka_client_jaas.conf,文件内容也和服务端的差不多,内容如下:

KafkaClient {
   com.sun.security.auth.module.Krb5LoginModule required
   useTicketCache=true
   renewTicket=true
   useKeyTab=true
   keyTab="/var/kerberos/krb5kdc/kafka.keytab"
   principal="kafka/www.kafka.com@KAFKA.COM";
};

在测试过程中,客户端和服务器在一个主机中,并且又是同一个主体所以可以和服务器使用同一个密钥文件。配置相同路径(keyTab)即可。

4. 添加环境变量

和服务一样,不多说了

export KAFKA_OPTS="-Djava.security.auth.login.config=/etc/kafka/kafka_client_jaas.conf"
5. 获取TGT

和服务端一样,命令如下:

kinit -k -t /var/kerberos/krb5kdc/kafka.keytab kafka/www.kafka.com@REALM
6. 重新创建主题

重现创建主题,添加我们之间创建的配置文件,命令如下:

./bin/kafka-topics.sh --create --topic test-topic --bootstrap-server www.kafka.com:9092 --replication-factor 1 --partitions 1 --command-config ./config/kraft/client.properties

注意:这里一定要用域名,原因上面已经说了,会拼接这个域名,组成主体名

结果如下:

7. 验证主题是否创建成功

同样的,查询主题的命令也可以通过添加配置成功运行。命令如下:

./bin/kafka-topics.sh --list --bootstrap-server www.kafka.com:9092 --command-config ./config/kraft/client.properties

结果如下:

相关推荐
wkj0011 小时前
php操作redis
开发语言·redis·php
hzyyyyyyyu1 小时前
内网安全隧道搭建-ngrok-frp-nps-sapp
服务器·网络·安全
网络研究院1 小时前
国土安全部发布关键基础设施安全人工智能框架
人工智能·安全·框架·关键基础设施
刽子手发艺2 小时前
WebSocket详解、WebSocket入门案例
网络·websocket·网络协议
Daniel 大东3 小时前
BugJson因为json格式问题OOM怎么办
java·安全
速盾cdn6 小时前
速盾:CDN是否支持屏蔽IP?
网络·网络协议·tcp/ip
yaoxin5211236 小时前
第二十七章 TCP 客户端 服务器通信 - 连接管理
服务器·网络·tcp/ip
内核程序员kevin6 小时前
TCP Listen 队列详解与优化指南
linux·网络·tcp/ip
PersistJiao7 小时前
Spark 分布式计算中网络传输和序列化的关系(一)
大数据·网络·spark