Try   HackMD

使用 FreeRADIUS 搭配 Google 認證服務進行雙重驗證

tags: MFA freeradius gauth

協助同事處理 MFA 驗證問題,之前也沒玩過,順便紀錄一下過程。這種架構應該是蠻適合用 Docker 建立的,有機會再說囉!

執行環境

執行步驟

  • 執行步驟應可以使用腳本檔執行達成目標,這樣一來只要做一次一勞永逸
  • 使用容器完成應該會更好。

修改主機名稱

使用 hostnamectl 可不用重啟系統調整主機名稱,但記得要重新登入

  • hostnamectl set-hostname authServer

    Image Not Showing Possible Reasons
    • The image file may be corrupted
    • The server hosting the image is unavailable
    • The image path is incorrect
    • The image format is not supported
    Learn More →

  • hostnamectl

    Image Not Showing Possible Reasons
    • The image file may be corrupted
    • The server hosting the image is unavailable
    • The image path is incorrect
    • The image format is not supported
    Learn More →

確認 NTP 狀態

Ubuntu 預設使用 systemd-timesycd 作為 NTP 校時服務。

使用 timedatectl 確認系統時間相關資訊。

  • timedatectl [status]

    Image Not Showing Possible Reasons
    • The image file may be corrupted
    • The server hosting the image is unavailable
    • The image path is incorrect
    • The image format is not supported
    Learn More →

以上資訊可以得知:

  • System clock synchronized: yes 該系統啟用系統網路校時服務。
  • 開啟 NTP 功能: timedatectl set-ntp true
  • 關閉 NTP 功能: timedatectl set-ntp false
  • systemd-timesyncd.service active: yes 該系統目前使用 systemd-timesyncd 服務進行網路校時作業。
  • 組態檔 /etc/systemd/timesyncd.conf
  • 可在組態檔中指定校時 NTP 伺服器,若有多組以空白區隔。
    ​​[Time]
    ​​NTP=time1.google.com time2.google.com time3.google.com time4.google.com
    ​​FallbackNTP=ntp.ubuntu.com
    
  • 使用 systemctl restart systemd-timesyncd 重啟服務。

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

修改時區

同樣使用 timedatectl 列出可用時區及調整時區。

  • timedatectl list-timezones

    Image Not Showing Possible Reasons
    • The image file may be corrupted
    • The server hosting the image is unavailable
    • The image path is incorrect
    • The image format is not supported
    Learn More →

指定 Asia/Taipei 作為系統時區。

  • timedatectl set-timezone Asia/Taipei

再次使用 timedatectl 確認系統時間相關設定。

  • timedatectl [status]

    Image Not Showing Possible Reasons
    • The image file may be corrupted
    • The server hosting the image is unavailable
    • The image path is incorrect
    • The image format is not supported
    Learn More →

注意
RTC 時間 請使用 UTC 時間,而不要儲存本地時間(Local Time)

確認 DNS 解析

一般 Linux 作業系統關於 DNS 解析都可以檢視 /etc/resolv.conf 並修改其中 nameserver 參數。

不過,目前似乎各發行版本都改由 systemd-resolved 服務處理。該組態檔可以檢視

  • /run/systemd/resolve/resolv.conf: 基本上可以直接修改此組態檔,再重啟服務

  • /run/systemd/resolve/stub-resolv.conf

    Image Not Showing Possible Reasons
    • The image file may be corrupted
    • The server hosting the image is unavailable
    • The image path is incorrect
    • The image format is not supported
    Learn More →

    Image Not Showing Possible Reasons
    • The image file may be corrupted
    • The server hosting the image is unavailable
    • The image path is incorrect
    • The image format is not supported
    Learn More →

當然也可以使用不同 Linux 發行平台所提供的工具。

  • Ubuntu: netplan
    • 組態檔: /etc/netplan/<network_config>.yaml。編輯網路組態後,使用 netplan apply 套用設定。

      Image Not Showing Possible Reasons
      • The image file may be corrupted
      • The server hosting the image is unavailable
      • The image path is incorrect
      • The image format is not supported
      Learn More →

    • 使用 systemd-resolve --status | grep -A2 'DNS Servers' 查詢設定。

      Image Not Showing Possible Reasons
      • The image file may be corrupted
      • The server hosting the image is unavailable
      • The image path is incorrect
      • The image format is not supported
      Learn More →

  • Fedora: nmcli
    • 使用 nmcli connection modify <device> ipv4.dns "8.8.8.8 8.8.4.4"

      Image Not Showing Possible Reasons
      • The image file may be corrupted
      • The server hosting the image is unavailable
      • The image path is incorrect
      • The image format is not supported
      Learn More →

    • 使用 resolvectl status | grep 'DNS Servers' 查詢設定。

      Image Not Showing Possible Reasons
      • The image file may be corrupted
      • The server hosting the image is unavailable
      • The image path is incorrect
      • The image format is not supported
      Learn More →

