🐳 容器安全進階:Docker Rootless 模式與鏡像安全掃描實務
容器安全常見的破口,往往不是「容器裡跑了什麼」,而是「Daemon 與主機權限」本身被放大了。 這篇用兩條主線把風險降下來:第一條是 Docker Rootless(讓 daemon 與容器以非 root 身分運行),第二條是 鏡像安全掃描(在上線前把 CVE 與可修補項目先揪出來)。
📌 目標與適用場景
- 降低 Docker daemon 被攻擊後的主機權限風險(Rootless)
- 建立可落地的鏡像掃描流程:本機掃描、CI 掛閘、輸出報告(Trivy / Docker Scout)
- 適合:多使用者主機、實驗環境、需要縮小 blast radius 的部署
- 不適合:你明確需要大量特權能力(例如非常依賴 privileged、底層網路/儲存驅動強耦合)
🧠 Rootless Docker 是什麼?為什麼它有效?
Rootless 模式的核心就是:Docker daemon 與容器都在 user namespace 內以非 root 身分執行, 用來降低 daemon / runtime 出現漏洞時,直接把主機 root 權限送出去的風險。
✅ Rootless 的安全收益(務實版)
- daemon 不再以 root 權限常駐,攻擊面縮小
- 更適合多租戶或共用主機(避免某人把整台主機拖下水)
- 可與「容器內非 root 執行」、「最小化 capability」、「唯讀檔案系統」一起疊加
🛠 Rootless 安裝前檢查(必要條件)
Rootless 不靠 setuid 與特權(除了必要的 newuidmap/newgidmap),所以主機端要先滿足 user namespace 的映射條件。
1) 確認必要工具
# Debian/Ubuntu
sudo apt-get update
sudo apt-get install -y uidmap
# RHEL/CentOS/Fedora(視發行版套件名稱可能不同)
sudo dnf install -y uidmap
2) 確認 subuid/subgid 至少 65536
whoami
id -u
# 至少要有 65536 筆 subordinate id
grep ^$(whoami): /etc/subuid
grep ^$(whoami): /etc/subgid
如果沒有,請補上(以下示意,請依你的環境規劃範圍):
# 例:給目前使用者一段 65536 的範圍
# 實際起始值請避免與其他使用者衝突
echo "$(whoami):231072:65536" | sudo tee -a /etc/subuid
echo "$(whoami):231072:65536" | sudo tee -a /etc/subgid
🚀 Rootless 安裝與啟動(建議 systemd user 模式)
情境 A:你已用套件安裝 Docker(最常見)
# 以「非 root 使用者」執行
dockerd-rootless-setuptool.sh install
接著你會得到類似提示:建立 user systemd 服務、建立 rootless context、以及可能需要設定 DOCKER_HOST。
啟動/設定開機自動啟動
systemctl --user start docker
systemctl --user enable docker
# 讓使用者在未登入時也能啟動 user service
sudo loginctl enable-linger $(whoami)
確認目前 Docker context
docker context ls
docker context use rootless
docker info | head
⚠️ Rootless 常見限制與對策(你一定會踩到的)
1) 需要綁定 80/443 這類「<1024」port?
Rootless 預設無法直接綁定特權 port。常見做法有兩個:
做法 A:給 rootlesskit 綁定低 port 的能力(較常用)
sudo setcap cap_net_bind_service=ep $(which rootlesskit)
systemctl --user restart docker
做法 B:調整系統允許非特權 port 起點
# 允許非 root 綁定所有低 port(影響面較大,請評估)
echo "net.ipv4.ip_unprivileged_port_start=0" | sudo tee /etc/sysctl.d/99-rootless.conf
sudo sysctl --system
2) 為什麼 docker run --memory/--cpus 沒有效?
Rootless 的資源限制通常需要 cgroup v2 + systemd 才完整支援;若不滿足條件,Rootless 可能會忽略部分 cgroup 相關參數。
你可以先檢查:
docker info | egrep -i "Cgroup|Driver"
如果你要把更多控制器委派給 user slice(示意):
sudo mkdir -p /etc/systemd/system/user@.service.d
cat << 'EOF' | sudo tee /etc/systemd/system/user@.service.d/delegate.conf
[Service]
Delegate=cpu cpuset io memory pids
EOF
sudo systemctl daemon-reload
🔎 鏡像安全掃描:Trivy 與 Docker Scout(兩套都會用到)
為什麼不只用一套?
- Trivy:速度快、在 CI 很常見、輸出格式完整(含 SARIF / SPDX / CycloneDX 等)
- Docker Scout:和 Docker 生態整合很好,
quickview可以快速看風險,cves可輸出 SARIF/Markdown 報告
✅ Trivy:最常用的三種掃描方式
1) 直接掃描鏡像
trivy image python:3.4-alpine
2) 只看 HIGH/CRITICAL(縮小噪音)
trivy image --severity HIGH,CRITICAL alpine:3.15
3) 忽略「目前沒有修補版本」的項目(更接近可落地修復清單)
trivy image --ignore-unfixed alpine:3.15
CI 掛閘建議(有問題直接 fail)
# 有掃到安全問題就回傳 exit code 1
trivy image --severity HIGH,CRITICAL --exit-code 1 your-image:tag
輸出報告(示意:SARIF 給 GitHub/GitLab 安全報表)
trivy image --format sarif -o trivy.sarif your-image:tag
✅ Docker Scout:快速總覽 + CVE 報告
1) quickview:一眼看風險與 base image 建議
docker scout quickview golang:1.19.4
# 或縮寫
docker scout qv
2) cves:列出 CVE(可分 severity、可輸出報告)
docker scout cves alpine
docker scout cves --only-severity critical,high your-image:tag
輸出 SARIF(方便丟進 CI 安全檢視)
docker scout cves --format sarif --output scout.sarif.json your-image:tag
輸出 Markdown(適合貼到 MR/PR 討論)
docker scout cves --format markdown your-image:tag
🧩 建議落地流程(你可以直接照這套跑)
- 開發/測試主機:Rootless Docker(先把 daemon 風險壓低)
- Build:多階段建置 + 最小化 base image(先減少套件數)
- Scan(本機):Trivy 先過一輪(HIGH/CRITICAL + ignore-unfixed)
- Scan(CI):Trivy 掛閘 + Docker Scout 輸出報告(SARIF/Markdown)
- Remediate:優先處理「可修補(fixable)」與「你真的有用到的套件」
- Release:推 registry + 記錄掃描結果(留存)
✅ 出貨前檢查清單(超精簡版)
- Rootless:daemon/containers 以非 root 身分運作
- 容器內:預設非 root user(不要全都跑 root)
- 鏡像:已掃描(HIGH/CRITICAL),CI 有 gate
- 報告:SARIF / Markdown 可追溯
- 修補:至少把可修補的 critical/high 壓到可接受
💬 留言交流
你目前的環境是 Debian/Ubuntu 還是 RHEL/CentOS?Rootless 你遇到最多的是「低 port」還是「cgroup 限制」?
也歡迎貼上你的 docker info 關鍵段落,我可以直接幫你判斷該怎麼調。
沒有留言: