鳥哥的 Linux 私房菜

利用 kerberos 提供票據加密

最近更新日期:2017/11/27

我們知道很多身份驗證都會透過類似 LDAP 之類的方式來驗證你的身份,然後透過 NFS 或者是 SAMBA 等檔案系統的協助,來讓你取得工作目錄。 雖然 LDAP 可以透過加密通道來讓你的用戶在輸入帳密時,不至於有密碼外露的風險,但是在檔案系統方面,若是透過 NFS 的傳輸,那就麻煩了! 因為 NFS 不會理會身份驗證,同時也不會進行傳輸加密啊!此時,一個簡單的票據給予的加密,透過 kerberos 就行了!所以, 底下我們就來簡單的玩一玩 kerberos 這個玩意兒吧!

1、關於 kerberos

如果你有一個自己使用的環境,這個環境的資料傳輸主要是透過明碼傳遞,而這個明碼傳遞的協定就只有明碼傳輸的協定,並沒有其他的加密機制存在, 這時你該如何是好?我們知道 ssh 的協定使用非對稱式金鑰系統來作為加密與解密之用,那麼如果像上面這個情境,舉例來說,使用明碼傳輸的 NFS 協定時, 你又想要加密,那能不能使用金鑰系統的方式來處理呢?可以的,那就是 kerberos 多種運用方式當中的一種!

1.1、什麼是 kerberos ?

根據維基百科 (註1) 的說明,kerberos 就是一種計算機網路的授權協議,可以用在非安全的網路環境中, 對個人通信以安全的手段進行身份認證。同時,客戶端與伺服器端均可向對方進行身份認證,因此可用於防止竊聽,保護資料完整性的應用中。 基本上, kerberos 是透過對稱式金鑰的方式來進行資料加密的,與 ssh 的非對稱式金鑰不同喔!不過,至少都有加密的用途!

在鳥哥的伺服器篇裡面的 ssh 章節曾經談過金鑰系統的運作, 一般來說,伺服器與客戶端都需要產生一對非對稱的金鑰,然後互相交換公鑰之後,再以這兩對金鑰系統進行連線資料加密的行為。 那確認這把金鑰的唯一手段,就是與第一次連線時的公鑰紀錄做比對,若比對成功則代表這個 server 應該是原本的那個 server。 問題是,server 如何確認 client 的來源也是正確的?此外,如果第一次連線的時候,那部 server 本身就有問題, 那你怎麼確認該 server 是真的你要去的那一部?

因此,在 kerberos 的運作中,首先整個 kerberos 系統就需要一部『可信賴的第三方』,這一台 server 是大家都信任的, 這是一個大前提!也就是說,大家都得要承認,只要是這部 server 驗證成功的,那就是合法的一個成員。 這部大家都公認的第三方 server 定義上被稱為金鑰分發中心 (Key Distribution Center, KDC)。

那麼在整個架構裡面,到底是如何達成資料加密的呢?首先有個大前提,就是所有的主機 (不論是 server 端還是 client 端) 都需要加入 kerberos 服務內, 所有的主機都必須要向 kerberos KDC 請求一個票據 (ticket),且 KDC 必須要針對這個要求的來源設定好相對應的規則設定 (principal), 因此所有的主機就能夠根據這個對應的票據來跟 KDC 驗證後,並要求給予加密的金鑰資料了。

一般來說,KDC 除了發放票據與金鑰之外,同時也負責身份驗證的功能 (Authentication Server, AS),如下圖所示,右上角那部 AS 你可以想像,他就是 KDC 了。 那麼當用戶端想要連線到伺服器 (Service Server, SS) 時,想要同時取得一把能夠進行資料加密的金鑰,他的流程是怎麼跑得呢?

  1. 用戶端先透過票據資料 (ticket) 的內容,根據規定的加密方式直接向 AS 伺服器提出要求:
    • AS 根據用戶端的要求並搭配內部已紀錄 (principal) 的資料做比對,以確認該用戶的身份是否為正確。 若正確才開始給予後續的驗證,否則就直接拒絕用戶端的要求。
    • 回傳給用戶端 (1)client-to-server 的票據資料,以及 (2)cient-to-server 的加密金鑰
  2. 用戶端取得票據資料與加密金鑰後,向伺服器 (下圖中右下角的伺服器, SS) 提出連線要求:
    • SS 取得用戶端的連線要求後,會以自己的票據資料向 AS 進行驗證,同樣的, AS 也會先確認 SS 的身份是否正確, 若正確才會持續提供後續的動作。
    • SS 會向 AS 提出 client 送來的資料是否為 AS 授權的資訊?若 AS 回傳為正確,則 SS 會接受該 client-to-server 的加密金鑰, 然後開始透過該加密金鑰讓 client/server 之間的傳輸加密。(所以 client/server 都使用同一把加密金鑰,這就是對稱式金鑰系統)
kerberos 驗證示意圖
圖 1.1-1、kerberos 驗證示意圖(註1)

上述的流程鳥哥已經簡化過相當多的步驟,如果想要更清楚的了解 kerberos 在這三方 (AS, Client, SS) 的交談,還是建議到 wiki 查一下更多的資料來閱讀較佳。


1.2、一個簡單的應用範例

那麼 kerberos 可以應用在哪些『不具備加密傳輸』的環境中,幫助 server/client 進行加密呢?最簡單的一個案例,就是 NFS 囉! 不過,老實說,鳥哥的 NFS 應用環境都在 cluster 的內部傳輸,倒是不太可能傳輸到整個 LAN 裡面去,所以從來沒有想過 NFS 需要加密~ 但是,最近由於工作環境內的大量的 server 經常都得要更改 ssh port 好繞過 gateway 的管控,結果導致某些 server 就沒有受到良好的管理。 因此,最近的作法,就是只讓 LAN 內的一部 firewall server 承受外部的登入,然後再透過這部 firewall server 登入到內部的 LAN server。 如此一來,我就可以關閉 LAN server 的 ssh port 導向,且單純僅放行 firewall server 的 ssh 連線。

