使用 Logind Session 以另一個使用者身份執行 Systemd 服務
問題
如何在啟動時以任意使用者身份執行任意服務,並使用
/run/user/uid
為該使用者創建的登錄會話(特別包括 下的所有好東西)而無需以該使用者身份顯式登錄?背景
我正在轉換 docker-compose 部署以用於無根 podman + systemd 服務。我已經弄清楚了大部分 podman 的東西,但特別是在努力讓它通過 systemd 執行。
在我之前的部署中,我為每個服務創建了一個使用者帳戶,並將容器配置為以此使用者身份執行。從文件系統控制和維護的角度來看,這非常方便,並且確實是我希望保留的主要屬性。
為此,我發現了這個askubuntu 問題,它使我能夠將使用者直接嵌入到我的 systemd 作業中,並以所述使用者的身份執行。完美的。
現在問題來了:Fedora 遷移到了現在由 systemd 處理的 cgroups v2,事實上,這也是最初進行這項工作的原因。因此,podman 需要能夠與 systemd 對話,而 systemd 基本上需要 logind 設置的登錄會話(如果我正確理解此連結)。我不是系統專家,所以請糾正我的任何問題。
我確實發現了另一個關於等待使用者會話的問題,該問題接近我所追求的,但似乎表明這是不可能的。我的情況在兩個主要方面有所不同:
- 我不想等待任何會話(例如,這應該在啟動時執行而無需互動)。
- 我的解決方案需要足夠健壯,才能承受手動干預來啟動和關閉服務。
所以,如上所述,我真的在尋找任何方法來讓 systemd 服務作為特定使用者執行,並有足夠的登錄環境讓服務應用程序連接到 systemd(或者,至少,它的 cgroups v2 部分)。
最後,下面是其中一項服務的範例 systemd 單元文件,該文件按預期工作,直到需要連接到 systemd。此外,當以我的登錄使用者身份手動執行時,podman 呼叫完全有效。
[Unit] Description=Emby Podman Container [Service] User=emby Group=emby Restart=on-failure ExecStartPre=/usr/bin/rm -f /%t/%n-pid /home/emby/%n-cid ExecStart=/usr/bin/podman run --conmon-pidfile /%t/%n-pid --cidfile /home/emby/%n-cid -d --name=emby --cgroup-manager=systemd -e TZ="$TZ" -p 8096:8096 -p 8920:8920 -v /opt/docker/storage/emby:/config -v /media/media/:/media emby/embyserver ExecStop=/usr/bin/sh -c "/usr/bin/podman rm -f `cat /home/emby/%n-cid`" KillMode=none Type=forking PIDFile=/%t/%n-pid [Install] WantedBy=multi-user.target
因此,經過一番摸索後,我找到了一個可行的解決方案,結果證明它比我想像的更簡單,如果不夠優雅的話。讓我們切入正題,看一下功能單元文件:
[Unit] Description=Emby Podman Container BindsTo=user@1012.service After=user@1012.service [Service] User=emby Group=media Restart=on-failure ExecStartPre=/usr/bin/rm -f /home/emby/%n-pid /home/emby/%n-cid ExecStartPre=-/usr/bin/podman rm emby ExecStart=/usr/bin/podman run --conmon-pidfile /home/emby/%n-pid --cidfile /home/emby/%n-cid \ --name=emby --rm --cgroup-manager=systemd \ -e TZ="$TZ" \ -p 8096:8096 -p 8920:8920 \ -v /opt/docker/storage/emby:/config \ -v /media/media/:/media \ emby/embyserver ExecStop=/usr/bin/sh -c "/usr/bin/podman rm -f `cat /home/emby/%n-cid`" KillMode=none Type=forking PIDFile=/home/emby/%n-pid [Install] WantedBy=multi-user.target
這裡的關鍵見解是讓 systemd 管理使用者會話本身(而不是它會讓你做任何其他事情)。在此配置中使用
BindsTo
和After
是必不可少的,因為它們將強制在實際啟動 emby 服務之前完全創建 emby 使用者的使用者會話。此外,這使得管理員(閱讀:我)不必登錄每個使用者來啟用會話,這應該有助於添加更多服務和使用者。有關設置的其他一些有用說明:
- 該
-d
標誌已從 podman 中刪除,以便可以通過journalctl -fu emby _TRANSPORT=stdout
. 便於測試和驗證。- 根據user@.service 手冊頁,必須使用 UID 而不是名稱(在我的系統 emby == 1012 上)實例化使用者服務。我還沒有找到在任何非
Exec
命令中進行擴展的方法,所以現在,這是硬編碼的。如果有人知道如何清理這個,我很想听聽。- PID 文件已移至使用者的主目錄,因為
/run
它不可寫字(也很好)。我嘗試過的其他一些方法不起作用:
- 直接啟動使用者服務
ExecPre
。該單元以使用者身份執行,因此無法為該使用者啟動 systmd(雞,見蛋)。- 自動登錄使用者。注意:這可能有效,但對完全登錄的使用者存在安全隱患。
- 通過 su 更改使用者。 systemd 維護者對 su 的看法相當模糊,拒絕修復它。拋開宗教爭論不談,su plain 是行不通的。
其他參考:
- systemd.unit 手冊頁:與往常一樣,了解手冊頁是一件好事。
- Arch Wiki Page for systemd/User:對 systemd 使用者管理的一些內部結構有很好的描述。
編輯:
當然,一旦我發布了這個,我就設法找到了一個神奇的搜尋字元串,它引導我找到了一篇避免我的方法的文章。
為簡潔起見,上面文章中的要點涉及以 root 身份執行服務並使用
--uidmap
/--gidmap
將容器的 root 使用者映射到所需的系統使用者。但是,此解決方案是特定於 podman 的,因此我將為非 root、非 podman 程序需要訪問 systemd 的其他任何人保留上述內容。
最後,我認為我的解決方案更加安全,因為如果攻擊者破壞了容器執行時,範圍仍然僅限於我的非特權使用者。不過,這可能會被另一個正在執行的使用者服務增加的攻擊面所抵消,因此,這可能是一種清洗。