Linux基础知识(16)- Kerberos (一) | Kerberos 安装配置

发布时间 2023-04-24 22:31:12作者: 垄山小站


Kerberos (Secure Network Authentication System,网络安全认证系统),是一种网络认证协议,其设计目标是通过密钥系统为 Client/Server 提供强大的认证服务。该认证过程的实现不依赖于主机操作系统的认证,无需基于的信任,不要求网络上所有主机的物理安全,并假定网络上传送的数据包可以被任意地读取、修改和插入数据。

Kerberos 协议主要用于计算机网络的身份鉴别,其特点是用户只需输入一次身份验证信息就可以凭借此验证获得的凭证(Ticket Granting Ticket)访问多个服务(即 SSO,Single Sign On),因为在每个 Client 和 Service 之间建立了共享秘钥,所以使得该协议具有相当的安全性。Kerberos 在进行认证过程中并不会传输用户的密码,而是通过传输 Tickets(票据)进行认证。

Kerberos 认证协议里的角色:

    (1) Client: 客户端,比如访问 HBase 的 Springboot 程序
    (2) Server: 服务端,本文指 HBase 服务器
    (3) KDC (Key Distribution Center):密钥颁发中心,默认安装在 DC (域控制器)上 Kerberos 的主要服务,由 AS 和 TGS 组成
    (4) AS (Authentication Server):认证服务器,认证用户身份并为其发放 TGT
    (5) TGS (Ticket Granting Server):票据授予服务器,用来发放客户端访问服务器端的 ST
    (6) TGT (Ticket Granting Ticket):票据授予票据
    (7) ST (Server Ticket):服务票据

Kerberos 协议使用的前提条件:Client、KDC 和 Server 在协议工作前已经有了各自的共享密钥,并且由于协议中的消息无法穿透防火墙,这些条件就限制了 Kerberos 协议往往用于一个组织的内部,使其应用场景不同于 X.509 PKI。

Kerberos 认证协议包含三个子协议 (Sub-Protocol)或步骤:

    (1)Authentication Service Exchange (Client 向 KDC 申请 TGT)

        Client 向 KDC 中的 AS 发送 Authentication Service Request(KRB_AS_REQ),为确保 KRB _AS_REQ 仅限于自己和 KDC 知道,Client 使用自己的 Master Key 对 KRB_AS_REQ 主体进行加密。KRB_AS _ REQ 的主体内容如下:

            Pre-authentication data:包含用于证明自己身份的信息,是一个被 Client 的 Master Key 加密过的 Timestamp
            Client name &realm:就是 Domain name\Client
            Server Name:KDC 的 TGS 的 Server Name

        AS 接受到 KRB_AS_REQ 之后,要验证 Client 的身份,AS 从 Domain 的 Account Database 获取 Client 对应的 Master Key 对 Pre-authentication data 进行解密,如果是一个合法的 Timestamp,则可以通过验证。然后 AS 将 Authentication Service Response(KRB_AS_REP)发送给 Client。KRB_ AS_REP 包含两个部分:由 Client 的 Master Key 加密过的 Logon Session Key 和被 KDC 的 Master Key 加密的 TGT。TGT 主体内容如下:

            Logon Session Key:SKDC-Client
            Client name &realm:就是 Domain name\Client
            End time:TGT 到期的时间

        Client 通过自己的 Master Key 对第一部分进行解密获得 Logon Session Key(SKDC-Client)之后,携带着 TGT 进入下一步 Ticket Granting Service Exchange

    (2) Ticket Granting Service Exchange (Client 通过获得的 TGT 向 KDC 申请用于访问 Server 的 Ticket)

        Client 向 KDC 中的 TGS 发送 Ticket Granting Service Request(KRB_TGS_REQ),KRB_TGS_REQ 主体内容如下:

            TGT:被 KDC 的 Master Key 加密过的 TGT
            Authenticator:用来证明 TGT 的拥有者是否是自己,使用 Logon Session Key 进行加密  
            Client name &realm:就是 Domain name \Client
            Server name &realm:就是 Domain name \Server

        TGS 收到 KRB_TGS_REQ 之后,要验证 Client 的身份,TGS 通过自己的 Master Key 对 Client 提供的 TGT 进行解密,得到 Logon Sesssion Key,然后在利用 Logon Sesssion Key 在对 Authenticator 进行验证,验证通过向 Client 发送 Ticket Granting Service Response(KRB_TGS_REP),KRB_TGS_REP 由两部分组成:使用 Logon Session Key 加密过的用于 Client 和 Server 的 Session Key(SServer-Client)和使用 Server 的 Master Key 进行加密的 Server Ticket。Server Ticket 主体内容如下:

            Session Key:SServer-Client
            Client name &realm:就是 Domain name\Client
            End time:Ticket 的到期时间

        Client 接收到 KRB_TGS_REP 之后,使用 Logon Session Key(SKDC-Client)解密第一部分获得 Session Key(SServer-Client),有了 Session Key 和 Server Ticket,Client 就可以和 Server 进行交互,而无需通过 KDC 作中间人。

    (3) Client/Server Exchange (Client 向 Server 提交 Ticket)

        Client 向 Server 发送 Application Server Request(KRB_AP_REQ), KRB_AP_REQ 主体内容如下:

            Server Ticket:被 Server 的 Master Key 加密过的 Server Ticket
            Authenticator:使用 Session Key 进行加密
            Flag:用于表示 Client 是否需要进行双向验证

        Server 接收到 KRB_AP_REQ,用自己的 Master Key 解密 Server Ticket,从而获得 Session Key(SServer-Client),通过 Session Key(SServer-Client)解密 Authenticator,进而验证对方身份。验证成功,让 Client 访问需要访问的资源,否则直接拒绝对方的请求。对于需要双向验证,Server 从 Authenticator 提取 Timestamp,使用 Session Key(SServer-Client)进行加密,并发送给 Client 用于 Client 验证 Server 身份。