不過如此一來也衍生出一些問題,那就是每個用戶都喜歡有自己的工作目錄與家目錄,因此,就有共用 NFS 目錄的需求了。 但此時 NFS 就是透過整個 LAN 在傳輸資料,眾所皆知的,NFS 當然是沒有加密的協定~因此,這個時候,可以協助加密的 kerberos 就派上用場囉!

要達成這個目的有幾個重要的項目得要完成:

  • 所有的 LAN server 都要加入同一個 kerberos 的領域中 (realm):
    • 由於票據是有時間性的,所以最好所有的主機都加入同一部 NTP 服務內
    • 需要建置 KDC 來提供用戶端票據的取得
    • 所有的 LAN server 都需要從 KDC 取得票據資料
  • 讓 LAN Server 與 LAN client 的服務加上 kerberos 的支援!

要完成這個練習,我們至少就需要:

  • 一部 Kerberos KDC 伺服器
  • 一部加入 kerberos 領域的 NFS server
  • 一部加入 kerberos 領域的 NFS client

下個小節開始,我們就一步一步的完成各項設定吧!


2、設定 kerberos 領域 KDC 與 workstation

在處理 kerberos 之前,最好能夠先就整個網路規劃一番,避免未來出問題啊~

2.1、事先設定:網路主機名稱一定要正確,且時間也要正確

在 1.1 裡面談到 kerberos 的 KDC 會給予用戶端票據 (ticket) 資料,讓他們有權以及透過票據內規定的方式來進行通訊的加密與登入等行為。 而票據裡面紀錄的就是每部主機的主機名稱囉!因此,一開始指定好主機名稱與 IP 的對應是最重要的一件事。否則未來 KDC 會無法判斷用戶的來源啊!

一般來說,紀錄主機名稱與 IP 對應的正統方法,應該是使用 DNS 解析比較妥當,因為是 DNS server 統一控制的,在未來處理方面會比較單純。 不過在這個小章節裡面,我們主要是想要了解 kerberos 的運作方式而已,因此預設只使用 /etc/hosts 來進行 IP 與主機名稱的對應而已。 在這個章節中,我們的 IP 與主機名稱對應主要是以底下的方式來規劃的:

  • kerberos KDC: kdc.book.vbird: 10.0.0.101/24
  • NFS Server: server.book.vbird: 10.0.0.102/24
  • NFS client: client.book.vbird: 10.0.0.103/24

我們使用 CentOS 7.4 的系統來設定(請更新到最新環境),同時預設使用 NetworkManager 來管理網路環境。在 kerberos KDC 伺服器上面,你可以使用底下的方式來處理你的網路環境。至於其他兩部系統,就請自行設定囉!

[root@kdc ~]# nmcli connection modify eth0 ipv4.method manual ipv4.addresses 10.0.0.101/24 \
> ipv4.gateway 10.0.0.254 ipv4.dns 168.95.1.1
[root@kdc ~]# nmcli connection up eth0
[root@kdc ~]# hostnamectl set-hostname kdc.book.vbird
[root@kdc ~]# hostname
kdc.book.vbird
[root@kdc ~]# vim /etc/hosts
127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
::1         localhost localhost.localdomain localhost6 localhost6.localdomain6
10.0.0.101      kdc.book.vbird          kdc
10.0.0.102      server.book.vbird       server
10.0.0.103      client.book.vbird       client

另外的兩部系統可以在建立網路之後,在直接以 scp 的方式將 /etc/hosts 在不同的電腦系統間複製即可!無須重複編輯啦! 至於時間伺服器就使用 chronyd 來處理即可!如下所示:

[root@kdc ~]# vim /etc/chrony.conf
server ntp.ksu.edu.tw iburst
driftfile /var/lib/chrony/drift
makestep 1.0 3
rtcsync
allow 10.0.0.0/24
logdir /var/log/chrony
# 鳥哥有改變的地方只有上述兩個特殊字體部份,其他的倒是沒有修改。不過 server 僅保留一個即可。

[root@kdc ~]# systemctl restart chronyd
[root@kdc ~]# systemctl enable chronyd
[root@kdc ~]# systemctl status chronyd
● chronyd.service - NTP client/server
   Loaded: loaded (/usr/lib/systemd/system/chronyd.service; disabled; vendor preset: enabled)
   Active: active (running) since 一 2017-11-27 11:47:09 CST; 7s ago
     Docs: man:chronyd(8)
           man:chrony.conf(5)
  Process: 2273 ExecStartPost=/usr/libexec/chrony-helper update-daemon (code=exited, status=0/SUCCESS)
  Process: 2269 ExecStart=/usr/sbin/chronyd $OPTIONS (code=exited, status=0/SUCCESS)
 Main PID: 2271 (chronyd)
   CGroup: /system.slice/chronyd.service
           └─2271 /usr/sbin/chronyd

11月 27 11:47:09 kdc.book.vbird systemd[1]: Starting NTP client/server...
11月 27 11:47:09 kdc.book.vbird chronyd[2271]: chronyd version 3.1 starting (+CMDMON ...)
11月 27 11:47:09 kdc.book.vbird systemd[1]: Started NTP client/server.
11月 27 11:47:14 kdc.book.vbird chronyd[2271]: Selected source 120.114.100.1
11月 27 11:47:14 kdc.book.vbird chronyd[2271]: System clock wrong by 2.308642 seconds, adjustment started
11月 27 11:47:16 kdc.book.vbird chronyd[2271]: System clock was stepped by 2.308642 seconds
# 至少要看到上面的特殊字體,才代表你已經連上那個上層 NTP 服務!

