kerberos入坑指南

原理介紹

kerberos主要是用來做網(wǎng)絡(luò)通信時(shí)候的身份認(rèn)證,最主要的特點(diǎn)就是“復(fù)雜”。所以在入坑kerberos之前,最好先熟悉一下其原理。這里推薦一些別人寫的文章內(nèi)容來進(jìn)行簡(jiǎn)單匯總:

  1. 鏈接
    kerberos認(rèn)證原理
    用對(duì)話場(chǎng)景來解釋kerbeors的設(shè)計(jì)過程

  2. 簡(jiǎn)圖


    kerberos認(rèn)證流程簡(jiǎn)圖

幾個(gè)概念的補(bǔ)充

  1. principal
    認(rèn)證的主體,簡(jiǎn)單來說就是"用戶名"

  2. realm
    realm有點(diǎn)像編程語言中的namespace。在編程語言中,變量名只有在某個(gè)"namespace"里才有意義。同樣的,一個(gè)principal只有在某個(gè)realm下才有意義。
    所以realm可以看成是principal的一個(gè)"容器"或者"空間"。相對(duì)應(yīng)的,principal的命名規(guī)則是"what_name_you_like@realm"。
    在kerberos, 大家都約定成俗用大寫來命名realm, 比如"EXAMPLE.COM"

  3. password
    某個(gè)用戶的密碼,對(duì)應(yīng)于kerberos中的master_key。password可以存在一個(gè)keytab文件中。所以kerberos中需要使用密碼的場(chǎng)景都可以用一個(gè)keytab作為輸入。

  4. credential
    credential是“證明某個(gè)人確定是他自己/某一種行為的確可以發(fā)生”的憑據(jù)。在不同的使用場(chǎng)景下, credential的具體含義也略有不同:

    • 對(duì)于某個(gè)principal個(gè)體而言,他的credential就是他的password。
    • 在kerberos認(rèn)證的環(huán)節(jié)中,credential就意味著各種各樣的ticket。

搭建一個(gè)KDC的環(huán)境

想要理解Kerberos,最好的方式是自己搭建一個(gè)KDC server。同時(shí),這對(duì)于開發(fā)過程中進(jìn)行測(cè)試也是非常有幫助的。

這里用ubuntu 16.04為例,簡(jiǎn)單搭一個(gè)kdc server

安裝下載

apt-get install krb5-admin-server krb5-kdc krb5-user krb5-config

其中,這幾個(gè)軟件包的作用分別是:

  • krb5-admin-server: kdc管理員程序,可以讓使用者遠(yuǎn)程管理kdc數(shù)據(jù)庫。
  • krb5-kdc:kdc主程序
  • krb5-user: kerberos的一些客戶端命令,用來獲取、查看、銷毀ticket等等。

配置

/etc/krb5.conf

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

[libdefaults]
 default_realm = EXAMPLE.COM
 dns_lookup_realm = false
 dns_lookup_kdc = false
 ticket_lifetime = 400
 renew_lifetime = 600
 forwardable = true
 udp_preference_limit = 1

[realms]
 EXAMPLE.COM = {
   kdc = 127.0.0.1:88
   admin_server = 127.0.0.1
 }

這個(gè)配置kdc,kerberos客戶端,以及調(diào)用kerberos api時(shí)都會(huì)使用到。
幾個(gè)重要的配置項(xiàng)目包括:

  • ticket_lifetime和renew_lifetime:指定了kdc授權(quán)ticket的過期時(shí)長(zhǎng),和允許更新現(xiàn)有ticket的時(shí)長(zhǎng)。
  • realms的section:指定了kdc和admin_server的路徑

/etc/krb5kdc/kdc.conf

[kdcdefaults]
    kdc_ports = 750,88

[realms]
    EXAMPLE.COM = {
        database_name = /etc/krb5kdc/example/principal
        admin_keytab = FILE:/etc/krb5kdc/example/kadm5.keytab
        acl_file = /etc/krb5kdc/example/kadm5.acl
        key_stash_file = /etc/krb5kdc/example/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 arcfour-hmac:normal des3-hmac-sha1:normal des-cbc-crc:normal des:normal des:v4 des:norealm des:onlyrealm des:afs3
        default_principal_flags = +preauth
    }

