章節概覽#

本章涵蓋讓 user-space 軟體能與系統基礎設施互動的重要組件,包括:

  • System logging — 系統日誌記錄
  • 系統函式庫存取的設定檔(取得伺服器與使用者資訊)
  • 開機時啟動的伺服器程式(daemons)
  • 時間設定定期任務排程

隨著 systemd 的普及,許多獨立 daemon 已被整合。例如傳統的 syslogd 大部分功能已由 systemd 內建的 journald 取代,但 crond 和 atd 等傳統 daemon 仍然存在。


7.1 System Logging#

大多數系統程式將診斷輸出以訊息形式寫入 syslog 服務。在現代系統上,journald(隨 systemd 而來)負責大部分工作,但許多系統也同時執行傳統的 rsyslogd。

一則 log 訊息通常包含:

  • Timestamp — 時間戳記
  • Process nameProcess ID
  • Facility — 訊息的一般分類(如 kernel、mail、printer)
  • Severity — 訊息的緊急程度(0-7,0 最重要)

7.1.1 檢查 Log 設定#

確認系統使用哪種 logging 的步驟:

  1. 執行 journalctl 檢查 journald 是否運作
  2. 在 process listing 中尋找 rsyslogd,並檢查 /etc/rsyslog.conf
  3. 若無 rsyslogd,檢查 /etc/syslog-ng 目錄(syslog-ng)

日誌檔案通常位於 /var/log,journald 的二進位日誌存放在 /var/log/journal

7.1.2 搜尋與監控 Log#

使用 journalctl 搜尋日誌的常用方式:

依時間篩選:

journalctl -S -4h          # 最近 4 小時
journalctl -S 2020-01-14   # 特定日期之後

依 Unit 篩選:

journalctl -u cron.service  # 特定 unit
journalctl -F _SYSTEMD_UNIT # 列出所有 unit

依文字篩選:

journalctl -g 'kernel.*memory'  # 正規表示式搜尋

依開機篩選:

journalctl -b       # 當前開機
journalctl -b -1    # 上一次開機
journalctl --list-boots  # 列出所有開機記錄

依嚴重性篩選:

journalctl -p 3     # 等級 0-3(emerg 到 err)
journalctl -p 2..3  # 等級 2 到 3

即時監控:

journalctl -f  # 類似 tail -f 的效果

要完整存取 journal 訊息,需要以 root 身份執行 journalctl,或者使用者需屬於 adm 或 systemd-journal 群組。

7.1.3 Logfile Rotation#