[root@kdc ~]# firewall-cmd --add-rich-rule='rule family="ipv4" source address="10.0.0.0/24" accept'
[root@kdc ~]# firewall-cmd --add-rich-rule='rule family="ipv4" source address="10.0.0.0/24" accept' --permanent

後續還有很多的服務得要放行給用戶端,所以這邊先乾脆針對整個區網來放行網路的連線囉!接下來也請處理 server.book.vbird 以及 client.vbird.book 這兩個系統的 chrony 設定:

[root@server ~]# vim /etc/chrony.conf
server 10.0.0.101 iburst
driftfile /var/lib/chrony/drift
makestep 1.0 3
rtcsync
logdir /var/log/chrony

[root@server ~]# systemctl restart chronyd
[root@server ~]# systemctl enable chronyd
[root@server ~]# systemctl status chronyd
● chronyd.service - NTP client/server
   Loaded: loaded (/usr/lib/systemd/system/chronyd.service; enabled; vendor preset: enabled)
   Active: active (running) since 一 2017-11-27 11:55:10 CST; 16s ago
     Docs: man:chronyd(8)
           man:chrony.conf(5)
 Main PID: 2161 (chronyd)
   CGroup: /system.slice/chronyd.service
           └─2161 /usr/sbin/chronyd

11月 27 11:55:10 server.book.vbird systemd[1]: Starting NTP client/server...
11月 27 11:55:10 server.book.vbird chronyd[2161]: chronyd version 3.1 starting (+CMDMON +NTP ...)
11月 27 11:55:10 server.book.vbird systemd[1]: Started NTP client/server.
11月 27 11:55:14 server.book.vbird chronyd[2161]: Selected source 10.0.0.101
11月 27 11:55:14 server.book.vbird chronyd[2161]: System clock wrong by 3.542148 seconds, adjustment started
11月 27 11:55:18 server.book.vbird chronyd[2161]: System clock was stepped by 3.542148 seconds

同樣的, client.book.vbird 也要設定妥當喔!


2.2、設定 KDC 伺服器

KDC server 需要有三個軟體,包括 krb5-server, krb5-workstation, krb5-libs 等等,同時,要設定 KDC 時,我們要先來宣告 kerberos 的領域 (realm) 才行! 在此,我們假設使用的 kerberos 領域為 BOOK.VBIRD,請注意,要用大寫!只要是寫到 kerberos 的領域名,都請使用大寫來處理。 而一般主機名稱與 DNS 的主機名稱階段,則請使用小寫字元,這個習慣還挺奇特的~那就一步一步處理先!

# 1. 先安裝所需要的軟體
[root@kdc ~]# yum install krb5-server krb5-workstation krb5-libs

# 2. 開始編輯主要設定檔,位於 /etc/krb5.conf 喔!
[root@kdc ~]# vim /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
 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
 default_realm = BOOK.VBIRD
 default_ccache_name = KEYRING:persistent:%{uid}
 dns_lookup_kdc = false

[realms]
 BOOK.VBIRD = {
  kdc = kdc.book.vbird
  admin_server = kdc.book.vbird
 }

[domain_realm]
 .book.vbird = BOOK.VBIRD
 book.vbird = BOOK.VBIRD

# 3. 接下來請開始建置 KDC 所需要的資料庫環境!
[root@kdc ~]# ll /var/kerberos/krb5kdc/
-rw-------. 1 root root  22  4月 29  2017 kadm5.acl
-rw-------. 1 root root 451  4月 29  2017 kdc.conf
# 如上所示,一開始資料庫目錄底下並沒有資料庫檔案的生成!

[root@kdc ~]# kdb5_util create -s
Loading random data
Initializing database '/var/kerberos/krb5kdc/principal' for realm 'BOOK.VBIRD',
master key name 'K/M@BOOK.VBIRD'
You will be prompted for the database Master Password.
It is important that you NOT FORGET this password.
Enter KDC database master key:  <==這裡輸入密碼,不要忘記她!
Re-enter KDC database master key to verify:  <==再輸入一次

[root@kdc ~]# ll /var/kerberos/krb5kdc/
-rw-------. 1 root root   22  4月 29  2017 kadm5.acl
-rw-------. 1 root root  451  4月 29  2017 kdc.conf
-rw-------. 1 root root 8192 11月 27 12:04 principal
-rw-------. 1 root root 8192 11月 27 12:04 principal.kadm5
-rw-------. 1 root root    0 11月 27 12:04 principal.kadm5.lock
-rw-------. 1 root root    0 11月 27 12:04 principal.ok
# 資料庫檔案就這樣生成了!

由於 KDC 主要的目的在分發金鑰給所有的 kerberos 用戶端,且同時會根據用戶端的票據資料來提供驗證與加密金鑰的分派, 所以得要紀錄所有的用戶端來源,當然就需要有資料庫系統的支援才可以!因此,在修改 /etc/krb5.conf 之後,得要初始化資料庫才行。 同時,也得要加入一個資料庫管理的密碼~當然,未來還可以在新增其他的管理員名單啦!

最後,我們得要規範哪些用戶端可以管理資料庫?如果沒有規範的話,預設是僅有 KDC 伺服器本身可以透過內建的機制去管理的。 但是,鳥哥的經驗裡面,似乎透過 kerberos 用戶端去建立票據資料比較不會有問題~所以,這裡建議還是提供至少一個管理員名單, 讓用戶端可以透過這個管理員來管理 KDC 資料庫較佳。因此,我們得要修改資料庫存取設定檔,放行全部的管理員名單吧!

[root@kdc ~]# vim /var/kerberos/krb5kdc/kadm5.acl
*/admin@BOOK.VBIRD      *

