Node.js 應用程序的 Docker 安全優秀實踐
在構建、共享和運行 Docker容器安全應用程序時,您需要考慮一些Docker 安全最佳實踐。Docker 是一個開源平臺,用于構建、共享和運行您的容器化應用程序。您可以輕松構建包含應用程序的 Docker 映像,在團隊內部或團隊外部共享它們,并且只需一個命令即可運行您的應用程序。看起來很容易,對吧?然而,確實如此。
您可能已經知道 Docker 是什么以及它是如何工作的。因此,我們不會詳細介紹它。本博客將介紹使用 Docker 平臺時需要考慮的12 大 Docker 安全最佳實踐。
為什么需要保護 Dockerfile、容器?
容器化因其應用程序可以在任何地方部署的靈活性而風靡全球。但是,這也引入了一些安全漏洞。Docker 和 Docker 容器使構建、共享和部署應用程序變得非常容易,因此在部署后很難發現、檢測、報告和修復安全問題。通過向左移動安全性,可以防止和最小化大部分開銷。因此,保護從 Dockerfile 到 Docker 容器的所有內容以確保Docker 容器安全性至關重要。
12 大 Docker 安全最佳實踐
從一開始就可以通過各種專業來提高Docker 容器安全性,即從編寫 Dockerfile 到運行 Docker 容器。讓我們繼續看看可以將 Docker 容器安全性落實到位的 12 大 Docker 安全最佳實踐。
1. 使 Docker 主機和 Docker 引擎與 Docker 映像一起保持最新
Docker 容器在主機上可用的 Docker 引擎上運行。這些主機可以是 Linux/Mac 或 Windows。Docker 引擎可以是可用版本之一。 使用最新的穩定版本至關重要,它更新了以前版本中的已知問題。這同樣適用于主機操作系統。
例如,截至 2021 年 12 月 27 日,如果您使用 Ubuntu 作為主機操作系統,那么您可以使用 Ubuntu 20.04 LTS 而不是 Ubuntu 16.04 LTS,對于 Docker 引擎,您可以使用 20.10.11。查找Docker 發行說明以獲取更多信息,并檢查 Docker 支持的操作系統平臺。
安裝更新或補丁非常重要,因為每個補丁都可以解決CVE-2021-41092等漏洞。這個特定的補丁修復了用于從 CLI 登錄 docker 注冊表的憑據被發送到“registry-1.docker.io”而不是預期的私有注冊表的錯誤;這通常是由于配置錯誤的配置文件(通常是 `~/.docker/config.json`)列出了 `credsStore` 或 `credHelpers.
請參考以下截圖了解 Ubuntu OS 的發布周期。
2. 避免在 Dockerfile 指令中存儲機密數據
Dockerfile 包含用于創建 Docker 映像的指令。COPY、RUN、ADD、CMD、ENTRYPOINT 等。這些是一些可能是 Dockerfile 一部分的命令指令。我們還可以使用 ENV 和 ARGS 在運行時或構建時設置變量,具體取決于要求。您可以使用 ENV 或 ARGS 指令在 Docker 容器中使用環境變量。在設置環境變量時,您應該注意永遠不要將機密、憑據、密碼等分配給 Dockerfile 中的變量,也不應該在任何命令中進行硬編碼。將此視為 Dockerfile 安全最佳實踐之一,因為忽略它可能會導致潛在的安全威脅,并且可能會花費您很多錢。
例如,如果您在 Dockerfile 中硬編碼數據庫的密碼或連接詳細信息,將它們分配給環境變量,然后將 Dockerfile 上傳到公共存儲庫,則任何有權訪問存儲庫的人都可以獲得這些憑據并可以訪問詳細信息或連接到數據庫。
FROM mysql:5.7 ENV DATABASE_USERNAME=admin # < - Setting username is acceptable ENV DATABASE_PASSWORD=mypassword@!@#$ # < - Avoid setting password at any cost
3. 避免使用不受信任的鏡像注冊表
鏡像注冊表是存儲 Docker 鏡像的地方。它可以是私有的或公共的。Docker Hub 是 Docker 官方的基于云的 Docker 鏡像注冊表,它是安裝時的默認注冊表。如果您未配置任何注冊表,則將從該公共存儲庫中提取圖像。
當您從任何公共注冊表中提取 Docker 鏡像時,請注意來源,因為您可能不知道是誰構建了它們,它們是如何構建的,或者它們是否值得信賴。每當您從不受信任的發布者拉取鏡像時,請不要忘記驗證源注冊表和用于構建鏡像的 Dockerfile。此外,您的 Dockerfile 的基本映像,即 FROM 指令。
FROM # < - Verify the base image before you use it
4.提防遞歸復制
在為需要將文件從本地計算機復制到 Docker Image 的應用程序編寫 Dockerfile 時,您應該注意使用 COPY 指令復制的內容。您的本地計算機上可能有可能包含機密數據或機密的文件。因此,如果這些文件被復制到 Docker 映像中,任何有權訪問容器的人都可以從容器中獲取這些文件。因此,僅復制容器中需要的文件而不是復制所有內容非常重要,如下面的說明所示,以提高 Docker 容器安全性。
你可以試一試。dockerignor。它可以幫助排除與模式匹配的文件和目錄,并避免使用 ADD 或 COPY 將大型或敏感文件不必要地發送到圖像。
例如,在以下 COPY 指令中,當前位置的所有文件都將復制到 Docker 映像中。因此,您應該始終避免“復制”。./ ”,并且應該在 COPY 指令中明確指定文件名為“ COPY package.json ./ ”
FROM node:12.18.4-alpine WORKDIR /app ENV PATH /app/node_modules/.bin:$PATH COPY . ./ # < - Avoid such kind of COPY instruction
5. 開發過程中掃描圖像
Docker 鏡像是從 Dockerfiles 構建的,Dockerfiles 包含使用基礎鏡像、安裝包、啟動應用程序等的說明。Dockerfile 也可能包含錯誤硬編碼的憑據。那么,如果您使用的基礎鏡像存在一些漏洞,并且在 Dockerfile 中硬編碼的憑據從使用該 Dockerfile 構建的鏡像創建的容器中泄露,該怎么辦?
掃描鏡像是識別 Docker 鏡像中已知安全漏洞的過程,以便您可以在將它們推送到 Docker Hub 或任何其他注冊表之前修復它們。
您現在可以直接從 Docker Desktop CLI 運行 Snyk 漏洞掃描,因為 Snyk 和 Docker 已經合作。
例如,您可以通過提供用于創建映像的 Dockerfile 來獲取有關 Docker 映像的詳細報告。
docker scan --file PATH_TO_DOCKERFILE DOCKER_IMAGE
6. 使用固定標簽實現不變性
在 Docker 中,圖像上有標簽。Docker 鏡像最常見和默認的標簽是“latest”。因此,如果您沒有為圖像分配標簽,則默認情況下它將具有“最新”標簽。可以發布多個具有相同標簽的鏡像,即 Docker 鏡像標簽不是不可變的。因此,非常重要的是——
更喜歡為您的圖像使用更具體的標簽,以便您每次都能獲得相同的圖像。
更喜歡在您的私人存儲庫中保留圖像的副本。
使用 Docker 內容信任 (DCT) 將數字簽名用于客戶端或運行時驗證特定圖像標簽的完整性和發布者。訪問官方文檔以了解更多信息。
例如,讓我們說,
- Dev1拉取myimage:latest imag,在他/她的電腦上運行1.1版本的應用,發現應用運行流暢。
- 稍后,Dev2 拉取相同的圖像myimage:latest并在他們的計算機上運行該應用程序,并發現該應用程序出現了問題。在這里,您確定它們都在運行相同版本的應用程序嗎?
- 答案是否定的,因為在 Dev2 拉取鏡像myimage:latest 之前, Dev3 進行了更改并推送了同名myimage:latest 應用的不穩定版本 1.2。
- 現在,當他們部署鏡像myimage:latest 時, 它將指向應用程序的不穩定版本 1.2,然后這會破壞生產環境。
7. Lint Dockerfile
市場上有各種 Dockerfile linter 可用于確保 Dockerfile 遵循Dockerfile 安全最佳實踐。如果生成警告,Linter 可以幫助您停止構建過程;他們遍歷您的 Dockerfile 并在 Dockerfile 不遵循最佳實踐的情況下發出警告。您可以利用Hadolint,這是一個用于驗證內聯 bash 和 linting Dockerfile 的開源項目。
8.限制容器資源
默認情況下,在主機上運行的 Docker 容器可以利用所有的 RAM 和 CPU。在 Docker 容器遭到入侵的情況下,攻擊者可能會嘗試使用主機資源來執行惡意活動。此外,如果特定容器開始利用主機上的所有資源,則駐留在同一位置的其他容器可能會由于資源不可用而受到影響。為避免這種情況,建議對 Docker 容器設置資源限制,以使它們使用的資源不會超過分配給它們的資源,并有助于提供 Docker 容器安全性。
例如, 如果宿主機有 1 個 CPU,下面的第 1 條命令可以保證容器每秒最多使用 50% 的 CPU,第 2 條命令可以將容器的內存使用限制為 1 GB。
CPU 限制
docker run -it --cpus=".5" ubuntu /bin/bash
內存限制
docker run -it --memory="1g" ubuntu /bin/bash
9. 不要暴露 Docker Daemon Socket
Docker 與名為 /var/run/docker.sock 的 UNIX 域套接字通信,這是Docker API的主要入口點。如果任何人有權訪問 Docker 守護程序套接字,也可以獲得 root 訪問權限。因此,允許任何用戶寫入 /var/run/docker.sock 或將套接字暴露給容器對系統的其余部分來說是一個很大的 Docker 容器安全風險,因為這會給它提供 root 權限。因此,永遠不要在 Docker 容器內掛載 /var/run/docker.sock。
例如,永遠不要使用“-v /var/run/docker.sock:/var/run/docker.sock”之類的選項運行 docker run 命令,并將其視為 Docker 安全最佳實踐之一,可以幫助您保持系統保護。
10. 以非 root 用戶身份運行容器
根據 sysdig.com 的“ 2021 年容器安全和使用報告”,大多數鏡像都過于寬松,58% 的容器以 root 身份運行。這不被視為 Dockerfile 最佳實踐;應該避免這樣做,因為在極少數情況下您確實需要使用 root 用戶在容器中運行您的進程。為確保您不使用 root 用戶,請始終使用用戶名指定“USER”指令。
在 Docker 容器中使用非 root 用戶可確保減輕容器運行時中的潛在漏洞并實現 Docker 容器安全性。
例如,始終嘗試創建和使用非 root 用戶在容器中運行您的應用程序進程。你需要的非root用戶可能不存在;因此,您首先必須在使用它之前創建一個。
FROM alpine:3.12 RUN adduser -D non-root-user && chown -R non-root-user /myapp-data # < - Create a user USER non-root-user # < - use a non-root user
11. 保持 Docker 鏡像盡可能小
在整個 Dockerfile 構建過程中創建了許多工件,這些工件僅在構建期間是必需的。這些包是編譯或運行單元測試、臨時文件、機密等的依賴項所必需的。將這些工件保留在基礎映像中會增加 Docker 映像的大小,這可能會減慢下載時間并擴大攻擊面,因為更多的包是因此,加載是 Docker 支持多階段構建的原因之一。此功能允許您在構建過程中使用大量臨時映像,同時僅保留最新的映像和復制到其中的數據。
結果,您有兩個圖像:
- 圖 1:第一個圖像是一個大圖像,其中包含許多依賴項,您需要這些依賴項來創建應用程序和運行測試。
- 圖 2:在大小和庫數量方面非常小且輕量級的圖像,只有在生產中運行程序所需的工件副本。
通過這種方式,您可以采用多階段構建來構建您的 Docker 鏡像,這可以減少鏡像的大小并避免安裝不需要的庫,從而增加潛在安全風險的機會。
12. 使用最新的 Docker 鏡像
由于定期發現新的安全漏洞,保持最新的安全補丁是 Docker 安全最佳實踐。因此,使用經常更新的基礎鏡像并在它們之上構建自己的鏡像非常重要。沒有必要總是使用最新的版本,它可能包含重大更改,但您應該有一個版本控制策略。以下是您的基本圖像要考慮的幾點。
- 堅持使用更可能收到安全更新的穩定或長期支持版本。
- 在您的基礎映像版本達到其生命周期結束且不再接收更新之前,請準備好刪除舊版本并進行遷移。
- 定期重建你的鏡像并使用類似的技術從基本發行版中獲取最新的包
結論
我們都知道“預防勝于治療”,Docker 也是如此。不能簡單地忽視其安全性,因為這可能導致一場巨大的災難。我們現在知道為什么 Docker 容器安全性至關重要以及為什么必須到位。將安全性向左轉移對于改善 Docker 環境和減少管理開銷至關重要。
上面提到的前 12 條建議側重于 Dockerfile 安全最佳實踐和 Docker 容器安全最佳實踐,將幫助您保護 Docker 容器和 Docker 環境。
與經驗豐富的團隊一起保護您的 Docker 容器。