MIT Kerberos:http://web.mit.edu/kerberos/
Kerberos: https://kerberos.org/


1. 系统环境

    操作系统:Ubuntu 20.04

    本文 Kerberos 的客户端和服务端都安装在同一台主机上,主机名为 hadoop-master-vm。

 

2. 部署 Kerberos

    1) 安装 Kerberos 服务端

        # 安装 kdc 和 admin-server
        $ sudo apt-get install -y krb5-kdc krb5-admin-server

            # 安装过程选项如下
            Default Kerberos version 5 realm?
            
                hadoop.com

            Kerberos servers for your realm:
                
                hadoop-master-vm

            Administrative server for your Kerberos realm:
            
                hadoop-master-vm


            注:realm 是 Kerberos 中的域,类似于计算机网络中 "domain" 概念。

        # 安装客户端
        $ sudo apt-get install -y krb5-user libkrb5-dev \
                        libpam-krb5 libpam-ccreds

            注:libkrb5-dev 是 MIT Kerberos 客户端 C 开发库,pam-krb5、libpam-ccreds 与认证、授权、用户票据缓存处理等功能的 Kerberos v5 PAM 模块相关。              

        # 设置 realm,初始化 kerberos 数据库
        $ sudo krb5_newrealm

            This script should be run on the master KDC/admin server to initialize
            a Kerberos realm.  It will ask you to type in a master key password.
            This password will be used to generate a key that is stored in
            /etc/krb5kdc/stash.  You should try to remember this password, but it
            is much more important that it be a strong password than that it be
            remembered.  However, if you lose the password and /etc/krb5kdc/stash,
            you cannot decrypt your Kerberos database.
            Loading random data
            Initializing database '/var/lib/krb5kdc/principal' for realm 'hadoop.com',
            master key name 'K/M@hadoop.com'
            You will be prompted for the database Master Password.
            It is important that you NOT FORGET this password.

            Enter KDC database master key: 123456
            Re-enter KDC database master key to verify: 123456


            注:也可以使用 kdb5_util 命令初始化 kerberos 数据库,格式如下:

                $ kdb5_util create -s -r hadoop.com

                参数说明:

                    -r 指定域名 (krb5.conf 文件 [realms] 组里面定义的域名)
                    -s 指定将数据库的主节点密钥存储在文件中,从而可以在每次启动 KDC 时自动重新生成主节点密钥

                    默认的数据库名字都是 principal。可以使用 -d 指定数据库名字。

        # 查看 Kerberos 版本
        $ klist -V

            Kerberos 5 version 1.17

    2) 修改配置文件

        (1) 修改 krb5.conf

          krb5.conf 是 Kerberos 的主配置文件,可以配置 KDC、AS、Kerberos 域等。该文件也是 Kerberos 客户端的配置文件,客户端使用 kinit 通过 KDC 进行身份验证,该文件就会被读取。

            # 在 krb5.conf 最后添加 logging 配置
            $ sudo vim /etc/krb5.conf

                [realms]
                    hadoop.com = {
                        kdc = hadoop-master-vm
                        admin_server = hadoop-master-vm
                    }

                ...

                [logging]
                    kdc = FILE:/var/log/kerberos/krb5kdc.log
                    admin_server = FILE:/var/log/kerberos/kadmin.log
                    default = FILE:/var/log/kerberos/krb5lib.log


            # 创建 log 目录
            $ sudo mkdir /var/log/kerberos
            $ sudo chmod -R 750  /var/log/kerberos

        (2) 查看 kdc.conf

            kdc.conf 是 KDC 的配置文件,这里使用默认设置,不做修改。

            $ sudo cat /etc/krb5kdc/kdc.conf

                [kdcdefaults]
                    kdc_ports = 750,88

                [realms]
                    hadoop.com = {
                        database_name = /var/lib/krb5kdc/principal
                        admin_keytab = FILE:/etc/krb5kdc/kadm5.keytab
                        acl_file = /etc/krb5kdc/kadm5.acl
                        key_stash_file = /etc/krb5kdc/stash
                        kdc_ports = 750,88
                        max_life = 10h 0m 0s
                        max_renewable_life = 7d 0h 0m 0s
                        master_key_type = des3-hmac-sha1
                        #supported_enctypes = aes256-cts:normal aes128-cts:normal
                        default_principal_flags = +preauth
                    }


        (3) 修改 kadm5.acl

            kadm5.acl 是 Kerberos 数据库权限管理的配置文件,可以通过修改 kdc.conf 文件的 acl_file 属性改变 acl 文件的位置。

            $ sudo vim /etc/krb5kdc/kadm5.acl

                # This file Is the access control list for krb5 administration.
                # When this file is edited run service krb5-admin-server restart to activate
                # One common way to set up Kerberos administration is to allow any principal
                # ending in /admin  is given full administrative rights.
                # To enable this, uncomment the following line:
                */admin *


                注:* 号是通配符,表示类似 “abc/admin” 或 “xxx/admin” 的用户都可以使用此工具(远程或本地)管理 Kerberos 数据库,后一个 * 跟权限有关,* 表示所有权限,还可以进行更细的控制,参见 ACL (http://web.mit.edu/kerberos/krb5-1.12/doc/admin/conf_files/kadm5_acl.html)。

        (4) 重启服务

            $ sudo systemctl restart krb5-kdc
            $ sudo systemctl restart krb5-admin-server


3. kadmin 管理工具

    kadmin 管理工具是用来管理 Kerberos V5 系统的主体或账号(principals)、密码策略(policy)、Service key tables(keytabs) 等功能,包含 kadmin 和 kadmin.local 两个命令行接口。

    kadmin 和 kadmin.local 两者基本上提供相同的功能,区别是 kadmin.local 直接访问 KDC 数据库,而 kadmin 通过 kadmind 来执行操作。
    
    kadmin.local 直接访问 KDC 数据库,因此它只能运行在 KDC 所在主机上,并有足够的权限来访问 KDC 的数据库。如果 KDC 数据库使用 LDAP 数据库模块,kadmin.local 可以运行在能访问 LDAP 服务器的机器上。   

    1) kadmin.local 两种运行模式

        # 进入交互程序,查看 Principal
        $ sudo kadmin.local

            Authenticating as principal root/admin@hadoop.com with password.
            kadmin.local: list_requests   # 或输入 lr 和 ?,显示所有子命令和命令的简写

                ...

            kadmin.local: listprincs

                K/M@hadoop.com
                kadmin/admin@hadoop.com
                kadmin/changepw@hadoop.com
                kadmin/hadoop-master-vm@hadoop.com
                kiprop/hadoop-master-vm@hadoop.com
                krbtgt/hadoop.com@hadoop.com

            kadmin.local: quit      # 或 q 退出 kadmin 


        # 使用 -q 参数,不进入交互直接输出结果
        $ sudo kadmin.local -q listprincs

            K/M@hadoop.com
            kadmin/admin@hadoop.com
            kadmin/changepw@hadoop.com
            kadmin/hadoop-master-vm@hadoop.com
            kiprop/hadoop-master-vm@hadoop.com
            krbtgt/hadoop.com@hadoop.com


    2) 密码策略 (Policy)

        # 添加/修改/删除策略
        $ sudo kadmin.local

            Authenticating as principal root/admin@hadoop.com with password.

            # 添加 4 个策略,规定最小密码长度和最少包含几种字符类型
            kadmin.local:  add_policy -minlength 8 -minclasses 3 admin
            kadmin.local:  add_policy -minlength 8 -minclasses 4 host
            kadmin.local:  add_policy -minlength 8 -minclasses 4 service
            kadmin.local:  add_policy -minlength 8 -minclasses 2 user

            # 列出所有策略
            kadmin.local:  listpols

                admin
                host
                service
                user

            # 查看 service 策略
            kadmin.local:  getpol service

                Policy: service
                Maximum password life: 0 days 00:00:00
                Minimum password life: 0 days 00:00:00
                Minimum password length: 8
                Minimum number of password character classes: 4
                Number of old keys kept: 1
                Maximum password failures before lockout: 0
                Password failure count reset interval: 0 days 00:00:00
                Password lockout duration: 0 days 00:00:00

            # 修改 service 策略
            kadmin.local: modpol -minclasses 3 service

            # 删除 service 策略
            kadmin.local: delpol service

                Are you sure you want to delete the policy "service"? (yes/no): y:es

            kadmin.local: q


    3) 主体或账号 (Principal)

        # 添加/删除主体
        $ sudo kadmin.local

            Authenticating as principal root/admin@hadoop.com with password.

            # 创建 1 个特权主体 (privileged principal),使用 admin 策略
            kadmin.local: addprinc -policy admin root/admin

                Enter password for principal "root/admin@hadoop.com": test123ABC
                Re-enter password for principal "root/admin@hadoop.com": test123ABC
                Principal "root/admin@hadoop.com" created.

            # 创建 1 个无特权主体(unprivileged principal),使用 user 策略,需输入密码
            kadmin.local: addprinc -policy user demo

                Enter password for principal "demo@hadoop.com": test1234
                Re-enter password for principal "demo@hadoop.com": test1234
                Principal "demo@hadoop.com" created.

            # 创建 1 个无特权主体,使用随机密码
            kadmin.local: addprinc -randkey demo2

                Principal "demo2@hadoop.com" created.

            # 列出所有主体
            kadmin.local: listprincs

                K/M@hadoop.com
                demo@hadoop.com
                demo2@hadoop.com
                kadmin/admin@hadoop.com
                kadmin/changepw@hadoop.com
                kadmin/hadoop-master-vm@hadoop.com
                kiprop/hadoop-master-vm@hadoop.com
                krbtgt/hadoop.com@hadoop.com
                root/admin@hadoop.com

            # 删除 root/admin 主体

                kadmin.local:  delprinc  root/admin
                Are you sure you want to delete the principal "root/admin@hadoop.com"? (yes/no): yes
                Principal "root/admin@hadoop.com" deleted.

            kadmin.local: q


    4) 导出 keytab

        $ cd ~/krb5     # 这里使用当前 linux 用户的根目录下的 krb5 目录存放 *.keytab 文件
        $ sudo kadmin.local

            Authenticating as principal root/admin@hadoop.com with password.

            # 使用 xst 命令会在当前目录下生成 demo.keytab 文件,-norandkey 确保初始密码有效
            kadmin.local: xst -k demo.keytab -norandkey demo@hadoop.com

                Entry for principal demo@hadoop.com with kvno 1, encryption type aes256-cts-hmac-sha1-96 added to keytab WRFILE:demo.keytab.
                Entry for principal demo@hadoop.com with kvno 1, encryption type aes128-cts-hmac-sha1-96 added to keytab WRFILE:demo.keytab.

            # 也可以使用 ktadd 命令
            kadmin.local: ktadd -k demo2.keytab -norandkey demo@hadoop.com

                Entry for principal demo@hadoop.com with kvno 1, encryption type aes256-cts-hmac-sha1-96 added to keytab WRFILE:demo2.keytab.
                Entry for principal demo@hadoop.com with kvno 1, encryption type aes128-cts-hmac-sha1-96 added to keytab WRFILE:demo2.keytab.

            kadmin.local: q


    5) kadmin 命令

        # 指定 demo 主体运行
        $ sudo kadmin -p demo

            Authenticating as principal demo with password.
            Password for demo@hadoop.com: test1234
            kadmin:  listprincs

                get_principals: Operation requires ``list'' privilege while retrieving list.

            kadmin:  q 


            注:demo 主体没有 list 权限。

        # 指定 demo2 主体运行
        $ sudo kadmin -p demo2

            Authenticating as principal demo2 with password.
            Password for demo2@hadoop.com:
            kadmin: Preauthentication failed while initializing kadmin interface

            注:demo2 主体使用了随机密码,无法运行。

        # 无参数运行
        $ sudo kadmin

            Authenticating as principal root/admin@hadoop.com with password.
            kadmin: Client 'root/admin@hadoop.com' not found in Kerberos database while initializing kadmin interface

            注:无参数运行会默认使用 root/admin 主体,在 kadmin.local 命令部分,我们创建了 root/admin 主体,并删除了 root/admin,此时 Kerberos 数据库里没有 root/admin。

        # 再次创建 root/admin 主体,密码 test123ABC,无参数运行
        $ sudo kadmin

            Authenticating as principal root/admin@hadoop.com with password.
            Password for root/admin@hadoop.com: test123ABC
            kadmin:  listprincs

                K/M@hadoop.com
                demo@hadoop.com
                kadmin/admin@hadoop.com
                kadmin/changepw@hadoop.com
                kadmin/hadoop-master-vm@hadoop.com
                kiprop/hadoop-master-vm@hadoop.com
                krbtgt/hadoop.com@hadoop.com
                root/admin@hadoop.com

            kadmin: q


        # 指定 root/admin 主体运行
        $ sudo kadmin -p root/admin

            Authenticating as principal root/admin with password.
            Password for root/admin@hadoop.com: test123ABC
            kadmin:

                ...

            kadmin:  q