其實就只有將原本的 EXAMPLE.COM 改成我們的 kerberos 領域而已。另外,基本上,想要管理 KDC 的資料庫有兩種方式, 一種直接在 KDC 本機上面直接執行,可以不需要密碼就登入資料庫管理;一種則是需要輸入帳密才能管理~這兩種管理方式分別是:

  • kadmin.local:需要在 KDC server 上面運作,無須密碼即可管理資料庫
  • kadmin:可以在任何一台 KDC 領域的系統上面運作,但是需要輸入管理員密碼

我們想要讓 KDC 用戶端也能夠『使用 root 身份來登入 KDC 資料庫的管理』,這個身份在 KDC 裡面被稱為『 root/admin 』! 則請在 KDC server 上面使用 kadmin.local 來執行底下的指令,以建立好相關的帳號囉!

[root@kdc ~]# kadmin.local
Authenticating as principal root/admin@BOOK.VBIRD with password.
kadmin.local:  ?  # 你可以透過 ? 來了解所有的指令用途!
Available kadmin.local requests:

add_principal, addprinc, ank
                         Add principal
delete_principal, delprinc
                         Delete principal
modify_principal, modprinc
                         Modify principal
rename_principal, renprinc
                         Rename principal
change_password, cpw     Change password
get_principal, getprinc  Get principal
list_principals, listprincs, get_principals, getprincs
                         List principals
....(其他省略)....

kadmin.local:  addprinc root/admin
WARNING: no policy specified for root/admin@BOOK.VBIRD; defaulting to no policy
Enter password for principal "root/admin@BOOK.VBIRD":   <==這裡輸入管理員密碼
Re-enter password for principal "root/admin@BOOK.VBIRD":  <==再輸入一次
Principal "root/admin@BOOK.VBIRD" created.

kadmin.local:  listprincs
K/M@BOOK.VBIRD
kadmin/admin@BOOK.VBIRD
kadmin/changepw@BOOK.VBIRD
kadmin/kdc.book.vbird@BOOK.VBIRD
kiprop/kdc.book.vbird@BOOK.VBIRD
krbtgt/BOOK.VBIRD@BOOK.VBIRD
root/admin@BOOK.VBIRD  <==這就是管理員的功能設定!

kadmin.local:  exit

到這裡為止,我們的 KDC 伺服器就建置的差不多了~接下來,就是直接啟動兩個相關的服務吧!並且觀察一下服務啟動的狀態囉!

[root@kdc ~]# systemctl start kadmin krb5kdc
[root@kdc ~]# systemctl enable kadmin krb5kdc
[root@kdc ~]# systemctl status kadmin krb5kdc
[root@kdc ~]# netstat -tlunp
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 0.0.0.0:749             0.0.0.0:*               LISTEN      3510/kadmind
tcp        0      0 0.0.0.0:464             0.0.0.0:*               LISTEN      3510/kadmind
tcp        0      0 0.0.0.0:88              0.0.0.0:*               LISTEN      3512/krb5kdc
tcp6       0      0 :::749                  :::*                    LISTEN      3510/kadmind
tcp6       0      0 :::464                  :::*                    LISTEN      3510/kadmind
tcp6       0      0 :::88                   :::*                    LISTEN      3512/krb5kdc
udp        0      0 0.0.0.0:464             0.0.0.0:*                           3510/kadmind
udp        0      0 0.0.0.0:88              0.0.0.0:*                           3512/krb5kdc
udp6       0      0 :::464                  :::*                                3510/kadmind
udp6       0      0 :::88                   :::*                                3512/krb5kdc

其實啟動的服務還挺多的~不過主要的埠口其實是在 port 88 上面~但是如果你需要讓 KDC client 可以登入的話,那就得要放行 port 749 才行! 如果你使用的是 firewalld 的管理機制,那就還挺簡單的,透過 --add-service={kerberos|kadmin|kpasswd} 三條指令來處理就可以了!如果使用單純的 iptables 規則, 請分別加上 TCP 的 port 88, 749, 464 以及 UDP port 88, 464 喔! (其實,我們在前一小節已經放行了整個區網的連線要求, 所以這幾個規則沒有設定其實也沒關係的喔!)

[root@kdc ~]# firewall-cmd --add-service=kerberos
[root@kdc ~]# firewall-cmd --add-service=kerberos --permanent
[root@kdc ~]# firewall-cmd --add-service=kadmin
[root@kdc ~]# firewall-cmd --add-service=kadmin --permanent
[root@kdc ~]# firewall-cmd --add-service=kpasswd
[root@kdc ~]# firewall-cmd --add-service=kpasswd --permanent

再來,讓我們在自己的 KDC 上面透過 kadmin 從網路登入看看能不能成功喔?

[root@kdc ~]# kadmin
Authenticating as principal root/admin@BOOK.VBIRD with password.
Password for root/admin@BOOK.VBIRD:  <==請輸入密碼喔!
kadmin:  listprincs  <==隨便測試一個指令!確定能成功即可!
K/M@BOOK.VBIRD
kadmin/admin@BOOK.VBIRD
kadmin/changepw@BOOK.VBIRD
kadmin/kdc.book.vbird@BOOK.VBIRD
kiprop/kdc.book.vbird@BOOK.VBIRD
krbtgt/BOOK.VBIRD@BOOK.VBIRD
root/admin@BOOK.VBIRD
kadmin:  exit

到此為止,KDC 就成功建置起來囉!


2.3、建立 KDC 資料庫的主機規則 (principal)

在 1.1 小節談到,KDC 總是得要驗證用戶端的,透過的就是 KDC 資料庫內的主機規則設定 (principal)!這些規則其實可以針對不同的功能與服務來設定的! 基本上有這些常見的設定:

增加管理員帳號:      addprinc newname/admin
增加一般帳號:        addprinc username
增加 KDC 用戶端主機: addprinc -randkey host/client.host.name
增加可用 NFS 服務:   addprinc -randkey nfs/client.host.name

只要是想用 KDC 作為加密驗證的來源時,就是得要使用 host/servername 的方式來增加一筆紀錄的!因此,我們應該要將三部系統都加入到這個環境中才行!

