歡迎光臨
每天分享高質量文章

10 個 Docker 映象安全最佳實踐

 

《Docker 映象安全最佳實踐速查表[1]》列舉了 10 個訣竅和指南,確保更安全和更高質量的 Docker 映象處理。此外,還可以檢視有關 Docker 安全的新報告《Docker 安全要趁早[2]》。

 

 

1. 選用最小化基礎映象

 

人們編寫專案的 Dockerfile 時,經常使用一個通用的 Docker 容器映象作為基礎,例如 From Node 。 Node 映象實際上是以一個完整安裝的 Debian Stretch 發行版為基礎,這意味著構建得到的專案容器映象將包含一個完整的作業系統。如果該專案不需要任何通用的系統庫或者系統工具應用,最好不要使用完整的作業系統作為基礎映象。
Synx 釋出的《開源安全報告-2019[3]》指出,Docker Hub 上流行的很多容器映象,都用到了包含大量已知安全漏洞的基礎映象。例如,執行 docker pull node ,下載並使用 Node 映象,相當於在應用中引入了一個包含 580 個已知漏洞的作業系統。
從上圖(摘自《開源安全報告-2019》)可知,Docker Hub 上最流行的 10 個映象都包含已知的安全漏洞。選用最小化基礎映象,即只包含專案確實需要的系統工具和庫的映象,就能最小化系統的攻擊面,確保所用作業系統是安全的。
瞭解更多 Docker 映象安全的知識[4]。
2. 設定最小許可權的 USER

 

如果 Dockerfile 中沒有指定 USER ,Docker 預設將會以超級使用者 root 的身份執行容器,容器所屬的名稱空間(namespace)因此對映為 root 所有,這意味著容器有可能獲取 Docker 宿主機的超級管理許可權。不僅如此,以 root 使用者身份執行容器,還擴大了攻擊面,如果容器應用中存在安全漏洞,很容易造成許可權提升。
在實踐中,一般不需要容器擁有 root 許可權。為了儘量降低安全威脅,建立專門的使用者和使用者組,在 Dockerfile 中使用 USER 指定使用者,確保以最小許可權的使用者身份執行容器應用。
如果基礎映象中不包含專門的使用者,那麼就在 Dockerfile 中直接建立。下麵就是一個這樣的例子,它用到的基礎映象是 Ubuntu :

 

  1. FROM ubuntu
  2. RUN mkdir /app
  3. RUN groupadd -r lirantal && useradd -r -s /bin/false -g lirantal lirantal
  4. WORKDIR /app
  5. COPY . /app
  6. RUN chown -R lirantal:lirantal /app
  7. USER lirantal
  8. CMD node index.js
在上例中:
  • 建立一個系統使用者( -r 選項),沒有密碼、沒有主目錄且沒有 shell;

  • 將該使用者新增到前面(使用 groupadd )建立的使用者組;

  • 最後一段引數設定了使用者名稱以及所屬的使用者組。

 

如果你使用的是 Node.js 和 alpine 映象,已經包含了一個使用者 node,直接使用即可:
  1. FROM node:10-alpine
  2. RUN mkdir /app
  3. COPY . /app
  4. RUN chown -R node:node /app
  5. USER node
  6. CMD [“node”, index.js”]
Node.js 應用開發者請參閱官方的Docker 和 Node.js 最佳實踐[5]。
3. 簽名和校驗映象,防範中間人攻擊

 

Docker 映象的認證頗具挑戰性。在生產環境使用這些映象執行我們的程式碼,意味著我們對這些映象的極大信任。因此,必須保證我們拉取的容器映象確實是釋出者釋出的映象,沒有被任何人篡改。發生映象篡改,有可能是因為 Docker 客戶端和映象中心之間的中間人攻擊,或者是釋出者的身份被人盜用併在映象中心釋出了惡意映象。
校驗 Docker 映象
Docker 預設直接拉取容器映象,不會校驗映象的來源和釋出者。這意味著你有可能使用來源和釋出者不明的任何映象。
無論採用何種策略,最佳實踐都是先校驗容器映象,透過驗證後再拉取映象。為了體驗映象校驗功能,執行下列暫時開啟 Docker Content Trust 的命令:
  1. export DOCKER_CONTENT_TRUST=1
現在,嘗試拉取一個沒有簽名的容器映象——請求會被拒絕,不會拉取映象。
簽名 Docker 映象
優先使用 Docker 認證的映象,即這些映象來自經過 Docker Hub 檢查和選擇的可信提供者。不要使用無法檢驗來源和釋出者的容器映象。
Docker 支援映象簽名,提供了額外一層的保護。使用 Docker Notary 簽名映象。Notary 會檢驗映象的簽名,如果簽名不合法,它會阻止執行該映象。
如果開啟了 Docker Content Trust ,構建 Docker 映象的同時也會對映象簽名。如果是第一次簽名,Docker 會為當前使用者生成一個私鑰,儲存在 ~/docker/trust 。後續所有的映象都會使用這個私鑰簽名。
請參考Docker 官方檔案[6],瞭解簽名映象的詳細指令。
4. 找出、修正和監控開源漏洞

 

