2020年6月14日 星期日

Raspberry Pi OS 建置輕量 Citrix XenDesktop thin client

Why RPi Citrix thin client

Raspberry Pi的低功耗、價位便宜、且效能足夠作為一個 terminal,除了要自己從零開始建構的問題外(尤其對於不懂 Linux 的人),是個做成 Citrix thin client 非常經濟的選擇。以本人服務的單位而言,大多使用者的需求就是基本公司 ERP 的操作與 Office 系統的需求,讓使用者透過 Raspberry Pi 登入 Citrix desktop 完全錯錯有餘
在本文中,會介紹從RPi官方維護的作業系統出發,從最精簡的Lite版本出發,建構起一個能運作的 Citrix thin client
因為是自建使用,不會比外面市售的 Citrix thin client 考量的完善,供有需要的使用者參考,或在我目前嘗試出來的成果上再精進

硬體需求

Raspberry Pi:我測試過 3B, 3B+, 4B
TF卡:本文中全部安裝完需要的空間不會超過 4 GB,可以依實際需求決定採用的 TF 卡容量
螢幕:Raspberry Pi 3B, 3B+只允許單螢幕,Raspberry Pi 4B 可以接雙螢幕
Citrix:XenApp, XenDesktop, Netscaler Gateway
其他周邊:外接音效卡、智慧晶片卡讀卡機 等

準備階段

首先先去抓 Raspberry Pi 官方提供的 Raspberry Pi OS Lite (原名 Raspbian),本文是以 Buster 2020-05-27 版為基礎進行製作
Raspberry Pi OS 預設網路是透過 DHCP 取得 IP,如果有特定網路環境配置,需要先依使用環境做相關設定

從Windows燒錄

Raspberry Pi 官方介紹 Windows 燒錄方法介紹網頁中有三套工具可供選擇 balenaEtcher、Win32DiskImager 與 imgFlasher 兩套工具;本人是使用 Win32DiskImager ,沒有做過三套工具的比較。
Win32DiskImager 操作上非常簡單,只需要在 Image File 欄位選擇下載並解壓縮得到的 .img 檔,確認後面 Device 選擇的位置是正確的,大膽的點下 Write,剩下的就等資料完整寫到 TF 上。
註:我在使用 Win32DiskImager 的這段時間中,有發現到兩個比較明顯的問題
1. 若先開啟 Win32DiskImager 才插入 TF卡,Win32DiskImager 不一定會抓到 Windows 掛載 TF 的位置
2. Win32DiskImager 在讀寫的過程中,可能會導致其他偵測這台Windows電腦的系統;我使用時發現其他台電腦安裝的 MS SCCM 會偵測不到使用的電腦
如果這兩個問題會影響到操作,建議給另外兩套表現的機會

從 Linux 燒錄

從 Linux 進行將 img 檔燒錄至 TF 卡,可以透過工具,像是 balenaEtcher,也可以直接使用指令,當作是更熟悉 dd 指令。假設要 TF 被掛在 /dev/sdd 上,指令為
# dd bs=4M if=2020-05-27-raspios-buster-lite-armhf.img of=/dev/sdd status=progress conv=fsync
註:
dd 是磁碟複製用的指令,使用上要相當注意 if(來源)與 of(目標),按下 enter 以後 of 指向的磁區就會被覆蓋成 if 的內容,是有一定的危險性,要再三確認沒有填寫錯誤後再按下 enter

Raspbian Lite 準備就緒