[root@kdc ~]# kadmin.local
Authenticating as principal root/admin@BOOK.VBIRD with password.
kadmin.local:  addprinc -randkey host/kdc.book.vbird
WARNING: no policy specified for host/kdc.book.vbird@BOOK.VBIRD; defaulting to no policy
Principal "host/kdc.book.vbird@BOOK.VBIRD" created.
kadmin.local:  addprinc -randkey host/server.book.vbird
WARNING: no policy specified for host/server.book.vbird@BOOK.VBIRD; defaulting to no policy
Principal "host/server.book.vbird@BOOK.VBIRD" created.
kadmin.local:  addprinc -randkey host/client.book.vbird
WARNING: no policy specified for host/client.book.vbird@BOOK.VBIRD; defaulting to no policy
Principal "host/client.book.vbird@BOOK.VBIRD" created.
kadmin.local:  listprincs
K/M@BOOK.VBIRD
host/client.book.vbird@BOOK.VBIRD
host/kdc.book.vbird@BOOK.VBIRD
host/server.book.vbird@BOOK.VBIRD
kadmin/admin@BOOK.VBIRD
kadmin/changepw@BOOK.VBIRD
kadmin/kdc.book.vbird@BOOK.VBIRD
kiprop/kdc.book.vbird@BOOK.VBIRD
krbtgt/BOOK.VBIRD@BOOK.VBIRD
root/admin@BOOK.VBIRD

其中只有 server.book.vbird 及 client.book.vbird 需要用到 NFS 的服務,因此在這上面只需要加上這兩部系統的資訊即可!

kadmin.local:  addprinc -randkey nfs/server.book.vbird
WARNING: no policy specified for nfs/server.book.vbird@BOOK.VBIRD; defaulting to no policy
Principal "nfs/server.book.vbird@BOOK.VBIRD" created.
kadmin.local:  addprinc -randkey nfs/client.book.vbird
WARNING: no policy specified for nfs/client.book.vbird@BOOK.VBIRD; defaulting to no policy
Principal "nfs/client.book.vbird@BOOK.VBIRD" created.
kadmin.local:  listprincs
K/M@BOOK.VBIRD
host/client.book.vbird@BOOK.VBIRD
host/kdc.book.vbird@BOOK.VBIRD
host/server.book.vbird@BOOK.VBIRD
kadmin/admin@BOOK.VBIRD
kadmin/changepw@BOOK.VBIRD
kadmin/kdc.book.vbird@BOOK.VBIRD
kiprop/kdc.book.vbird@BOOK.VBIRD
krbtgt/BOOK.VBIRD@BOOK.VBIRD
nfs/client.book.vbird@BOOK.VBIRD
nfs/server.book.vbird@BOOK.VBIRD
root/admin@BOOK.VBIRD
kadmin.local:  exit

如果你還需要讓用戶端透過這個 kerberos 來達成身份的驗證,例如,假設這三個系統都有個名為 student 的帳號,這個帳號也想要透過 kerberos 來驗證其使用 NFS 的使用權限,那可這樣做:

[root@kdc ~]# kadmin.local
Authenticating as principal root/admin@BOOK.VBIRD with password.
kadmin.local:  addprinc student
WARNING: no policy specified for student@BOOK.VBIRD; defaulting to no policy
Enter password for principal "student@BOOK.VBIRD":  <==輸入 student 在 kerberos 上的密碼!
Re-enter password for principal "student@BOOK.VBIRD":  <==再一次
Principal "student@BOOK.VBIRD" created.
kadmin.local:  listprincs
K/M@BOOK.VBIRD
host/client.book.vbird@BOOK.VBIRD
host/kdc.book.vbird@BOOK.VBIRD
host/server.book.vbird@BOOK.VBIRD
kadmin/admin@BOOK.VBIRD
kadmin/changepw@BOOK.VBIRD
kadmin/kdc.book.vbird@BOOK.VBIRD
kiprop/kdc.book.vbird@BOOK.VBIRD
krbtgt/BOOK.VBIRD@BOOK.VBIRD
nfs/client.book.vbird@BOOK.VBIRD
nfs/server.book.vbird@BOOK.VBIRD
root/admin@BOOK.VBIRD
student@BOOK.VBIRD
kadmin.local:  exit

這樣就幾乎完成了 kerberos 的資料庫設定囉!


2.4、建立所有的 kerberos 用戶端 (workstation)

kerberos 用戶端想要使用 KDC 進行傳輸的驗證,就得要取得票據資料。而想要取得票據資料,最好就是可以從本身透過 kadmin 來取得票據! 最好不要從 KDC 上面透過 kadmin.local 來取得~這是經驗...另外,從 client 端取得的票據資料其實可以傳輸給任何一台 KDC 用戶端! 所以,我們可以在 server.book.vbird 建置好所有的票據資料後,在直接傳給 client 即可!那麼 client 就無須登入 KDC 資料庫囉! 那就一步一步來完成吧!

# 1. 先安裝所需要的軟體
[root@server ~]# yum install krb5-workstation pam_krb5

# 2. 更改設定,直接從 KDC 處取得即可!
[root@server ~]# scp kdc:/etc/krb5.conf /etc