指定容器的基礎映象,同時也引入了該映象包含的作業系統及系統庫有可能存在的所有安全風險。
最好選用能夠正常執行應用程式碼的最小化映象,這有助於減少攻擊面,因為限制了可能的安全漏洞數量。不過,這麼做並沒有對映象進行安全審計,也不能防範將來發現的新漏洞。
因此,防範安全軟體漏洞的一種方法是使用像 Snyk 這樣的工具,持續掃描和監控 Docker 映象各層可能存在的漏洞。
使用下列命令掃描容器映象,檢查是否存在已知漏洞:
  1. # fetch the image to be tested so it exists locally
  2. $ docker pull node:10
  3. # scan the image with snyk
  4. $ snyk test --docker node:10 --file=path/to/Dockerfile
Snyk 能夠監控指定的容器映象,一旦有新發現的安全漏洞,通知使用者並給出修補建議:
  1. $ snyk monitor --docker node:10
根據 Snyk 使用者執行的映象掃描,我們發現大約 40% 的 Docker 映象包含已知漏洞,實際上彌補這些漏洞的新版本基礎映象已經有了。 Synx 提供了絕無僅有的修正建議功能,使用者可以根據建議採取行動,升級 Docker 映象。
Snyk 還發現在掃描的所有映象中,為了減少漏洞的數量,大約 20% 的映象需要重新構建。更多資訊請參閱《開源安全報告-2019[3]》。
5. 不要在容器映象中包含機密資訊

 

有時候,構建包含應用的容器映象時,需要用到一些機密資訊,例如從私有倉庫拉取程式碼所需的 SSH 私鑰,或者安全私有軟體包所需的令牌。如果 Dockerfile 中包含複製機密資訊的命令,構建映象時,這行命令對應的中間容器會被快取,導致機密資料也被快取,有可能造成機密資訊洩漏。因此,像令牌和金鑰這樣的機密資訊必須儲存在 Dockerfile 之外。
使用多階段構建
利用 Docker 的多階段構建功能,用一個中間映象層獲取和管理機密資訊,然後清除中間映象,這樣在應用映象構建階段不涉及敏感資料。如下麵例子所示,使用程式碼將機密資訊新增到中間層:
  1. FROM: ubuntu as intermediate
  2. WORKDIR /app
  3. COPY secret/key /tmp/
  4. RUN scp -i /tmp/key build@acme/files .
  5. FROM ubuntu
  6. WORKDIR /app
  7. COPY --from intermediate /app .
使用 Docker 的 secret 管理功能
使用 Docker 的 secret 管理功能(alpha 階段),載入敏感資訊檔案且不會快取這些資訊:
  1. # syntax = docker/dockerfile:1.0-experimental
  2. FROM alpine
  3. # shows secret from default secret location
  4. RUN --mount=type=secret,id=mysecret cat /run/secrets/mysecre
  5. # shows secret from custom secret location
  6. RUN --mount=type=secret,id=mysecret,dst=/foobar cat /foobar
想瞭解有關 Docker secret 的更多資訊,請訪問 Docker 官方站點[6]。
避免無意中複製機密資訊
往映象中複製檔案時,也要當心,避免無意中添加了機密資訊。例如,下麵的命令將整個構建背景關係檔案夾複製到 Docker 映象,有可能把敏感檔案也複製進去了:
  1. COPY . .
如果檔案夾中有敏感檔案,要麼先移除這些檔案,要麼將這些檔案包含在 .dockerignore 中,複製時會忽略這些檔案:
  1. private.key
  2. appsettings.json
6. 設定映象的標簽,保證映象的不可更改性

 

每個 Docker 映象可以有多個標簽(tag),代表該映象的不同變體。最常見的標簽是 latest ,表示這是該映象的最新版本。映象標簽是可更改的,也就是說映象的作者可以多次釋出相同標簽的映象。
因此,即使你的 Dockerfile 明確指定了使用的基礎映象及其標簽,這次映象構建和下次映象構建仍然可能用到了不同的基礎映象。解決這個問題,有多種辦法:
  • 優先選用最詳細的映象標簽。例如,映象有 :8、:8.0.1 和 :8.0.1-alpine 等標簽,選擇最後這個,因為它提供了最詳細的資訊。不要使用像 latest 這樣過於泛泛的標簽。

  • 記住,映象的釋出者有可能刪除映象的某個標簽。如果設定了所用映象的標簽,一旦這個標簽被刪除,映象構建會因為找不到基礎映象而失敗。為了避免這個問題,可以提前把該映象複製到私有映象中心或者公有映象中心的私人賬戶下麵。這麼做,保證了映象的不可更改性,同時也帶來了維護私有映象中心的負擔。

  • 使用比簽名更具體的 SHA256 取用指明要使用的映象,這能保證每次拉取都是相同內容的映象。這麼做也有風險,如果映象改變了,以前的 SHA256 取用(雜湊值)也不存在了。

 

7. 使用 COPY ,不要使用 ADD

 

