Systemd

使用 RootDirectory= 執行 systemd 服務並訪問 /bin 二進製文件

  • March 16, 2021

我正在嘗試利用一些 systemd 助手來chroot(2)使用RootDirectory=. 這是一個基本的 Python 腳本,位於/srv/http託管 Web 伺服器的下面。它有一個shebang #!/usr/bin/python (我也嘗試過不同的組合)

服務文件也很簡單:

[Unit]
Wants=network-online.target
After=network-online.target

AssertPathExists=/srv/http

[Service]
Type=simple
Restart=always
RestartSec=10

RootDirectory=/srv/http
PrivateTmp=true

ExecStart=/server.py
PIDFile=/run/miniweb.pid

[Install]
WantedBy=multi-user.target

日誌清楚地表明它找不到執行檔:

Mar 11 19:23:49 bigrigv2 systemd[13213]: testweb.service: Failed to execute /server.py: No such file or directory
Mar 11 19:23:49 bigrigv2 systemd[13213]: testweb.service: Failed at step EXEC spawning /server.py: No such file or directory

它被標記為執行檔:

-rwxr-xr-x 1 anton anton  650 Mar 11 19:06 server.py

我也嘗試過ExecStart=/bin/python /srv/http/server.py其他變體。我不完全確定我是否理解RootDirectory以及如何正確執行來自 chroot 服務腳本的 Python 或其他二進製文件的概念。我的假設是,在執行服務之前,它會 chroot:s 進入,/srv/http之後服務將無法退出並在這種情況下執行 Python。這是有道理的,但是我不太明白為什麼/server.py找不到。你將如何執行依賴於其他二進製文件的事情?大多數解決方案都提到使用語言(例如 C)chroot並從應用程序控制它,但是我不明白在服務腳本中提供 chroot 的意義,而不是非常有限的 bash 腳本或獨立二進製文件。

可能是一個非常簡單的問題,但我很迷茫,任何幫助將不勝感激!

直接回答你的問題:

如何使用 RootDirectory 在 chroot 之外正確執行具有外部依賴項的服務。

你不能。如果某些東西在 chroot 監獄中,它就無法訪問外部的任何東西,包括二進製文件和庫。但仍有一些方法可以保護您的系統。

man systemd.exec

採用相對於主機根目錄(即執行服務管理器的系統的根目錄)的目錄路徑。使用 chroot(2) 系統呼叫設置已執行程序的根目錄。如果使用它,則必須確保程序二進製文件及其所有輔助文件在 chroot() jail 中可用

如果你設置了RootDirectory=/srv/http,那麼當/server.py被呼叫時,它會嘗試執行/usr/bin/python,但是因為找不到那個路徑而失敗。即使您可以執行類似的操作ExecStartPre=/bin/cp /usr/bin/python /src/http/usr/bin/python,當您嘗試這樣做時仍然會遇到問題,import flask或者import pyramid因為這些庫未安裝在您的 chroot 中。我用像你這樣的設置做了一個測試,沒有一個好的shebang,我得到了和你一樣的錯誤。

這裡有三個選項:

  1. 為您的 chroot 提供所需的一切。如果您使用的是基於 debian 的系統,那麼debootstrap設置它的好工具deboostrap buster /srv/http應該可以工作。它將安裝一個基本系統,然後你可以sudo chroot && apt install python python-flask在裡面安裝任何你喜歡的東西。
  2. 使用內置選項對您的服務進行沙箱處理,而不是對其進行 chroot。具體來說:
  • RemoveIPC=truePrivateTmp=true。這些確保了由執行程序創建的 IPC 對象和臨時文件的生命週期綁定到服務的執行時。由於/tmp並且/var/tmp通常是系統上唯一的全域可寫目錄,這確保了該單元在終止後不會留下文件。
  • NoNewPrivileges=trueRestrictSUIDSGID=true。這些確保呼叫的程序無法受益或創建 SUID/SGID 文件或目錄。
  • ProtectSystem=strictProtectHome=read-only禁止服務寫入文件系統中的任何位置(例外是/dev/ /proc//sys/。為了允許服務寫入某些目錄,必須使用ReadWritePaths=.
  • RuntimeDirectory=為服務分配一個執行時目錄,該目錄由服務的使用者擁有,並在系統終止時自動刪除。
  1. 您可以用一行替換我在第二步中所說的所有內容DynamicUser=true。這裡有一個很好的開發者解釋

無論哪種方式,如果您不使用User=DynamicUser=應該使用。這將阻止您的服務存在並擁有對其他機密或其他機密root的讀取權限。/etc/shadow

我真的很喜歡選項 3。啟用它確實可以保護您的系統免受服務的影響。

引用自:https://unix.stackexchange.com/questions/638816