燒錄完成後,需要先確認接下來會使用的螢幕解析度能不能接收 1080P,如果是使用 HDMI to VGA 的轉接方式,且螢幕沒有 22 吋(基本上可以猜測沒有到 1080P),需要先將螢幕輸出的部份調整好,避免螢幕沒辦法顯示過於細緻的解析度
如果是 Windows 使用者,在燒錄完成後會掛載一個 boot 磁碟;如果是 Linux 使用者,請掛載 /dev/sdc1 磁碟。更改磁碟內的 config.txt 檔案,檔案內已經有寫好一些基本的以及使用者可能會設定的,把最前面的 # 刪除就能啟用該項設定
hdmi_safe   #如果螢幕是 17吋以下的舊式螢幕,或是一直沒有辦法正確顯示,就直接開啟這個模式吧
hdmi_force_hotplug = 1  #建議開啟此項,RPi 會強致送顯示資訊至 HDMI,可以避免開機時沒有插入 HDMI,或使用中插拔 HDMI 而導致 RPi 關閉 HDMI 的問題
hdmi_group = 2  #與 hdmi_mode 配合
hdmi_mode = 16  #與 hdmi_group 配合,用來設定 HDMI 輸出解析度,如果已經很明確解析度,可以現在更改
螢幕部份設定完成後,就只需要把 TF 卡置入 RPi 內,準備第一次開機

第一次登入

剛燒錄好的 Raspbian 首次開機,會進行內部的調整後重新啟動,包括將根目錄能使用的空間擴展至整個TF能使用的範圍,因此不會再像早期的的 Raspbian 忘了到 raspi-config 裡面去 expend file system
緊接著第二次開機,Raspbian 的預設使用者是 pi ,密碼是 raspberry,第一次登入後建議先把 Raspbian 的環境設定好,並將系統更新
在設定過程中,基本上都會需要有 root 權限,這邊就看使用者的習慣是將使用者切換為 root 下指令:
# sudo su

或是在一般使用者,在進行較高權限指令時進行權限索取的動作

# sudo raspi-config

後續的指令都不會特別強調權限的問題,基本上在安裝過程都會需要 root 權限,設定過程要依系統設定檔或使用者設定檔決定需不需要權限。

環境設定

Raspberry Pi OS 提供了集中化系統設定指令,讓使用者可以快速設定基本環境
# raspi-config
這邊我只變更 keyboard 設定(其他的與 Citrix thin client 設定比較沒相關):
  • Raspbian 預設的鍵盤配置是 UK 105 鍵標準鍵盤,這邊只需要改成 US 105 鍵標準鍵盤就能符合台灣使用習性運作。依序點選 Location options, Change keyboard layout, Others, English (US), English (US), default layout, no compose key,可以看到相對應的設定檔內容變動
# cat /etc/default/keyboard
XKBMODEL="pc105"
XKBLAYOUT="us"
XKBVARIANT=""
XKBOPTIONS=""
BACKSPACE="guess"

系統更新

如果還沒有離開 raspi-config,可以直接點選 Update,會自動連線到網路上進行更新。使用者也可以透過 command line 方式手動更新:
# apt-get -y update
# apt-get -y full-upgrade

更新韌體(非必要,不建議)

如果仔細去 google Raspberry Pi update 的相關文章,部份會提到可以對 Raspberry Pi 的 firmware 做更新
# rpi-update
這個動作執行後,會出現一些不建議一般使用者更新的字串,確認更新後會將 Raspbian kernel 更新到測試用的最新 kernel 版本(4.19-118-v7+ 變成 5.4.42-v7+),除非使用上遇到無法解決的問題(像是有硬體抓不到的狀況),或是開發者需要測試環境需求,不然是沒有必要去更新 kernel

安裝 GUI 環境

Raspbian 可以選用的 XWindow 很多,有興趣的可以參考這篇,但是這邊會直接安裝 icewm 做視窗介面(這邊選用 icewm 的原因,主要是先前的 Raspbian 版本測試過程,官方建議的 rdp 沒辦法讓 RPi 4B 的雙螢幕輸出都是為 Citrix 環境)
  • xserver-xorg, xinit:XWindow 基礎
  • icewm:這邊使用的 GUI 管理套件
  • lightdm:登入管理,用於讓 raspi-config 設定預設開機到 GUI 環境