# 3. 登入 KDC 資料庫,並建立本身的票據資料與 client 的票據資料
[root@server ~]# kadmin
Authenticating as principal root/admin@BOOK.VBIRD with password.
Password for root/admin@BOOK.VBIRD: <==輸入 KDC 管理員 root/admin 的密碼!
kadmin:  listprincs <==嘗試列出資料庫內的主機規則
K/M@BOOK.VBIRD
host/client.book.vbird@BOOK.VBIRD
host/kdc.book.vbird@BOOK.VBIRD
host/server.book.vbird@BOOK.VBIRD
kadmin/admin@BOOK.VBIRD
kadmin/changepw@BOOK.VBIRD
kadmin/kdc.book.vbird@BOOK.VBIRD
kiprop/kdc.book.vbird@BOOK.VBIRD
krbtgt/BOOK.VBIRD@BOOK.VBIRD
nfs/client.book.vbird@BOOK.VBIRD
nfs/server.book.vbird@BOOK.VBIRD
root/admin@BOOK.VBIRD
student@BOOK.VBIRD
kadmin:  ktadd host/server.book.vbird@BOOK.VBIRD
Entry for principal host/server.book.vbird@BOOK.VBIRD .. added to keytab FILE:/etc/krb5.keytab.
Entry for principal host/server.book.vbird@BOOK.VBIRD .. added to keytab FILE:/etc/krb5.keytab.
kadmin:  ktadd nfs/server.book.vbird@BOOK.VBIRD
Entry for principal nfs/server.book.vbird@BOOK.VBIRD  .. added to keytab FILE:/etc/krb5.keytab.
Entry for principal nfs/server.book.vbird@BOOK.VBIRD  .. added to keytab FILE:/etc/krb5.keytab.
kadmin:  ktadd -k /root/client.keytab host/client.book.vbird@BOOK.VBIRD
Entry for principal host/client.book.vbird@BOOK.VBIRD .. added to keytab WRFILE:/root/client.keytab.
Entry for principal host/client.book.vbird@BOOK.VBIRD .. added to keytab WRFILE:/root/client.keytab.
kadmin:  ktadd -k /root/client.keytab nfs/client.book.vbird@BOOK.VBIRD
Entry for principal nfs/client.book.vbird@BOOK.VBIRD .. added to keytab WRFILE:/root/client.keytab.
Entry for principal nfs/client.book.vbird@BOOK.VBIRD .. added to keytab WRFILE:/root/client.keytab.
kadmin:  exit

使用 ktadd 功能時,預設會將票據資料放置於 /etc/krb5.keytab 裡面,這個票據檔案非常重要!最好將它的權限改為 600 較佳! 否則如果被竊取,那就任何人都可能不用透過密碼即可讓 KDC server 進行票據的驗證啊!如果加上 -k 的選項,就可以將票據加入其他的檔案內! 現在,讓我們來瞧瞧票據內的資料與我們的主機名稱是否吻合呢?

[root@server ~]# ll /etc/krb5.keytab /root/client.keytab
-rw-------. 1 root root 336 11月 27 06:23 /etc/krb5.keytab
-rw-------. 1 root root 336 11月 27 06:23 /root/client.keytab

[root@server ~]# klist -k
Keytab name: FILE:/etc/krb5.keytab
KVNO Principal
---- --------------------------------------------------------------------------
   2 host/server.book.vbird@BOOK.VBIRD
   2 host/server.book.vbird@BOOK.VBIRD
   2 nfs/server.book.vbird@BOOK.VBIRD
   2 nfs/server.book.vbird@BOOK.VBIRD

[root@server ~]# klist -t /root/client.keytab -k
Keytab name: FILE:/root/client.keytab
KVNO Timestamp           Principal
---- ------------------- ------------------------------------------------------
   2 2017-11-27T12:13:23 host/client.book.vbird@BOOK.VBIRD
   2 2017-11-27T12:13:23 host/client.book.vbird@BOOK.VBIRD
   2 2017-11-27T12:13:28 nfs/client.book.vbird@BOOK.VBIRD
   2 2017-11-27T12:13:28 nfs/client.book.vbird@BOOK.VBIRD

看起來一切都屬於正常,現在就開始來處理另一台 client.book.vbird 的系統囉!

[root@client ~]# yum -y install krb5-workstation pam_krb5
[root@client ~]# scp kdc:/etc/krb5.conf /etc
[root@client ~]# scp server:/root/client.keytab /etc/krb5.keytab
[root@client ~]# ll -Z /etc/krb5.keytab
-rw-------. root root unconfined_u:object_r:krb5_keytab_t:s0 /etc/krb5.keytab
[root@client ~]# klist -k
Keytab name: FILE:/etc/krb5.keytab
KVNO Principal
---- --------------------------------------------------------------------------
   2 host/client.book.vbird@BOOK.VBIRD
   2 host/client.book.vbird@BOOK.VBIRD
   2 nfs/client.book.vbird@BOOK.VBIRD
   2 nfs/client.book.vbird@BOOK.VBIRD

如果你有啟用 SELinux 的話,注意上面的特性喔!這樣就搞定了 kerberos 的領域資料囉!連同 NFS 的服務也在各個票據資料內建立妥當!


3、加密傳輸的 NFS 服務

其實加密傳輸最麻煩的地方竟然是在 kerberos 身上,而不是在 NFS 本身啦!很有趣的啦!只是得要特別注意的, 不同的 CentOS 7.x 的版本中,使用的服務並不相同喔!我這裡使用的是 CentOS 7.4 (更新到最新的日期為 2017/11/27) , 如果你使用的是不同的版本,那得要特別注意不同的服務名稱~

3.1、Server 的設定

假設一個架構情況是這樣的:

  • 分享的目錄為 /srv/myshare,分享的權限為可讀寫,且支援 kerberos 傳輸機制,但 root 身份保持壓縮。
  • /srv/myshare/tostudent/ 為 student 所有,且 student 可以在該目錄下進行任何權限行為。

一步一步來進行各項工作:

# 1. 建立分享的目錄資料
[root@server ~]# mkdir /srv/myshare
[root@server ~]# mkdir /srv/myshare/tostudent
[root@server ~]# chown student /srv/myshare/tostudent
[root@server ~]# ll -d /srv/myshare/tostudent
drwxr-xr-x. 2 student root 6 11月 27 12:17 /srv/myshare/tostudent

# 2. 處理 NFS 的設定
[root@server ~]# vim /etc/exports
/srv/myshare    10.0.0.0/24(rw,sec=krb5p,async) 127.0.0.0/8(rw,async)