使用 syslog daemon 時,日誌會不斷增長。logrotate 工具負責 log rotation(日誌輪替):

  • 將日誌分割成多個 chunk(如 auth.logauth.log.1auth.log.2
  • 輪替時移除最舊的檔案,依序重新命名
  • 部分發行版會壓縮舊日誌(如 auth.log.2.gz
  • 部分發行版以日期作為後綴(如 -20200529

7.1.4 Journal 維護#

journald 儲存在 /var/log/journal 的日誌不需要 rotation。journald 根據以下因素自動管理:

  • 檔案系統剩餘空間
  • journal 應佔檔案系統的百分比
  • 設定的最大 journal 大小
  • 日誌訊息的最大保留時間

詳細設定請參考 journald.conf(5) manual page。

7.1.5 深入了解 System Logging#

Syslog 的運作機制:

  • 傳統 syslogd 監聽 Unix domain socket /dev/log 等待訊息
  • 也可以監聽網路 socket,讓多台機器的 log 集中到一台伺服器
  • Syslog 協定定義在 RFC 5424

Facility 與 Severity:

  • Facility — 訊息來源的服務類別(kernel、mail system、printer 等)
  • Severity — 八個等級(0-7):
等級名稱等級名稱
0emerg4warning
1alert5notice
2crit6info
3err7debug

Syslog 與 journald 的關係:

Syslog 仍然存在的原因:

  • 擅長跨機器彙整日誌
  • rsyslogd 等版本支援模組化輸出(多種格式與資料庫)

journald 則專注於單一機器的日誌收集與組織,並能將日誌轉送給不同的 logger。


7.2 /etc 的結構#

大多數系統設定檔位於 /etc。近年趨勢是將設定檔放入 /etc 下的子目錄(如 /etc/systemd)。

為解決升級時設定被覆蓋的問題,現在可以將自訂設定放在設定子目錄中的獨立檔案(如 /etc/grub.d 中的檔案)。

/etc 中存放的是單一機器的可自訂設定(如 /etc/passwd/etc/network)。系統預設設定檔(不需自訂的)則放在其他位置,如 /usr/lib/systemd


7.3 User Management Files#

Unix 系統支援多個獨立使用者。在 kernel 層級,使用者只是數字(user ID),username 僅存在於 user space。

7.3.1 /etc/passwd 檔案#

/etc/passwd 以純文字將 username 對應到 user ID。每行包含七個以冒號分隔的欄位:

juser:x:3119:1000:J. Random User:/home/juser:/bin/bash
  • Login name — 使用者名稱
  • Passwordx 表示密碼存在 shadow 檔案中,* 表示無法登入
  • User ID (UID) — kernel 中使用者的數字表示
  • Group ID (GID) — 使用者的 primary group
  • GECOS — 使用者的真實姓名等資訊
  • Home directory — 家目錄路徑
  • Shell — 使用者登入時執行的 shell

Figure 7-1: An entry in the password file

若 password 欄位為空(兩個連續冒號),表示不需密碼即可登入。絕對不要讓使用者無密碼登入。

7.3.2 特殊使用者#

  • root (superuser) — 永遠是 UID 0、GID 0
  • daemonbin 等 — 無法登入的系統使用者
  • nobody — 權限極低的使用者,部分 process 以此身份執行

無法登入的使用者稱為 pseudo-users,通常基於安全理由而建立。

7.3.3 /etc/shadow 檔案#

shadow password file (/etc/shadow) 儲存加密過的密碼及密碼過期資訊。它的引入是為了提供更安全、更靈活的密碼儲存方式。一般使用者無法讀取此檔案。

7.3.4 操作使用者與密碼#

  • passwd — 變更密碼
  • chfn — 變更真實姓名
  • chsh — 變更 shell(shell 必須列在 /etc/shells 中)
  • adduser / userdel — 新增/刪除使用者
  • vipw — 安全編輯 /etc/passwd(加鎖備份)
  • vipw -s — 安全編輯 /etc/shadow

不要直接用文字編輯器修改 /etc/passwd。使用 vipw 可以在編輯時加鎖並備份,避免並行修改問題。

7.3.5 群組 (Groups)#

/etc/group 定義群組 ID。每行包含四個欄位:

disk:*:6:juser,beazley
  • Group name — 群組名稱
  • Group password — 幾乎不使用(通常為 *!
  • Group ID (GID) — 唯一的群組 ID
  • Additional members — 額外屬於此群組的使用者列表

使用 groups 指令查看你所屬的群組。

Figure 7-2: An entry in the group file

Linux 發行版通常會為每個新使用者建立一個同名的群組。


7.4 getty 與 login#

getty 程式連接到終端機並顯示登入提示。在大多數 Linux 系統上,getty 僅用於虛擬終端 (virtual terminal)。

登入流程:

  1. getty 顯示登入提示
  2. 輸入使用者名稱後,getty 將自己替換為 login 程式
  3. login 要求輸入密碼
  4. 密碼正確時,login 使用 exec() 將自己替換為使用者的 shell
  5. 實際的認證工作由 PAM 處理(見 7.10 節)

現今大多數使用者透過圖形介面(如 gdm)或 SSH 遠端登入,不直接使用 getty 或 login。


7.5 設定時間#

Unix 機器依賴準確的計時。kernel 維護 system clock(系統時鐘),PC 硬體則有電池供電的 real-time clock (RTC)

  • kernel 開機時根據 RTC 設定系統時鐘
  • Time drift — kernel 時間與真實時間的差距,長時間運行後會累積
  • 不要用 hwclock 修正 time drift,應使用網路時間 daemon
hwclock --systohc --utc  # 將 RTC 設為 kernel 的 UTC 時間

保持硬體時鐘使用 UTC,以避免時區和日光節約時間造成的問題。

7.5.1 Kernel 時間表示與時區#

  • kernel 以自 1970 年 1 月 1 日 00:00 UTC 以來的秒數表示時間
  • 本地時區由 /etc/localtime 控制(二進位檔案)
  • 時區檔案位於 /usr/share/zoneinfo
  • 使用 tzselect 指令幫助選擇時區

臨時變更時區:

export TZ=US/Central
date

7.5.2 Network Time#

Network Time Protocol (NTP) 透過遠端伺服器維持時間同步:

  • 傳統由 ntpd 處理,現在 systemd 提供了 timesyncd
  • 大多數 Linux 發行版預設啟用 timesyncd
  • 若無永久網路連線,可使用 chronyd
  • 設定詳見 timesyncd.conf(5) manual page

7.6 使用 cron 與 Timer Units 排程週期性任務#

有兩種方式執行週期性任務:cronsystemd timer units

cron 基礎#

透過 crontab 指令建立 cron job。crontab 檔案每行的前五個欄位指定排程時間:

分鐘  小時  日  月  星期幾  指令

範例:

15 09 * * * /home/juser/bin/spmake       # 每天 9:15
15 09 14 * * /home/juser/bin/spmake      # 每月 14 號 9:15
15 09 5,14 * * /home/juser/bin/spmake    # 每月 5 號和 14 號 9:15
  • * 表示匹配所有值
  • 可用逗號指定多個值

Figure 7-3: An entry in the crontab file

若 cron job 產生 standard output 或錯誤,cron 會將資訊 email 給 job 的擁有者。將輸出導向 /dev/null 可避免收到信件。

7.6.1 安裝 Crontab 檔案#

  • crontab file — 安裝 crontab 檔案
  • crontab -e — 編輯 crontab
  • crontab -l — 列出 cron jobs
  • crontab -r — 移除 crontab

使用者的 crontab 存放在 /var/spool/cron/crontabs

7.6.2 System Crontab 檔案#

系統層級的 cron 任務定義在 /etc/crontab,格式多一個使用者欄位:

42 6 * * * root /usr/local/bin/cleansystem > /dev/null 2>&1

部分發行版也使用 /etc/cron.d 目錄及 /etc/cron.daily 等目錄。

7.6.3 Timer Units#

systemd timer unit 是 cron job 的替代方案。需要建立兩個 unit 檔案:

Timer unit (loggertest.timer):

[Unit]
Description=Example timer unit

[Timer]
OnCalendar=*-*-* *:00,20,40
Unit=loggertest.service

[Install]
WantedBy=timers.target

Service unit (loggertest.service):

[Unit]
Description=Example Test Service

[Service]
Type=oneshot
ExecStart=/usr/bin/logger -p local3.debug I\'m a logger
  • OnCalendar 格式:year-month-day hour:minute:second
  • Type=oneshot 表示服務執行完畢後即結束
  • Timer unit 放在 /etc/systemd/system

7.6.4 cron 與 Timer Units 的比較#

cron 的優勢:

  • 設定更簡單
  • 與第三方服務的相容性
  • 使用者更容易安裝自己的任務

Timer units 的優勢:

  • 透過 cgroups 追蹤相關 process
  • journal 中有更好的診斷資訊記錄
  • 更多啟動時間和頻率的選項
  • 可使用 systemd 依賴關係與啟動機制

7.7 使用 at 排程一次性任務#

at 服務用於排程只執行一次的任務:

at 22:30
at> myjob

按 CTRL-D 結束輸入。

  • atq — 查看已排程的 job
  • atrm — 移除 job
  • 可指定未來日期:at 22:30 30.09.15

7.7.1 Timer Unit 等效方式#

使用 systemd-run 建立一次性的 transient timer unit:

systemd-run --on-calendar='2022-08-14 18:00' /bin/echo this is a test
  • 也可用 --on-active=30m 指定相對時間(30 分鐘後)

使用 --on-calendar 時,必須包含未來的日期和時間。否則 timer 和 service unit 會持續存在,每天在指定時間重複執行。


7.8 以一般使用者執行 Timer Units#

Timer units 也可以一般使用者身份執行,透過 --user 選項傳給 systemd-run

但有一個限制:若使用者登出,unit 會終止(因為 systemd 的 user manager 與登入 session 綁定)。解決方式:

loginctl enable-linger        # 為自己啟用
loginctl enable-linger user   # root 為其他使用者啟用

7.9 User Access 進階主題#

7.9.1 User ID 與使用者切換#

使用 sudosu 切換使用者時,本質上是在改變 user ID。kernel 的三個基本規則:

  • process 可以執行 setuid 程式(只要有適當的檔案權限)
  • 以 root (UID 0) 執行的 process 可用 setuid() 變成任何使用者
  • 非 root process 無法使用 setuid()

7.9.2 Process Ownership、Effective UID、Real UID 與 Saved UID#

每個 process 實際上有多個 user ID:

  • Effective UID (euid) — 決定 process 的存取權限(如檔案權限)
  • Real UID (ruid) — 表示啟動 process 的使用者,決定誰可以 kill 該 process
  • Saved user ID — process 可在 euid 和 saved UID 之間切換
  • File system user ID (fsuid) — 定義存取檔案系統的使用者(很少使用)

大多數 process 的 euid 和 ruid 相同。執行 setuid 程式時,Linux 將 euid 設為程式擁有者,但保留原始使用者在 ruid 中。

安全注意事項:

  • 必須嚴格控制具有 setuid 權限的程式數量與品質
  • 將 bash shell 設為 setuid root 會讓任何本地使用者取得完整系統控制權
  • 利用 root 程式的弱點是系統入侵的主要方法之一

7.9.3 User Identification、Authentication 與 Authorization#

多使用者系統的三個安全面向:

  • Identification — 辨識使用者是誰
  • Authentication — 驗證使用者確實是他所宣稱的人
  • Authorization — 定義並限制使用者被允許做的事

kernel 只認識數字 user ID,所有與 username 和密碼相關的認證都在 user space 進行。

7.9.4 使用函式庫取得使用者資訊#

程式透過標準函式庫函式(如 getpwuid())取得使用者名稱,而非直接讀取 /etc/passwd。這樣可以在不修改程式的情況下變更認證實作(如改用 LDAP)。


7.10 Pluggable Authentication Modules (PAM)#

PAM 是 1995 年由 Sun Microsystems 提出的認證框架(Open Software Foundation RFC 86.0)。應用程式將使用者交給 PAM 來判斷是否能成功認證,支援雙因素認證、實體金鑰等多種方式。

PAM 使用動態載入的 authentication modules(共享物件),每個模組執行特定任務。例如 pam_unix.so 可以檢查使用者的密碼。

7.10.1 PAM 設定#

設定檔位於 /etc/pam.d 目錄。每行設定包含三個欄位:

function_type    control_argument    module

Function types(功能類型):

  • auth — 認證使用者身份
  • account — 檢查帳號狀態(是否被授權)
  • session — 執行 session 相關動作(如顯示每日訊息)
  • password — 變更密碼或其他憑證

Control arguments(控制引數):

  • sufficient — 成功即完成認證,失敗則繼續下一條規則
  • requisite — 成功則繼續,失敗則立即結束認證(失敗)
  • required — 成功則繼續,失敗也繼續處理後續規則,但最終一定回報失敗

範例(chsh 的認證堆疊):

auth    sufficient    pam_rootok.so
auth    requisite     pam_shells.so
auth    sufficient    pam_unix.so
auth    required      pam_deny.so

此設定的流程:root 直接通過 → 檢查 shell 是否在 /etc/shells → 檢查密碼 → 全部失敗則拒絕。

Figure 7-4: PAM rule execution flow

7.10.2 PAM 設定語法提示#

  • 使用 man -k pam_ 尋找系統上可用的 PAM 模組
  • 許多發行版自動產生 PAM 設定檔,直接修改前先閱讀檔案中的註解
  • /etc/pam.d/other 定義沒有專屬設定檔的應用程式的預設設定(通常是拒絕所有)
  • @include 語法可載入整個設定檔
  • 部分模組使用 /etc/security 中的額外檔案來設定 per-user 限制

7.10.3 PAM 與密碼#

密碼設定的歷史遺留物:

  • /etc/login.defs — shadow password 套件的原始設定檔,有 PAM 時很少使用
  • PAM 設定中的加密演算法設定在 password function 中
grep password.*unix /etc/pam.d/*

設定密碼時,PAM 使用 obscure(檢查密碼強度)和 sha512(加密演算法)等參數。驗證密碼時,pam_unix.so 會自動嘗試猜測加密演算法(透過 libcrypt 函式庫)。


7.11 展望#

本章幾乎完全在 user space 層面討論了系統設定,涵蓋了 logging、使用者管理、時間設定、任務排程與認證等 Linux 系統的核心組成部分。這些內容展示了如何將服務與任務分割成小型、獨立但仍能互動的部分。

下一章將回到 kernel,深入探討 user-space process 及其所消耗的資源。