# 使用 FreeRADIUS 搭配 Google 認證服務進行雙重驗證 ###### tags: `MFA` `freeradius` `gauth` 協助同事處理 MFA 驗證問題,之前也沒玩過,順便紀錄一下過程。這種架構應該是蠻適合用 **Docker** 建立的,有機會再說囉! [toc] # 執行環境 - Ubuntu 18.04.6 LTS - FreeRADIUS 3.0 - [google-authenticator](https://github.com/google/google-authenticator) # 執行步驟 :::warning - 執行步驟應可以使用腳本檔執行達成目標,這樣一來只要**做一次一勞永逸**。 - 使用容器完成應該會更好。 ::: ## 修改主機名稱 使用 **`hostnamectl`** 可不用重啟系統調整主機名稱,但記得要**重新登入**。 - **`hostnamectl set-hostname authServer`** ![](https://i.imgur.com/aMcIlzK.png) - **`hostnamectl`** ![](https://i.imgur.com/GSusiZ4.png) ## 確認 NTP 狀態 Ubuntu 預設使用 **systemd-timesycd** 作為 NTP 校時服務。 使用 **`timedatectl`** 確認系統時間相關資訊。 - **`timedatectl [status]`** ![](https://i.imgur.com/L6E8Akb.png) 以上資訊可以得知: - **`System clock synchronized: yes`** 該系統啟用系統網路校時服務。 :::info - **開啟 NTP 功能**: `timedatectl set-ntp true` - **關閉 NTP 功能**: `timedatectl set-ntp false` ::: - **`systemd-timesyncd.service active: yes`** 該系統目前使用 **`systemd-timesyncd`** 服務進行網路校時作業。 :::info - 組態檔 **`/etc/systemd/timesyncd.conf`**。 - 可在組態檔中指定校時 NTP 伺服器,若有多組以**空白**區隔。 ```conf [Time] NTP=time1.google.com time2.google.com time3.google.com time4.google.com FallbackNTP=ntp.ubuntu.com ``` - 使用 **`systemctl restart systemd-timesyncd`** 重啟服務。 ::: ![](https://i.imgur.com/KxfGxdG.png) ## 修改時區 同樣使用 **`timedatectl`** 列出可用時區及調整時區。 - **`timedatectl list-timezones`** ![](https://i.imgur.com/cPsw4D6.png) 指定 **`Asia/Taipei`** 作為系統時區。 - **`timedatectl set-timezone Asia/Taipei`** 再次使用 **`timedatectl`** 確認系統時間相關設定。 - **`timedatectl [status]`** ![](https://i.imgur.com/M7V2uZN.png) :::danger **注意** **RTC 時間** 請使用 **UTC 時間**,而不要儲存**本地時間(Local Time)**。 ::: ## 確認 DNS 解析 一般 Linux 作業系統關於 DNS 解析都可以檢視 **`/etc/resolv.conf`** 並修改其中 **`nameserver`** 參數。 不過,目前似乎各發行版本都改由 **`systemd-resolved`** 服務處理。該組態檔可以檢視 - **`/run/systemd/resolve/resolv.conf`**: 基本上可以**直接修改此組態檔,再重啟服務**。 - **`/run/systemd/resolve/stub-resolv.conf`** ![](https://i.imgur.com/ambshJ5.png) ![](https://i.imgur.com/pm1u5qb.png) 當然也可以使用不同 Linux 發行平台所提供的工具。 - Ubuntu: **netplan** - 組態檔: **`/etc/netplan/<network_config>.yaml`**。編輯網路組態後,使用 **`netplan apply`** 套用設定。 ![](https://i.imgur.com/9OBot0M.png) - 使用 **`systemd-resolve --status | grep -A2 'DNS Servers'`** 查詢設定。 ![](https://i.imgur.com/oL9xP8j.png) :::info [**Netplan configuration examples**](https://netplan.io/examples) ::: - Fedora: **nmcli** - 使用 **`nmcli connection modify <device> ipv4.dns "8.8.8.8 8.8.4.4"`** ![](https://i.imgur.com/QhGfTB9.png) - 使用 **`resolvectl status | grep 'DNS Servers'`** 查詢設定。 ![](https://i.imgur.com/SU6qV0H.png) :::info [**Configuring IP networking with nmcli**](https://docs.fedoraproject.org/en-US/quick-docs/configuring-ip-networking-with-nmcli/) ::: 使用 **`dig`** 確認名稱解析。 ![](https://i.imgur.com/CPpiVKg.png) ## 更新系統套件 ![](https://i.imgur.com/SpAFDFO.png) ## 安裝 FreeRADIUS 和 PAM 相關套件 ```bash $ sudo apt-get install build-essential libpam0g-dev freeradius git libqrencode3 ``` ## 安裝 Google Authenticator 套件 ```bash $ sudo apt-get install -y libpam-google-authenticator ``` :::info **參考** 以上系統更新及套件安裝動作,可以使用腳本檔一鍵執行完成,可以免去重複打字或輸入錯誤的問題或使用 Ansible 自動佈署達成。 - **update_install.sh** ```bash! #!/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 ``` - 執行結果 ![](https://i.imgur.com/HGJKyA1.png) ::: ## 組態 FreeRADIUS 使用 Google Authenticator 進行 MFA :::warning **注意** - freeRADIUS 有可能會因為**版本不同**造成**服務組態檔位置不同**,請根據實際安裝版本檢視並修正對應組態檔。 - 使用 **`freeradius -v`** 可檢視安裝版本。 ![](https://i.imgur.com/ljgIeq3.png) - 下列以 **版本 3.0.16** 進行操作。 - 主要 freeRADIUS 組態檔所在目錄為 **`/etc/freeradius/3.0/`**。 ::: ### 建立暫時禁用權限群組 為了不刪除既有使用者,建立一個暫時禁用權限的群組 **`radius-disabled`**。 ```bash sudo addgroup radius-disabled ``` ### 編輯 `/etc/freeradius/3.0/radiusd.conf` :::danger **警告** 在編輯任一個服務組態檔時,務必先備份原始檔案後變動。 ::: :::info 將會變動以下列出組態檔內容: - /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`**,進行以下變更。 :::success **註解以下內容** ``` #user = freerad #group = freeead ``` **增加以下內容** ``` user = root group = root ``` ::: ![](https://i.imgur.com/q24Vo1P.png) ![](https://i.imgur.com/ZFbYfPE.png) ### 編輯 `/etc/freeradius/3.0/users` 請在 **# Deny access for a group of users.** 這個區塊加入以下內容。 :::danger 請**務必**按照以下內容的**格式對齊**,否則將會出現**無法正確啟用 FreeRADIUS 應用服務**。 ::: :::success ``` DEFAULT Group == "radius-disabled", Auth-Type := Reject Reply-Message = "Your account has been disabled." DEFAULT Auth-Type := PAM ``` ::: ![](https://i.imgur.com/nSUr5Tu.png) ### 編輯 `/etc/freeradius/3.0/sites-enabled/default` 請在 **Pluggable Authentication Modules.** 這個區塊加入註解掉 **`pam`** 內容。 ![](https://i.imgur.com/LKrK37m.png) ### 編輯 `/etc/pam.d/radiusd` 配置 PAM 以便透過**組合本機用戶密碼和 Google Authenticator 產生 PIN** 作為驗證方式。 :::success **以下註解** ``` #@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 ``` ::: ![](https://i.imgur.com/ucZremV.png) ### 重新開機 完成以上設定,請將**系統重開**,並確認服務運作正常。 ```bash $ reboot $ sudo systemctl status freeradius ``` ![](https://i.imgur.com/sztH80I.png) ## 設定 FreeRADIUS 用戶端 用戶端就是設定可以向 FreeRADIUS 要求進行用戶身份驗證的主機。若以防火牆整合驗證需求來看,防火牆 就可視為一個用戶端,而設定的 IP 位址就是要與 FreeRADIUS 溝通並進行驗證行為的。 ### 編輯 `/etc/freeradius/3.0/clients.conf` 以下是用戶端設定範例。 :::success ``` client Gateway { ipaddr = 10.2.2.1 secret = SECRET } client 10.2.2.1 { secret = SECRET shortname = Gateway } ``` ::: 我們也可以參考設定檔中 **`localhost`** 和 **`localhost_ipv6`** 的設定。 ![](https://i.imgur.com/0jc39l7.png) :::info - **secret** 是 FreeRADIUS 與用戶端進行驗證的**密碼**。 - 若只是簡易測試,使用 **Localhost** 即可。 ::: ## 設定 FreeRADIUS 使用者資料庫 根據以下流程建立使用者並進行 Goolge Authenticator 生成。 ### 建立使用者 可以使用以下簡單的腳本檔建立測試使用者帳號及密碼。 ```bash! #!/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} ``` ![](https://i.imgur.com/zDsvbDP.png) :::warning 使用 **`sudo userdel -r {user_name}`** 命令可以刪除使用者相關資訊。 ::: ### 使用新建立使用者登入 使用新建立的使用者帳號及密碼登入系統進行測試。 ![](https://i.imgur.com/AT3nYgF.png) ### 創建 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)** ![](https://i.imgur.com/8RiNgi2.png) :::info 稍微研究一下顯示 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 碼 [[**參考**]](https://www.w3schools.com/tags/ref_urlencode.ASP),可以透過 **`urlencode -d`** 轉換成可識別字符。 ![](https://i.imgur.com/uIqnzxz.png) 所以 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** 詳細資訊可以參考 [[**連結**]](https://github.com/google/google-authenticator/wiki/Key-Uri-Format)。 ::: 參考以下步驟繼續完成 Goolge Authenticator Token 建立程序。 ![](https://i.imgur.com/X7XFRzr.png) 完成上述設定程序,會將相關資訊儲存在該使用者家目錄中的 **`.google-authenticator`** 檔案。 ![](https://i.imgur.com/0v10IUz.png) ### Google-Authenticator 探索 其實可以研究一下 **`google-authenticator`** 程式執行的參數,讓這樣的設定程序可以自動化一點。 根據上述的問答流程,大致可以知道需要的配置如下: - 使用 TOTP 驗證 - 自行產出密鑰 - 生成備用碼 5 組並更新原有設定檔(.google_authenticator) - 單一驗證碼不允許重複使用 - 驗證碼 30 秒刷新(預設) - 時間同步窗口 (3, 預設) - 限制每 30 秒內不超過 3 次驗證流量 - 不顯示 QR Code ```bash $ google-authenticator --quiet --force \ --time-based \ --disallow-reuse \ --window-size=3 \ --rate-limit=3 --rate-time=30 \ --step-size=30 \ ## 可省略,會自帶 --emergency-codes=5 ## 可省略,會自帶 ``` 可簡寫為以下命令: ```bash $ google-authenticator -qftd -w 3 -r 3 -R 30 -S 30 -e 5 ``` 透過上述命令可以查看**執行結果**,省去產生 QR Code 及問答流程,可直接產生組態檔。 ![](https://i.imgur.com/efYIX3D.png) 至於 QR Code URL 透過以下簡單的腳本程式就可以取得! - **`getCodeUrl.sh`** ```bash! #!/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" ``` ![](https://i.imgur.com/red1T0g.png) 將上述產生的 QR Code URL 貼於瀏覽器確認狀態。 ![](https://i.imgur.com/neQdP2E.png) 若要取得該使用者的驗證備用碼也很容易! ```bash! $ cat .google_authenticator | sed -n '/^[0-9].*[0-9]$/p' ``` ![](https://i.imgur.com/rcEUenr.png) 透過簡單的 **mailx | mutt** 程式,可以模擬將驗證碼資訊寄發給使用者的應用情境。信件內文的訊息就是透過以上動作整合完成的。 ![](https://i.imgur.com/txaf43z.png) 這樣一來,串連以上相關的步驟,應該就可以**自動化產生驗證碼並寄發使用者相關資訊**了! :::info 若要透過 Linux 主機的郵件服務寄送至外部郵件伺服器,則須注意是否有被 Anti-SPAM 功能阻擋囉。 公司採用的是 Office365,可以透過 **反垃圾郵件 IP 取消清單網站** [[連結]](https://sender.office.com/) 將 IP 位址列入驗證要求清單。完成設定,可能需要等待**一段時間**再進行測試吧。 ![](https://i.imgur.com/Um2EEHo.png) 重新寄送驗證碼資訊到公司郵箱,模擬使用者收到驗證碼設定的郵件,看起來沒有問題! ![](https://i.imgur.com/Bps3RyG.png) ::: ### 重啟 FreeRADIUS 服務 <font color=red>**注意: 請務必確認以下連結是否存在,否則二次驗證在 FreeRADIUS 中無法成功啟用。**</font> ![](https://i.imgur.com/N28LGqt.png) 完成所有配置程序,將 FreeRADIUS 服務重啟。 ```bash $ sudo systemctl restart freeradius ``` :::warning 若有需要進行手機 App 測試,請取得 QR Code URL 後,以手機 App 操作掃描完成相關設定即可。 ::: ## 功能驗證 為了簡化驗證測試,就先使用 **`localhost`** 本機進行驗證程序。使用 **`radtest`** 命令,採用使用者 **`user02`**,驗證密碼為 **`{使用者密碼}{Google Authenticator 驗證碼}`**。使用以下命令進行測試。 ```bash! $ sudo radtest {username} {password} localhost 18120 testing123 ``` **執行結果** ![](https://i.imgur.com/8WwGPm5.png) :::info 驗證碼也採用**備用碼**以簡化測試過程。 另外檢視使用者的組態檔 **`.google_authenticator`**,也可發現使用的備用碼也從該組態檔中刪去。 ![](https://i.imgur.com/YfQXVTY.png) 可查看 **`/var/log/auth.log`** 檔檢視驗證紀錄。 ![](https://i.imgur.com/2glReSb.png) ::: :::success - 以上大致就是使用 FreeRADIUS 搭配 Google Authenticator 作 MFA 的紀錄。 - 至於後續與其他服務或網路設備整合,大致上只要將驗證主機指向 FreeRADIUS 服務應該就可以達成。 ::: :::warning **待解問題** - 雖然可以按照步驟完成 freeRADIUS 與 Google 認證產生 QRCode。但是整個**執行流程**似乎沒有**前端**可以提供給終端用戶。但可以**透過腳本程式達成一點點自動化的目標**。 - 若客戶**已有 AD 的使用者資料庫**,似乎 freeRADIUS 還要另外**與 AD 整合使用者資料庫**,否則將使造成管理者管理帳戶的負擔。 - 不清楚 AD 是否可以直接與 Google 認證結合?還是可以改用 **Microsoft Azure**? ::: --- # 參考 - [SSLVPN Two-factor Authentication with Google Authenticator](https://kb.hillstonenet.com/en/wp-content/uploads/2019/09/SSLVPN-Two-factor-Authentication-with-Google-Authenticator.pdf) - [FreeRADIUS Google Dual Factor Authenticator](https://developer.aliyun.com/article/449710) - [Setup FreeRADIUS on Kali Linux for 802.1X Authentication](https://www.youtube.com/watch?v=AwkIUw8mS_c) - [Quickly Install FreeRadius on CentOS 7 and Do a Basic Configuration](https://youtu.be/CXG51efc5oc)