4. Ticket 管理工具

    1) kinit 命令

        # 创建 demo 主体的 Ticket,需要输入密码
        $ kinit demo

            Password for demo@hadoop.com: test1234

        # 查看 Ticket 列表
        $ klist -f

            Ticket cache: FILE:/tmp/krb5cc_1000
            Default principal: demo@hadoop.com

            Valid starting       Expires              Service principal
            2023-04-19T20:51:52  2023-04-20T06:51:52  krbtgt/hadoop.com@hadoop.com
                    renew until 2023-04-20T20:51:39, Flags: FPRIA


        # 销毁 Ticket
        $ kdestroy -p demo

        # 查看 Ticket 列表
        $ klist -f

            klist: No credentials cache found (filename: /tmp/krb5cc_1000)

        # 使用上文的 keytab 创建 demo 主体的 Ticket,不需要输入密码
        $ cd ~/krb5
        $ kinit -kt ./demo.keytab demo    

    2) klist 命令

        # 查看 Ticket 列表
        $ klist -f

            Ticket cache: FILE:/tmp/krb5cc_1000
            Default principal: demo@hadoop.com

            Valid starting       Expires              Service principal
            2023-04-19T20:52:49  2023-04-20T06:52:49  krbtgt/hadoop.com@hadoop.com
                    renew until 2023-04-20T20:52:44, Flags: FPRIA


        # 查看 keytab
        $ cd ~/krb5
        $ klist -k -t -e ./demo.keytab

            Keytab name: FILE:./demo.keytab
            KVNO Timestamp           Principal
            ---- ------------------- ------------------------------------------------------
               1 2023-04-19T20:02:05 demo@hadoop.com (aes256-cts-hmac-sha1-96)
               1 2023-04-19T20:02:05 demo@hadoop.com (aes128-cts-hmac-sha1-96)


    3) 其它命令

        # 销毁默认 Ticket
        $ kdestroy

        # 修改 kerberos 主体密码
        $ kpasswd

        # 管理 keytab 文件
        $ cd ~/krb5
        $ ktutil

          ktutil: ?

            clear_list, clear        Clear the current keylist.
            read_kt, rkt             Read a krb5 keytab into the current keylist.
            read_st, rst             Read a krb4 srvtab into the current keylist.
            write_kt, wkt            Write the current keylist to a krb5 keytab.
            write_st, wst            Write the current keylist to a krb4 srvtab.
            add_entry, addent        Add an entry to the current keylist.
            delete_entry, delent     Delete an entry from the current keylist.
            list, l                  List the current keylist.
            list_requests, lr, ?     List available requests.
            quit, exit, q            Exit program.

          ktutil: read_kt ./demo.keytab
          ktutil: list

            ---- ---- ---------------------------------------------------------------------
               1    1                          demo@hadoop.com
               2    1                          demo@hadoop.com