# apt-get install --no-install-recommends xserver-xorg xinit icewm lightdm
這邊有設定不安裝建議套件(--no-install-recommends),少了這個選項會安裝過多不必要的元件,用基本的就能跑了,節省RPi的效能與記憶體

設定啟動 XWindow 環境

安裝完 lightdm,可以在一次執行 raspi-config 來設定開機登入到 XWindow 環境並自動登入 pi:
Boot Options, Desktop / CLI, Desktop Autologin。

配置 icewm

icewm 有提供環境配置的範例(/usr/share/icewm/),這邊的設定以全部不顯示來更動設定檔,將工作列、開始選單等資訊隱藏
  • 設定配置
    # cat /home/pi/.icewm/preferences
    WorkspaceNames=" 1 "
    ShowTaskBar=0
    ShowSettingsMenu=0
    ShowFocusModeMenu=0
    ShowThemesMenu=0
    ShowProgramsMenu=0
    ShowHelp=0
    ShowAbout=0
    ShowRun=0
    ShowLogoutMenu=0
    ShowWindowList=0
  • 主題配置
# cat /home/pi/.icewm/theme
Theme="icedesert/default.theme"
  • 功能選單配置
# echo "" > /home/pi/.icewm/menu
 

安裝與建立 Citrix 環境

至 Citrix官網下載 Citrix Workspace app for Linux, Debian, ARM HF,看需求下載 Full packages / Web packages 與 USB 介面功能,並安裝
# dpkg -i *.deb
我建置過程只有安裝 Web packages,安裝完成後可能會出現必要 library 遺失的警告訊息,再進行修正
# apt-get install -f --no-recommends
Citrix Workspace app 詳細的環境設定內容,可以參照 Citrix Workspace app for Linux。Citrix workspace app 的預設通常會符合大部分使用者,不過還是建議檢查下列相關設定與需求是否相符:
  • USB 裝置:大部分指的是儲存設備是否會掛載到 Citrix 系統上,這部分還有智慧卡設備設定
  • MIC 與 web cam:如果有允許使用者能使用通訊或視訊會議,相關影音資料要設定能轉到 Citrix 系統上

安裝與設定 XWindow 環境

這邊要安裝的工具包括
  • 瀏覽器:chromium-browser
  • 數字鎖管理:numlockx
    XWindow 預設鍵盤 Num Lock 是關閉的,安裝完 numlockx 後會變成是開啟的;這個套件要依個人操作特性決定要不要安裝
  • 中文字形:fonts-wqy-microhei, xfonts-wqy
    Raspberry Pi OS 預設並沒有安裝中文字型,供 Citrix 登入後的中文顯示使用。如果確定不會設定中文名稱,可以不用安裝