譯者警告:這部分對 ADD 和 COPY 的描述,與 Docker 官方檔案並不吻合,譯者按照自己的理解修改了這部分內容。如果要瞭解作者原意,請閱讀英文原文[7]。
從宿主機複製檔案到容器映象中的 Docker 命令有兩個:COPY 和 ADD ,這兩個命令本質上很相似,但具體功能並不相同:
  • COPY – 將本地檔案或者目錄(遞迴)複製到容器映象中的標的目錄,複製來源和標的都必須明確指定。

  • ADD – 與 COPY 類似的功能,有兩個不同:(1)如果複製來源是本地壓縮檔案,ADD 將把該檔案解壓縮到標的目錄;(2)ADD 也可以將遠端 URL 指定的檔案下載到標的目錄。

為了避免可能導致的安全問題,請記住 COPY 和 ADD 的不同:
  • 使用 ADD 從遠端 URL 下載檔案,存在中間人攻擊的風險,檔案內容有可能因此被篡改。必須確保遠端 URL 必須是安全的 TLS 連結,校驗遠端 URL 的來源和身份。譯者註:實際上,官方檔案並不鼓勵使用 ADD 新增遠端檔案。

  • 如果複製的是本地壓縮檔案, ADD 自動將它解壓縮到標的目錄,這有可能觸發 zip 炸彈或者 zip 任意檔案改寫漏洞。

  • 相比較而言,使用 COPY 複製檔案或目錄,會建立一個快取的中間映象層,最佳化映象構建的速度。

 

8. 使用 LABEL 指定映象元資料

 

映象元資料有助於使用者更好地理解和使用該映象。最常見的元資料是 maintainer ,它說明瞭映象維護者的電郵地址和名字。使用 LABEL 命令新增映象的元資料:
  1. LABEL maintainer="me@acme.com"
除了映象的維護者資訊,新增其他你認為重要的元資料,包括提交物件的雜湊值、相關構建的連結、質量狀態(透過所有測試了嗎?)、原始碼連結、SECURITY.TXT 檔案的位置等。
SECURITY.TXT (RFC5785)[8] 檔案說明瞭映象維護者的安全披露政策。最好在映象元資料中加上 SECURITY.TXT 的連結,例如:
  1. LABEL securitytxt="https://www.example.com/.well-known/security.txt"
想瞭解映象元資料的更多資訊,請訪問 https://label-schema.org/rc1/ 。
譯者註:這個規範好像已經廢止了,請直接訪問 OCI 映象規範[9]。
9. 使用多階段構建小而安全的映象

 

使用 Dockerfile 構建應用容器映象時,會生成很多隻是構建時需要的映象層,包括編譯時所需的開發工具和庫,執行單元測試所需的依賴、臨時檔案、機密資訊等等。
如果保留這些映象層,不僅會增加映象的大小,影響映象下載速度,而且會因為安裝更多軟體包而面臨更大的攻擊危險。這對用到的映象也是成立的——需要使用一個專門構建應用的映象,但不會用它來執行應用程式碼。
Go 語言就是一個很好的例子。構建一個 Go 應用需要用到 Go 編譯器。編譯得到的 Go 應用能夠在任何作業系統上直接執行,沒有任何依賴,包括 scratch 映象。
Docker 因此提供了多階段構建的功能,允許在構建過程中使用多個臨時映象,只保留最後一個映象。這樣,使用者得到兩個映象:
  • 第一個映象——非常大的映象,包含了構建應用和執行測試所需的所有依賴;

  • 第二個映象——非常小的映象,只包含執行應用所需的極少數依賴。

10. 使用靜態分析工具

 

使用靜態分析工具,能夠避免常見的錯誤,建立工程師自動遵循的最佳實踐指南。
例如,hadolint 分析 Dockerfile 併列出不符合最佳實踐規則的地方。
在整合開發環境(IDE)中使用 hadolint 更好。例如,安裝 VS Code 的 hadolint 擴充套件後,編寫 Dockerfile 時,邊寫邊檢查,既快又好。
瞭解更多 Docker 映象安全的知識[10]。
把速查表打印出來,貼在某處,時刻提醒自己構建容器映象時應該遵循的最佳安全實踐!
相關連結:
  1. https://res.cloudinary.com/snyk/image/upload/v1551798390/Docker_Image_Security_Best_Practices_.pdf

  2. https://snyk.io/blog/shifting-docker-security-left/

  3. https://snyk.io/blog/top-ten-most-popular-docker-images-each-contain-at-least-30-vulnerabilities/

  4. https://snyk.io/container-vulnerability-management/

  5. https://github.com/nodejs/docker-node/blob/master/docs/BestPractices.md

  6. https://docs.docker.com/engine/security/trust/content_trust/

  7. https://snyk.io/blog/10-docker-image-security-best-practices/

  8. https://securitytxt.org/

  9. https://github.com/opencontainers/image-spec

  10. https://snyk.io/container-vulnerability-management/

     

原文連結:https://snyk.io/blog/10-docker-image-security-best-practices/
贊(0)

分享創造快樂