"容器是隔離的空間,因此在內部使用 root 幹嘛都可以吧?"
"非要創建 USER 只會增加層數,太麻煩了..."
"要讓容器 USER 使用綁定到主機的目錄,處理權限也很麻煩..."
許多開發者就是這樣認為,因而直接使用 Dockerfile 的默認值 root 用戶。
但這是 非常危險的安全實踐。容器的“隔離”並不是完美的防火牆,以 root 權限運行容器可能會使整個伺服器面臨風險。
這篇文章將明確解釋為什麼不應以 root 身份運行容器,以及如何防止這種情況的發生。
1. 最壞的情況: "容器逃脫" (Container Escape)
避免使用 root 的最重要原因。
-
基本映射: Docker 容器內的
root用戶 (UID 0) 基本上就是 主機伺服器的root用戶 (UID 0)。 -
當隔離被突破: 假設攻擊者利用應用程序的漏洞或 Docker、甚至是 Linux 核心本身的漏洞成功“逃脫”了容器的隔離環境。
-
結果: 如果此時容器是以
root權限運行的,攻擊者將立即獲取主機伺服器的root權限。整個伺服器將完全被掌控。
比喻: 以
root身份運行容器就像是讓“一個擁有酒店鑰匙的大客戶”住進房間。當這位客戶打開自己房間(容器)的門後,就可以隨心所欲地在整個酒店(主機)內走動。
反之,如果容器是以 appuser (UID 1001) 這樣的無權限普通用戶運行的話,情況會怎樣呢?就算攻擊者成功逃脫,他也只會擁有appuser這一無權限的用戶的權限,從而將損害降到最低。
2. 最小權限原則 (Principle of Least Privilege)
安全的最基本原則是“所有程序和用戶僅應具備執行任務所需的最低權限”。
運行網頁應用程序根本不需要 root 權限。
-
當是
root時: 如果攻擊者進入到容器內(就算沒有逃脫),他仍然是容器內部的root。-
可以隨意安裝惡意的掃描器、加密挖掘工具等。
-
可以修改和刪除所有文件,包括包含數據庫連接信息的配置文件(如
settings.py等)。
-
-
當是
appuser時: 就算攻擊者成功入侵,他也只不過是appuser。-
apt-get install? 權限被拒絕。 -
要修改系統設置文件? 權限被拒絕。
-
損害範圍絕對限制在
appuser擁有的應用源代碼目錄內。
-
3. 澄清常見誤解
🤔 "USER 命令不只是增加映像層而已嗎?"
不是。這是最大的誤解。
Dockerfile 的 USER 命令並不會生成文件系統層。該命令只是向映像的元數據(Metadata) 添加了 “當這個容器啟動時,默認用戶設定為 'appuser'” 的指令。
映像大小不會增加 1KB,生成速度也不會受到影響。
當然,RUN useradd... 命令則會創建用戶並增加非常微小的層,但這是一個為了安全而必須付出的成本。
🤔 "要使用 80 號端口還是必須是 root 吧?"
正確。在 Linux 中,1024 以下的端口(例如 80,443)只能由 root 開放。然而,這不再是以 root 身份運行容器的理由。
現代的做法如下。
-
容器內部以
appuser權限運行應用,使用類似 8000 的高端口。 -
外部通過 Docker 映射端口 (
docker run -p 80:8000),或者使用 Nginx 等反向代理將外部 80 請求轉發至內部8000 端口。
容器內部並不需要 root 權限。
4. 如何: Dockerfile 的最佳實踐
那麼,應該怎麼適用呢?在Dockerfile 的最後添加幾行,這是最基本且重要的安全規則,而不是浪費。
Dockerfile
FROM python:3.12-slim
WORKDIR /app
# ... (apt-get install, pip install 等必要操作)
# 1. 創建無系統權限的(non-privileged)組和用戶
# -r: 以系統用戶/組的身份創建, --no-create-home: 不創建主目錄
RUN groupadd -r appgroup && useradd -r -g appgroup --no-create-home appuser
# 2. 在複製應用文件時指定所有權為 appuser
# (之後 WORKDIR 的文件也會遵循此所有權)
COPY --chown=appuser:appgroup . .
# 3. 之後的命令 будет выполнять пользователь appuser
USER appuser
# 4. 以 8000 之類的高端口啟動應用
EXPOSE 8000
CMD ["gunicorn", "myproject.wsgi:application", "--bind", "0.0.0.0:8000"]
總結
以 root 身份運行容器就是放棄“深度防禦(Defense in Depth)”的概念。在隔離這道第一道防線破裂之時,自行拆除第二道防線(USER)。
現在就檢查一下你的 Dockerfile吧。
目前沒有評論。