[root@server ~]# systemctl start nfs-server
[root@server ~]# systemctl enable nfs-server
[root@server ~]# systemctl status nfs-server rpc-gssd  <==你沒看錯,是叫做 rpc-gssd 沒錯!
● nfs-server.service - NFS server and services
   Loaded: loaded (/usr/lib/systemd/system/nfs-server.service; enabled; vendor preset: disabled)
  Drop-In: /run/systemd/generator/nfs-server.service.d
           └─order-with-mounts.conf
   Active: active (exited) since 一 2017-11-27 12:17:42 CST; 1min 7s ago
 Main PID: 2551 (code=exited, status=0/SUCCESS)
   CGroup: /system.slice/nfs-server.service

11月 27 12:17:42 server.book.vbird systemd[1]: Starting NFS server and services...
11月 27 12:17:42 server.book.vbird systemd[1]: Started NFS server and services.

● rpc-gssd.service - RPC security service for NFS client and server
   Loaded: loaded (/usr/lib/systemd/system/rpc-gssd.service; static; vendor preset: disabled)
   Active: active (running) since 一 2017-11-27 12:17:42 CST; 1min 7s ago
 Main PID: 2540 (rpc.gssd)
   CGroup: /system.slice/rpc-gssd.service
           └─2540 /usr/sbin/rpc.gssd

11月 27 12:17:42 server.book.vbird systemd[1]: Starting RPC security service for NFS client and server...
11月 27 12:17:42 server.book.vbird systemd[1]: Started RPC security service for NFS client and server.

[root@server ~]# showmount -e localhost
Export list for localhost:
/srv/myshare 127.0.0.0/8,10.0.0.0/24

# 3. 處理防火牆的設定
[root@server ~]# firewall-cmd --add-service=nfs
[root@server ~]# firewall-cmd --add-service=nfs --permanent
[root@server ~]# firewall-cmd --add-rich-rule='rule family="ipv4" source address="10.0.0.0/24" accept'
[root@server ~]# firewall-cmd --add-rich-rule='rule family="ipv4" source address="10.0.0.0/24" accept' --permanent

其實 rpc-gssd 就是啟動 NFS secure 的重要關鍵!所以得要進來仔細查看一下才好喔!確定是有啟動的!至於防火牆的部份, NFS server 會啟動的埠口太多了,還是先針對內網放行一下!


3.2、Client 的設定

其實 client 的設定幾乎沒啥必要的設定,只要有 keytab ,那預設就會啟動 NFS secure 的用戶端功能了! 基本上,會啟用 NFS 加密的,是透過一個名為 nfs-client.target 的操作界面,所以,如果要重新啟動 NFS 加密用戶端, 其實是要重新啟動 nfs-client.target 才對!不過與 nfs server 類似的,要查看狀態列,還是得要查閱 rpc-gssd 喔!

# 1. 還是來重新啟動 nfs-client.target 好了!
[root@client ~]# systemctl restart nfs-client.target
[root@client ~]# systemctl enable nfs-client.target
[root@client ~]# systemctl status rpc-gssd
● rpc-gssd.service - RPC security service for NFS client and server
   Loaded: loaded (/usr/lib/systemd/system/rpc-gssd.service; static; vendor preset: disabled)
   Active: active (running) since 一 2017-11-27 12:22:21 CST; 2min 8s ago
 Main PID: 2509 (rpc.gssd)
   CGroup: /system.slice/rpc-gssd.service
           └─2509 /usr/sbin/rpc.gssd

11月 27 12:22:21 client.book.vbird systemd[1]: Starting RPC security service for NFS client and server...
11月 27 12:22:21 client.book.vbird systemd[1]: Started RPC security service for NFS client and server.

# 2. 還是先確認 server 有提供資源否?
[root@client ~]# showmount -e server
Export list for server:
/srv/myshare 127.0.0.0/8,10.0.0.0/24

# 3. 準備來掛載 NFS 
[root@client ~]# mkdir /srv/myshare
[root@client ~]# vim /etc/fstab
server:/srv/myshare  /srv/myshare  nfs   defaults,sec=krb5p,vers=4.2,_netdev 0 0

[root@client ~]# mount -a
[root@client ~]# df /srv/myshare
檔案系統             1K-區段    已用    可用 已用% 掛載點
server:/srv/myshare 10475520 3891712 6583808   38% /srv/myshare

[root@client ~]# cd /srv/myshare/tostudent
[root@client tostudent]# touch 1234
touch: cannot touch ‘1234’: 拒絕不符權限的操作

最後確認一下,確實是不能操作的!因為 root 身份有被壓縮的緣故。不過上述的動作在掛在 (mount -a) 時,有點怪異! 鳥哥剛剛做好所有的設定,然後進行 mount -a 時,竟然會出現 access deny 喔!不過,過了一分鐘左右,再次 mount -a , 並沒有進行任何額外的動作,竟然就能夠順利通行了!實在有點怪異!

此外,你不見得能夠掛載 4.2 版本的 NFS 喔!一般來說,不加上 vers=4.2 也是能夠順利的以預設的 vers=4.1 來掛載的! 如果確定要使用 ver4.2 來掛載的話,那麼請到 server.book.vbird 上面,透過底下的方案來強制啟用 vers 4.2 版本!

[root@server ~]# cat /proc/fs/nfsd/versions
-2 +3 +4 +4.1 +4.2
# 上面的意思是,目前支援 3, 4, 4.1, 4.2 等版本,但是不支援 version 2 的意思。
# 上面是已經啟動的模樣,若沒有啟動,就會顯示 -4.2 囉!

# 若要強制啟動 v4.2 的話,可以這樣做:
[root@server ~]# vim /etc/sysconfig/nfs
RPCNFSDARGS="-V 4.2"