使用 dig 確認名稱解析。

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

更新系統套件

Image Not Showing Possible Reasons
  • The image file may be corrupted
  • The server hosting the image is unavailable
  • The image path is incorrect
  • The image format is not supported
Learn More →

安裝 FreeRADIUS 和 PAM 相關套件

$ sudo apt-get install build-essential libpam0g-dev freeradius git libqrencode3

安裝 Google Authenticator 套件

$ sudo apt-get install -y libpam-google-authenticator

參考

以上系統更新及套件安裝動作,可以使用腳本檔一鍵執行完成,可以免去重複打字或輸入錯誤的問題或使用 Ansible 自動佈署達成。

  • update_install.sh
#!/bin/bash
#

passport="${HOME}/.passport"

if [ -f ${passport} ]; then
    pass=$(cat ${passport})
else
    echo -e "<!> ${passport} NOT FOUND!<!>\n"
    exit
fi

##
echo -e "\n[TASK] Update the System\n"
echo ${pass} | sudo -S apt update && sudo -S apt -y upgrade

echo -e "\n[TASK] Install FreeRadius & PAM packages\n"
echo -e " - build-essential
 - libpam0g-dev
 - freeradius
 - freeradius-utils
 - git
 - libqrencode3"
echo

echo ${pass} | sudo -S apt install -y build-essential libpam0g-dev freeradius freeradius-utils git libqrencode3

echo -e "\n[TASK] Install Google Authenticator packages\n"
echo -e " - libpam-google-authenticator"
echo

echo ${pass} | sudo -S apt install -y libpam-google-authenticator
  • 執行結果

組態 FreeRADIUS 使用 Google Authenticator 進行 MFA

注意

  • freeRADIUS 有可能會因為版本不同造成服務組態檔位置不同,請根據實際安裝版本檢視並修正對應組態檔。
  • 使用 freeradius -v 可檢視安裝版本。
  • 下列以 版本 3.0.16 進行操作。
  • 主要 freeRADIUS 組態檔所在目錄為 /etc/freeradius/3.0/

建立暫時禁用權限群組

為了不刪除既有使用者,建立一個暫時禁用權限的群組 radius-disabled

sudo addgroup radius-disabled

編輯 /etc/freeradius/3.0/radiusd.conf

警告 在編輯任一個服務組態檔時,務必先備份原始檔案後變動。

將會變動以下列出組態檔內容:

  • /etc/freeradius/3.0/radiusd.conf
  • /etc/freeradius/3.0/users
  • /etc/freeradius/3.0/sites-enabled/default
  • /etc/freeradius/3.0/clients.conf
  • /etc/pam.d/radiusd

編輯組態檔 /etc/freeradius/3.0/radiusd.conf,進行以下變更。

註解以下內容

#user = freerad
#group = freeead

增加以下內容

user = root
group = root

編輯 /etc/freeradius/3.0/users

請在 # Deny access for a group of users. 這個區塊加入以下內容。

務必按照以下內容的格式對齊,否則將會出現無法正確啟用 FreeRADIUS 應用服務

DEFAULT Group == "radius-disabled", Auth-Type := Reject
        Reply-Message = "Your account has been disabled."
DEFAULT Auth-Type := PAM

編輯 /etc/freeradius/3.0/sites-enabled/default

請在 Pluggable Authentication Modules. 這個區塊加入註解掉 pam 內容。

編輯 /etc/pam.d/radiusd

配置 PAM 以便透過組合本機用戶密碼和 Google Authenticator 產生 PIN 作為驗證方式。

以下註解

#@include common-auth
#@include common-account
#@include common-password
#@include common-session

增加以下設定

auth requisite pam_google_authenticator.so forward_pass
auth required pam_unix.so use_first_pass