這是kdc的專屬配置,可以根據(jù)自己的需求修改下kdc數(shù)據(jù)庫的存放目錄。我都統(tǒng)一放/etc/krb5kdc/example目錄下了。對(duì)于這個(gè)目錄,自己需要提前建立好。

創(chuàng)建數(shù)據(jù)庫和principal

  1. 使用kdb5_util創(chuàng)建數(shù)據(jù)庫,從而可以存放principal相關(guān)的信息
kdb5_util create -r EXAMPLE.COM -s
  1. 使用kadmin.local來添加principal
root@weijiesun-kubuntu:/etc/krb5kdc# kadmin.local
Authenticating as principal root/admin@EXAMPLE.COM with password.
kadmin.local:  add_principal test-server/myhost@EXAMPLE.COM
WARNING: no policy specified for test-server/myhost@EXAMPLE.COM; defaulting to no policy
Enter password for principal "test-server/myhost@EXAMPLE.COM":
Re-enter password for principal "test-server/myhost@EXAMPLE.COM":
Principal "test-server/myhost@EXAMPLE.COM" created.
kadmin.local:  add_principal test-client/myhost@EXAMPLE.COM
WARNING: no policy specified for test-client/myhost@EXAMPLE.COM; defaulting to no policy
Enter password for principal "test-client/myhost@EXAMPLE.COM":
Re-enter password for principal "test-client/myhost@EXAMPLE.COM":
Principal "test-client/myhost@EXAMPLE.COM" created.
kadmin.local:  ktadd -k /etc/krb5.keytab test-server/myhost@EXAMPLE.COM
Entry for principal test-server/myhost@EXAMPLE.COM with kvno 2, encryption type aes256-cts-hmac-sha1-96 added to keytab WRFILE:/etc/krb5.keytab.
Entry for principal test-server/myhost@EXAMPLE.COM with kvno 2, encryption type arcfour-hmac added to keytab WRFILE:/etc/krb5.keytab.
Entry for principal test-server/myhost@EXAMPLE.COM with kvno 2, encryption type des3-cbc-sha1 added to keytab WRFILE:/etc/krb5.keytab.
Entry for principal test-server/myhost@EXAMPLE.COM with kvno 2, encryption type des-cbc-crc added to keytab WRFILE:/etc/krb5.keytab.
kadmin.local:  ktadd -k /etc/krb5.keytab test-client/myhost@EXAMPLE.COM
Entry for principal test-client/myhost@EXAMPLE.COM with kvno 2, encryption type aes256-cts-hmac-sha1-96 added to keytab WRFILE:/etc/krb5.keytab.
Entry for principal test-client/myhost@EXAMPLE.COM with kvno 2, encryption type arcfour-hmac added to keytab WRFILE:/etc/krb5.keytab.
Entry for principal test-client/myhost@EXAMPLE.COM with kvno 2, encryption type des3-cbc-sha1 added to keytab WRFILE:/etc/krb5.keytab.
Entry for principal test-client/myhost@EXAMPLE.COM with kvno 2, encryption type des-cbc-crc added to keytab WRFILE:/etc/krb5.keytab.
kadmin.local:  q
root@weijiesun-kubuntu:/etc/krb5kdc#

這里,我們創(chuàng)建了兩個(gè)新的用戶:test-server/myhost@EXAMPLE.COM和test-client/myhost@EXAMPLE.COM。并且把他們的密鑰放到/etc/krb5.keytab這一keytab文件下。

  1. 啟動(dòng)kdc
root@weijiesun-kubuntu:/etc/krb5kdc# service krb5-kdc start
 * Starting Kerberos KDC krb5kdc                                                                                                                                                       [ OK ]
root@weijiesun-kubuntu:/etc/krb5kdc# service krb5-admin-server start
 * Starting Kerberos administrative servers kadmind                                                                                                                                    [ OK ]

當(dāng)然,對(duì)于不同發(fā)行版,這一步執(zhí)行的命令可能會(huì)不太一樣。

  1. 用kinit驗(yàn)證KDC是否啟動(dòng)成功
kinit -k -t /etc/krb5.keytab test-client/myhost@EXAMPLE.COM

kinit對(duì)應(yīng)的是向kdc獲取TGT的步驟。它會(huì)向/etc/krb5.conf中指定的kdc server來發(fā)送請(qǐng)求。
如果TGT請(qǐng)求成功,你就可以用klist看到它。

weijiesun@weijiesun-kubuntu ~ $ klist
Ticket cache: FILE:/tmp/krb5cc_1000
Default principal: test-client/myhost@EXAMPLE.COM

Valid starting       Expires              Service principal
2018-08-17T13:50:25  2018-08-17T13:57:05  krbtgt/EXAMPLE.COM@EXAMPLE.COM
        renew until 2018-08-17T14:00:25

把kerberos認(rèn)證流程嵌到項(xiàng)目中

在真正使用kerberos進(jìn)行身份認(rèn)證時(shí),我們一般不直接使用kerberos的接口。而是會(huì)使用諸如GSSAPI或者SASL等更通用的一些標(biāo)準(zhǔn)接口。之所以這么做,是因?yàn)椋?/p>

  • kerberos的接口更瑣碎
  • SASL和GSSAPI都是IETF標(biāo)準(zhǔn),他們對(duì)身份認(rèn)證這一行為做了更宏觀的抽象。從而可以靈活的接入不同的認(rèn)證方案。

GSSAPI

GSSAPI的其流程基本和kerberos類似。在現(xiàn)實(shí)應(yīng)用中,你基本可以假設(shè)GSSAPI就是kerberos本身。在我們最常使用的kerberos實(shí)現(xiàn)MIT kerberos中,GSSAPI的接口也已經(jīng)是一個(gè)內(nèi)置項(xiàng)了。

比較推薦MIT官方給出的一個(gè)gssapi的sample,是學(xué)習(xí)kerberos完整認(rèn)證過程一個(gè)非常好的例子。里面也有詳細(xì)的文檔教大家如何使用:

MIT kerberos項(xiàng)目?jī)?nèi)置的gss-sample也可以拿來學(xué)習(xí)kerberos的認(rèn)證過程:

SASL

SASL是一個(gè)更加通用的身份認(rèn)證接口,其接口在設(shè)計(jì)上可以兼容很多主流的認(rèn)證方案。很多項(xiàng)目在做身份認(rèn)證的時(shí)候,也是采用的SASL接口和流程。

SASL本身也有很多的實(shí)現(xiàn),我在做小米的Pegasus項(xiàng)目時(shí),采用的是cyrus-sasl。

想把sasl集成到項(xiàng)目中,并且使用gssapi作為其中的認(rèn)證方案,其實(shí)不是特別的容易。這里給出一些要點(diǎn):

  • 從設(shè)計(jì)上而言,SASL上是一個(gè)client/server之間進(jìn)行認(rèn)證的接口。對(duì)于向KDC獲取TGT這一行為,SASL沒有預(yù)留接口。事實(shí)上,SASL在做第一步認(rèn)證時(shí),就假設(shè)用戶已經(jīng)獲取到TGT了。所以這里需要我們自己實(shí)現(xiàn)獲取TGT的代碼,也就是kinit的過程。
  • SASL的用戶名和kerberos的principal命名風(fēng)格不是完全相同的。在kerberos的標(biāo)準(zhǔn)中,principal的命名方式為name1/name2/name3/.../nameN@realm; 而在SASL中,用戶名的命名方式為username/FQDN。因而,在使用SASL的時(shí)候,一定要把username和FQDN分開傳給sasl的認(rèn)證接口,從而構(gòu)造成kerberos的principal。
  • 認(rèn)真學(xué)習(xí)cyrus-sasl的認(rèn)證示例,并參考這篇文檔
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容