[root@server ~]# systemctl restart nfs-server

因為我們有放行 student 的身份來進行讀寫的動作喔!所以,現在請切換身份成為 student ,然後測試一下能不能具有權限呢?

[student@client ~]$ ll /srv
ls: cannot access /srv/myshare: Permission denied
total 0
d????????? ? ? ? ?            ? myshare

見鬼了!竟然沒有權限!連 /srv/myshare 都看不到任何權限資訊了!這是因為該目錄的 NFS 是透過 kerberos 加密傳輸的, 所以你的身份沒有透過 kerberos 認證的話。現在讓我們使用 kinit 來取得認證吧!不過,要注意的是,當使用 kinit 來驗證身份時, 你輸入的密碼並不是 linux 帳號的密碼,而是透過 kerberos 資料庫內所建立的 student 密碼喔!

[student@client ~]$ 
Password for student@BOOK.VBIRD:  <==再說一次,是 kerberos 資料庫內的密碼喔!

[student@client ~]$ klist
Ticket cache: KEYRING:persistent:1000:1000
Default principal: student@BOOK.VBIRD

Valid starting       Expires              Service principal
11/27/2017 13:47:20  11/28/2017 13:47:20  krbtgt/BOOK.VBIRD@BOOK.VBIRD <==暫時取得的一個票據資料

[student@client ~]$ ll /srv/
drwxr-xr-x. 3 root root 23 Nov 27 12:17 myshare

[student@client ~]$ cd /srv/myshare/tostudent/
[student@client tostudent]$ touch 1324
[student@client tostudent]$ ll
-rw-rw-r--. 1 student student 0 Nov 27 13:49 1324

[student@client tostudent]$ klist
Ticket cache: KEYRING:persistent:1000:1000
Default principal: student@BOOK.VBIRD

Valid starting       Expires              Service principal
11/27/2017 13:48:48  11/28/2017 13:47:20  nfs/server.book.vbird@BOOK.VBIRD  <==server也能提供使用
11/27/2017 13:47:20  11/28/2017 13:47:20  krbtgt/BOOK.VBIRD@BOOK.VBIRD      <==只是身份驗證

使用 kinit 來驗證之後,若驗證成功,你就能夠嘗試使用 klist 來查看你暫時取得的 kerberos 票據資料~該票據資料顯示你有 1 天的使用期限, 若經過該期限,你就得要重新驗證身份了!另外,為啥最後有兩筆紀錄呢?這是因為身份驗證是 client 與 kdc 的事,但是如果你要使用 NFS server 的檔案系統, 此時就變成 client 與 server 的事,所以,server 也會向 kdc 詢問該筆紀錄是否正常,若確定來源與密碼皆正確,此時又會新增一筆規則囉。 所以就有兩筆資訊。若此時你跑到 kdc.book.vbird 去查看 /var/log/krb5kdc.log 的話,應該就會看到類似底下的登錄資訊:

[root@kdc ~]# tail /var/log/krb5kdc.log
Nov 27 13:47:20 kdc.book.vbird krb5kdc[2694](info): AS_REQ (8 etypes {18 17 20 19 16 23 25 26}) 
  10.0.0.103: ISSUE: authtime 1511761640, etypes {rep=18 tkt=18 ses=18}, student@BOOK.VBIRD 
  for krbtgt/BOOK.VBIRD@BOOK.VBIRD
Nov 27 13:48:48 kdc.book.vbird krb5kdc[2694](info): TGS_REQ (8 etypes {18 17 20 19 16 23 25 26}) 
  10.0.0.103: ISSUE: authtime 1511761640, etypes {rep=18 tkt=18 ses=18}, student@BOOK.VBIRD 
  for nfs/server.book.vbird@BOOK.VBIRD

未來若需要查閱你的相關 kerberos 票據,那麼就使用 klist 即可囉!若票據資料都被取消 (因為過期的關係), 那就重複使用 kinit 來重新驗證即可!


4、結語與參考資料

一開始因為對於 kerberos 這個機制並不熟悉,所以搞錯了好多的方向!舉例來說,我們單純是為了要搞定 NFS 的加密傳輸, 並不是要增加一個對 kerberos 做身份驗證的 Linux 帳號登入方式,因此,實際上是不用進行 autoconfig-tui 這個指令的建置的。 所以,不要道聽塗說啊~

另外,從上面 3.2 最後一個練習,你也會知道整個 kerberos 的通行與否都與票據有關,而這個票據資料最重要的地方除了主機名稱之外, 就是時間的定義了。因此,加入 kerberos 的所有網路主機,其時間應該要絕對相同,否則可能讓票據資料出現錯誤,導致無法順利的向 KDC 取得驗證。 一開始寫這篇的時候,為了簡化整體流程,所以打算略過 chronyd 不講,結果...怎麼設定都是失敗!最終只好還是處理好 chronyd 才順利啟動了 rpc-gssd 哩~

因為不同的 CentOS 版本會有很大的設定差異存在~第一次架設的時候,依舊想要偷懶,所以使用 7.3 的版本,不過安裝的 krb5-server 與 krb5-workstation 卻用預設的 7.4 的版本,可能是因為這樣的緣故,導致很多問題都互相干擾~甚至於 rpc-gssd 根本就無法啟動!搞了一整個晚上,都快要崩潰! 結果隔天早上,將系統重灌,然後直接更新到最新,再以這篇資料的內容從頭到尾做一次 (不到 10 分鐘),立刻就搞定了 kerberos 的架設.. 所以, CentOS 的版本對應也很重要!這一篇是針對 7.4 來講的~要注意!要注意!

重要的相關參考資料:

2017/11/27:因為認證考試以及自己的環境建置需要這個服務的幫忙,怕未來自己忘記了~所以就直接寫一篇
2017/11/27以來統計人數
計數器
   http://linux.vbird.org is designed by VBird during 2001-2017.