重新開機

完成以上設定,請將系統重開,並確認服務運作正常。

$ reboot

$ sudo systemctl status freeradius

設定 FreeRADIUS 用戶端

用戶端就是設定可以向 FreeRADIUS 要求進行用戶身份驗證的主機。若以防火牆整合驗證需求來看,防火牆 就可視為一個用戶端,而設定的 IP 位址就是要與 FreeRADIUS 溝通並進行驗證行為的。

編輯 /etc/freeradius/3.0/clients.conf

以下是用戶端設定範例。

client Gateway {
	  ipaddr		= 10.2.2.1
	  secret		= SECRET
}

client 10.2.2.1 {
	  secret		= SECRET
	  shortname		= Gateway
}

我們也可以參考設定檔中 localhostlocalhost_ipv6 的設定。

  • secret 是 FreeRADIUS 與用戶端進行驗證的密碼
  • 若只是簡易測試,使用 Localhost 即可。

設定 FreeRADIUS 使用者資料庫

根據以下流程建立使用者並進行 Goolge Authenticator 生成。

建立使用者

可以使用以下簡單的腳本檔建立測試使用者帳號及密碼。

#!/bin/bash

passport="${HOME}/.passport"
pass=$(cat ${passport})

username="${1:-user01}"
password='VMware1!'
userid='1500'

if id -u ${username} &>/dev/null; then
    echo -e "<!> User [${username}] is existed\n"
    exit
fi

echo -e "\n[TASK] Create a user for Google Authenticator"
echo ${pass} | sudo -S useradd -s /bin/bash -d "/home/${username}" -u ${userid} -m ${username}
echo "${username}:${password}" | sudo chpasswd

echo -e "\n[RESULT] User Infomation:"
id ${username}

使用 sudo userdel -r {user_name} 命令可以刪除使用者相關資訊。

使用新建立使用者登入

使用新建立的使用者帳號及密碼登入系統進行測試。

創建 Google Authenticator 驗證碼

在該使用者家目錄下直接執行 google-authenticator 程式。

在終端機中產生的 QR-Code 尺寸過大,所以加入 -Q UTF8 可縮小一些,要不然就要手動調整終端機配置了!

由於我們使用的是 Time-based One-Time Password(TOTP),所以第一個選項請回答 y

Do you want authentication tokens to be time-based (y/n) y

接著系統便會產生相關資訊:

  • QR Code 網頁顯示 URL: 可以將此 URL 寄給使用者,以完成 Google 兩步驟驗證功能設定。
  • QR Code
  • 密鑰(Secret Key)
  • 驗證碼(verification code)
  • 備用碼(emergency scratch code)

稍微研究一下顯示 QR Code URL。程式產生的 URL 如下:

https://www.google.com/chart?chs=200x200&chld=M|0&cht=qr&chl=otpauth://totp/user02@authServer%3Fsecret%3DRAP7KZ4CPRCRDTU6WRIKSEB2W4%26issuer%3DauthServer

其中帶了一些 urlencode 碼 [參考],可以透過 urlencode -d 轉換成可識別字符。

所以 QR Code 顯示 URL 的結構可以解析成 (1) + (2)。其中 (1) 部份為固定, (2) 部份其中 {variable} 則為變數。

(1) https://www.google.com/chart?chs=200x200&chld=M|0&cht=qr&
(2) chl=otpauth://totp/{USERNAME}@{HOSTNAME}?secret={SECRET_KEY}&issuer={HOSTNAME}

所以此 QR Code 顯示的 URL,可以取得相關 {變數}自行產生建立

有關 Key URI 詳細資訊可以參考 [連結]

參考以下步驟繼續完成 Goolge Authenticator Token 建立程序。

完成上述設定程序,會將相關資訊儲存在該使用者家目錄中的 .google-authenticator 檔案。

Google-Authenticator 探索

其實可以研究一下 google-authenticator 程式執行的參數,讓這樣的設定程序可以自動化一點。

根據上述的問答流程,大致可以知道需要的配置如下:

  • 使用 TOTP 驗證
  • 自行產出密鑰
  • 生成備用碼 5 組並更新原有設定檔(.google_authenticator)
  • 單一驗證碼不允許重複使用
  • 驗證碼 30 秒刷新(預設)
  • 時間同步窗口 (3, 預設)
  • 限制每 30 秒內不超過 3 次驗證流量
  • 不顯示 QR Code