apt-get install --no-install-recommends chromium-browser numlockx fonts-wqy-microhei xfonts-wqy
安裝完相關工具後,可以設定開機時會自動開啟網頁至 Citrix store-front 入口網頁
# cat /home/pi/.icewm/startup
#!/bin/bash
rm ~/Downloads/*.ica
chromium-browser http://your.citrix.FQDN

# chmod +x /home/pi/.icewm/startup
註:
1. 這邊有額外設定將 Downloads 資料夾內的 ica 檔案移除,因為 chromium 會將 Citrix 連結的檔案下載後呼叫 Workspace app 執行,所以 Downloads 資料夾內的 ica 檔需要固定清理
2. 自動執行是透過 icewm 的啟動後自動執行機制,startup 需要設定為可執行檔

Chromium 設定

由於 chromium 預設會開啟很多提示使用者的小視窗,像是儲存密碼、翻譯、恢復前次瀏覽等等,為了要讓使用者有更加的體驗,我會透過在 chromium 的啟動設定中去關閉這些功能
  • 簡潔模式 --kiosk (全螢幕)
  • 無痕模式 --incognito (密碼提示、前次瀏覽)
  • 延遲chromium更新檢查7日 --check-for-update-interval=604800
    # cat /etc/chromium-browser/customizations/01-customize-settings
    CHROMIUM_FLAGS="${CHROMIUM_FLAGS} --kiosk --incognito --check-for-update-interval=604800"
    
  • 取消自動翻譯功能提示
    # cat /etc/chromium-browser/policies/managed/no-translate.json
    {
      "TranslateEnabled": false
    }
  • 自動開啟 ica 檔
    設定自動開啟 ica 檔,會需要知道 JSON 檔案結構,建議可以手動開啟 chromium 下載一次 ica 檔後,點選 Always open files of this type;chromium 會產生的設定為
# cat ~/.config/chromium/Default/Preferences
{...,"download":{"directory_upgrade":true,"extensions_to_open":"ica"},...}
 

其他調整(非必要)

將 Raspberry Pi OS 作為 Citrix thin client,到這邊基本已經能正常運作,後續是想要繼續完善整體的行為而進行的設定與調整,如果有需要再做相關設定

隱藏開機畫面

Raspberry Pi OS 在開機過程保有 Linux 開機過程回饋目前啟動的進度,這些訊息與圖片是可以隱藏起來的。主要的設定
# echo "disable_splash=1" >> /boot/config.txt
# echo "avoid_warnings=1" >> /boot/config.txt
  • disable_splash=1:隱藏開機彩虹圖
  • avoid_warnings=1:隱藏電壓不穩、溫度過高等警告訊息(不建議關閉)
# cat /boot/cmdline.txt
console=serial10,115200 console=tty3 root=PARTUUID=...省略... rootwait loglevel=3 quiet logo.nologo vt.global_cursor_default=0
  • console=tty3:將啟動訊息從 tty1 改到 tty3
  • loglevel=3:降低 log 等級,減少 log 量,不過我不是那清楚會減少哪些log訊息
  • quiet:隱藏開機系統檢測訊息
  • logo.nologo:隱藏啟動訊息上方的樹莓 logo
  • vt.global_cursor_default=0:隱藏游標閃爍
在隱藏完大部分會顯示的訊息後,在 Raspberry Pi 開機過程中會有一定的機率螢幕會顯示自動登入的資訊,這部份可更改設定為:
# cat /etc/systemd/system/getty\@tty1.service.d/autologin.conf
ExecStart=
ExecStart=-/sbin/agetty --skip-login --noclear --noissue --login-options "-f pi" %I $TERM
如果有更改自動登入使用者名稱,注意把 pi 更改為登入的使用者
這邊的 autologin 會影響到 tty1 的登入人員,而實際登入到桌面的使用者,會是由 lightdm 控制

鎖定切換至終端機 tty1~6

偶爾就是會遇到一些使用者會用舊的輸入法切換方式(注音=Ctrl+Alt+3),然後 3 又按成 F2 或 F3 一代的 Fn 按鍵,然後就(接到電話)悲劇了。為了避免這一類的問題發生,我是透過 xmodmap 的設定取消 Alt+Ctrl+Fn 的鍵盤對應功能。首先要先安裝 xmodmap 套件
# apt-get install x11-xserver-utils
接著,建立鍵盤對應設定檔
# cat /home/pi/.Xmodmap
keycode 67 = F1 F1 F1 F1 F1 F1
keycode 68 = F2 F2 F2 F2 F2 F2
keycode 69 = F3 F3 F3 F3 F3 F3
keycode 70 = F4 F4 F4 F4 F4 F4
keycode 71 = F5 F5 F5 F5 F5 F5
keycode 72 = F6 F6 F6 F6 F6 F6
keycode 73 = F7 F7 F7 F7 F7 F7
keycode 74 = F8 F8 F8 F8 F8 F8
keycode 75 = F9 F9 F9 F9 F9 F9
keycode 76 = F10 F10 F10 F10 F10 F10
keycode 95 = F11 F11 F11 F11 F11 F11
keycode 96 = F12 F12 F12 F12 F12 F12
將讀取設定寫入 icewm 開機流程中
# echo "xmodmap ~/.Xmodmap" >> ~/.icewm/startup
透過 xmodmap 來限制 Alt+Ctrl+Fn 的運作,我習慣將開機環境的設定優先執行,接續啟動相關程式,因此這邊將指令調整在 startup 的第二行
這邊需要注意的,一旦取消 tty1~6 的快速鍵,將會導致以後沒有 terminal 可以使用。我是建議安裝 XWindow 下的 terminal 套件,全部設定都改在 GUI 環境中進行
# apt-get install xterm

並將 icewm 的快速鍵設定對應到 xterm 上

# echo /home/pi/.icewm/keys
key "Alt+Ctrl+t"   x-terminal-emulator

螢幕保護程式設定

Raspberry Pi OS 預設閒置600秒後會啟用螢幕保護程式,如果沒有安裝任何螢幕保護程式套件,會顯示全黑的畫面。如果要取消螢幕保護程式可以透過指令
# xset s off
# xset -dpms
若只想更改閒置時間為60秒
# xset s 60
# xset dpms 60 60 60
詳細的設定說明可以參閱 xset ,並將設定寫入啟動執行中

RPi 資安防護

網路上有不少 Raspberry Pi 加強防護的介紹,畢竟 Raspberry Pi 預設密碼是公開的,沒人會希望自己建立起來大量的 Raspberry Pi 會因為設定不周嚴而變成 DDoS attack 的幫凶。可以用的步驟包括
  • 更改預設使用者:
    就是不要再使用 pi 這個大家都知道的使用者,並停用 pi;如果有設定新的使用者,記得要在 sudoer 裡面增加新使用者,避免無法切換為 root
  • 更改預設密碼:跟更改預設使用者類似的意思
  • 切換 root 密碼:
    Raspberry Pi OS 為了要讓使用者方便,有在 sudoer 內增加使用者 pi 不用輸入密碼的設定,可以刪除該檔案讓 sudo 需要密碼
# rm /etc/sudoers.d/010_pi-nopasswd
  • 安裝防火牆
    # apt-get install ufw
  • 只開必要的連線方式:
    在 raspi-config 裡面有預設許多常見的連線方式,預設都會是關閉的,避免開啟不必要的連線方式
    如果有開啟網路連線的方式,使用或更換成自訂的 port 會是一個不錯的防範方法,fail2ban 是更佳的防範工具
    # apt-get install fail2ban
  • 刪除設定與狀態紀錄:
    慣用 Linux 的使用者應該都會知道,敲過的指令都會記錄在 ~/.bash_history,系統操作過程中有出現的紀錄都會在 /var/log,如果 Raspberry Pi 是會給其他使用者使用的狀態下,為了避免遇到強者輕易破解所有設定,設定紀錄與 log 檔還是在設定完成後刪除,會比較保險
  • 變更預設快速鍵行為:
    我在使用 XWindow 最常用的快速鍵之一,莫過於將 xterminal 叫起來,如果想要避免會 Linux 的使用者用查看個人化設定,變更 xterminal 與檔案管理工具快速鍵、停用 tty1~6 快速鍵,都是可以提防的作法

晶片卡讀卡機

對於有銀行或政府業務往來的人而言,就會有需求能用讀卡機讀取晶片卡、自然人憑證。這對於 Raspberry Pi / Linux 使用者而言會是一個痛,因為不是所有的週邊設備都會為 Linux 寫驅動程式,更不用講 ARM 架構的 Raspberry Pi。像是市面上非常常見,且便宜的讀卡機 EZ-100PU (我曾有跟製造商反應後被問我是他們的哪個經銷商的經驗,完全忽視終端使用者的需求),Raspberry Pi 就完全抓不到。我在測試過程,參照這篇的建議,(我是在門市買的) InfoThink IT-500U 運作正常。晶片卡會需要相關套件
# apt-get install pcsc-tools pcscd
安裝完畢後,應該會自動啟動 pcscd,如果沒有啟動可以
# systemctl restart pcscd
並將 pcscd 設定為啟動自動執行
# systemctl enable pcscd
啟動完畢後,可以透過 pcsc-tools 內的工具來確認有沒有抓到晶片卡
# pcsc_scan
確認有抓到晶片卡設備與卡片資訊後,重新連線 Citrix,晶片卡資訊就能自動轉到 Citrix 系統內,後續可以考慮用 Windows 晶片卡軟體測試
註:這部份有個我建置過程中感覺蠻詭異的問題,我並沒有安裝 Citrix Workspace App USB 套件,但是晶片卡資訊卻能正常傳遞過去

USB音效卡

Raspberry Pi 作為 thin client 的其中一個麻煩就是只有提供一個 3.5" 耳機輸出孔,並沒有相對應的 mic,對於有想要用 IM 軟體對話功能而言,就必須要用擴充的方式來增加音訊輸入的功能。在目前的設計中。Raspberry Pi 有許多方法可以擴充 mic 輸入,我這邊簡單介紹利用 USB 音效卡來達成需求
Raspberry Pi OS 預設音效輸出會是由 HDMI 介面輸出,且 raspi-config 指令中也可以切換音訊輸出至 3.5" 輸出,但是外接 USB 音效卡後並不會誘使 raspi-config 內的設定多出第三個選項,因此需要自己進行相關設定
首先要先得到 USB 音效卡在目前系統音效輸出的編號
# aplay -l
card 0: b1 [bcm2835 HDMI 1], device 0: bcm2835 HDMI 1 [bcm2835 HDMI 1]
card 1: Headphones [bcm2835 Headphones], device0: bcm2835 Headphones [bcm2835 Headphones]
card 2: Device [USB Advanced Audio Device], device 0: USB Audio [USB Audio]
以我這邊得到的結果是 2,接著到系統設定中將 USB 音效卡設定為預設音效設備
# echo /home/pi/.asound
pcm.!default {
  type hw
  card 2
}

ctl.!default {
  type hw
  card 2
}
設定音效輸出與輸入的聲音大小
# alsamixer
這邊可以先做初步音效輸出測試
# speaker-test -c2
下一步,設定 Citrix Workspace App 音效相關參數
# cat /opt/Citrix/ICAClient/config/module.ini
...
[ICA 3.0]
MultiMedia=On
...
# cat /home/pi/.ICAClient/wfclient.ini
...
[WFClient]
AllowAudioInput=True
EnableAudioInput=True
...
設定完畢後,務必要重新開啟 Citrix 系統 (斷線再登入),Workspace App 看似無法動態把新增的硬體傳遞至 Citrix 系統當中

連線到 Netscaler Gateway

透過 netscaler gateway 登入 Citrix 系統,會需要有合法的憑證才能正常登入。當沒有公發憑證時,就必須手動安裝憑證。首先要先拿到 domain root CA 檔,檔案格式必須要是 PEM(.pem)格式,如果拿到的是 DER(.crt / .cer)格式,就需要先做轉檔(這個是一次性的動作,建議找台 Linux 電腦,確認有安裝 OpenSSL 後進行)
# openssl x509 -inform der -in cert.crt -outform pem -out cert.pem
# openssl x509 -inform der -in cert.cer -outform pem -out cert.pem
Citrix Workspace App 確認憑證的方式,匯到指定的資料夾中尋找相關的 CA 檔,只需要將上面轉出來的 .pem 檔案放至資料夾內可以
# cp cert.pem /opt/Citrix/ICAClient/keystore/cacerts/
在連線到 Netscaler Gateway 之前,要先確認系統的時間正確性,避免時間錯誤而造成連線異常。預設 Raspberry Pi OS 透過 systemd-timesyncd.service 同步時間,其設定檔為 /etc/systemd/timesyncd.conf,如果有特殊應用是在無法連線到網際網路的地方會需要透過 Netscaler Gateway 連線到 Citrix 系統,務必要將內部 NTP server 設定上去