$ google-authenticator --quiet --force \
  --time-based \
  --disallow-reuse \
  --window-size=3 \
  --rate-limit=3 --rate-time=30 \
  --step-size=30 \     ## 可省略,會自帶
  --emergency-codes=5  ## 可省略,會自帶

可簡寫為以下命令:

$ google-authenticator -qftd -w 3 -r 3 -R 30 -S 30 -e 5

透過上述命令可以查看執行結果,省去產生 QR Code 及問答流程,可直接產生組態檔。

至於 QR Code URL 透過以下簡單的腳本程式就可以取得!

  • getCodeUrl.sh
#!/bin/bash
#
username="${1}"
user_home=$(grep "${username}" /etc/passwd | cut -d: -f6)
mfa_config="${user_home}/.google_authenticator"

echo -e "\n[TASK] Check the configuration of Google Authenticator"
if [ ! -f "${mfa_config}" ]; then
    echo -e " > Not found!! Please run \"google-authenticator\" first"
    exit
fi

secretkey=$(head -n1 ${mfa_config})
hostname=$(hostname)

baseUrl='https://www.google.com/chart?chs=200x200&chld=M|0&cht=qr&'
keyUri="chl=otpauth://totp/${username}@${hostname}?secret=${secretkey}&issuer=${hostname}"

qrCodeUrl="${baseUrl}${keyUri}"

echo -e "\n[TASK] QR Code URL for \"${username}@${hostname}\""
echo -e "\n${qrCodeUrl}\n"

將上述產生的 QR Code URL 貼於瀏覽器確認狀態。

若要取得該使用者的驗證備用碼也很容易!

$ cat .google_authenticator | sed -n '/^[0-9].*[0-9]$/p'

透過簡單的 mailx | mutt 程式,可以模擬將驗證碼資訊寄發給使用者的應用情境。信件內文的訊息就是透過以上動作整合完成的。

這樣一來,串連以上相關的步驟,應該就可以自動化產生驗證碼並寄發使用者相關資訊了!

若要透過 Linux 主機的郵件服務寄送至外部郵件伺服器,則須注意是否有被 Anti-SPAM 功能阻擋囉。

公司採用的是 Office365,可以透過 反垃圾郵件 IP 取消清單網站 [連結] 將 IP 位址列入驗證要求清單。完成設定,可能需要等待一段時間再進行測試吧。

重新寄送驗證碼資訊到公司郵箱,模擬使用者收到驗證碼設定的郵件,看起來沒有問題!

重啟 FreeRADIUS 服務

注意: 請務必確認以下連結是否存在,否則二次驗證在 FreeRADIUS 中無法成功啟用。

完成所有配置程序,將 FreeRADIUS 服務重啟。

$ sudo systemctl restart freeradius

若有需要進行手機 App 測試,請取得 QR Code URL 後,以手機 App 操作掃描完成相關設定即可。

功能驗證

為了簡化驗證測試,就先使用 localhost 本機進行驗證程序。使用 radtest 命令,採用使用者 user02,驗證密碼為 {使用者密碼}{Google Authenticator 驗證碼}。使用以下命令進行測試。

$ sudo radtest {username} {password} localhost 18120 testing123

執行結果

驗證碼也採用備用碼以簡化測試過程。

另外檢視使用者的組態檔 .google_authenticator,也可發現使用的備用碼也從該組態檔中刪去。

可查看 /var/log/auth.log 檔檢視驗證紀錄。

  • 以上大致就是使用 FreeRADIUS 搭配 Google Authenticator 作 MFA 的紀錄。
  • 至於後續與其他服務或網路設備整合,大致上只要將驗證主機指向 FreeRADIUS 服務應該就可以達成。

待解問題

  • 雖然可以按照步驟完成 freeRADIUS 與 Google 認證產生 QRCode。但是整個執行流程似乎沒有前端可以提供給終端用戶。但可以透過腳本程式達成一點點自動化的目標
  • 若客戶已有 AD 的使用者資料庫,似乎 freeRADIUS 還要另外與 AD 整合使用者資料庫,否則將使造成管理者管理帳戶的負擔。
  • 不清楚 AD 是否可以直接與 Google 認證結合?還是可以改用 Microsoft Azure

參考