--- tags: image,security,docker --- # Container Image has a lot Vulnerabilities!! ## 緣起 > 以下內容整理自CNCF > My Container Image has 500 Vulnerabilities, Now What? - Matt Jarvis, Snyk > https://www.youtube.com/watch?v=1fO_xSnwDPg 最近在使用Trivy、Kubescabe等弱掃工具時,常發現K8S內的image一掃下來,Critical、High的弱點一大堆,很多都是屬於Library的弱點,image的版本也是latest了,根本也無從修復或更換image版本,在軟體開發流程中,到底要怎麼處理這種情形? ![](https://i.imgur.com/5ViyfI0.png) (圖1) mysql:latest的掃描結果 ## 回歸使用docker的初衷 使用docker取代VM開發就是因為 1. 更輕量:Docker Container僅包含應用程序和相關庫文件,而不像 VM 一樣需要運行完整的操作系統,因此它們比 VM 更輕量,並且更容易和快速部署、啟動和關閉。 2. 更快速:由於 Docker Container不需要運行完整的操作系統,因此啟動Container所需的時間比啟動 VM 快得多。 3. 更高效:由於 Docker Container共享主機的操作系統核心,因此它們比 VM 使用更少的系統資源,並且可以在同一台機器上運行多個Container。 4. 更易於管理:Docker Container使用 Dockerfile 定義,因此環境可以很容易地重現和分享。此外,Docker 提供了一個方便的管理界面,可以用來啟動、停止和管理Container。 Container不是實體主機,對於Container的 Vulnerabilities mitigation有不同的做法,首先了解你的application之於image的關係,是如下圖從dockfile一層一層加上去的 ![](https://i.imgur.com/62NvbHH.png) (圖2) Container是分層建構的 而Base Image也有可能是從Parent Image繼承而來的,所以**漏洞最小化的策略取決於弱掃工具怎麼掃進Image的** ## Image的繼承關係 ![](https://i.imgur.com/H1uniMt.png) (圖3)Image的進化類比圖 以Nginx image為例,是從debian:buster-slim建置而來的 ![](https://i.imgur.com/sk4tZvP.png) (圖4) 而debian是從scratch(空白的image,不包含任何操作系統或其他文件),透過指令將一個已壓縮的 tarball 檔案 rootfs.tar.xz 添加到 Docker Image中。這個 tarball 包含了一個完整的根文件系統(root file system),包括所有需要的庫文件和執行應用程序所需的其他文件。當 Docker 容器運行時,它會使用這個根文件系統來運行應用程序。 ![](https://i.imgur.com/oNmWLkz.png) (圖5) 而這個tarball 檔案 rootfs.tar.xz來自於Debuerreotype,Debuerreotype 提供了一些工具和腳本,用於快速生成簡單、最小化的 Debian Docker image ![](https://i.imgur.com/6SXfUAd.png) (圖6) 為了維護與開發的方便,千萬不要想要從頭修起(弱點),這樣只是沒完沒了 ![](https://i.imgur.com/UVQRRn7.png) (圖7) 所以如何選擇合適的Image TAG是一個重要且不簡單的問題!什麼都有的image通常也代表包含了很多弱點,但slim也不一定好,因為你需要安裝很多dependencies。 ![](https://i.imgur.com/NcWeehp.png) (圖8)以Ruby為例 **那到底要怎麼做???** ## Best Practices ### Base Image 最佳解就是使用 **Multi-stage builds** ! 使用 Multi-stage builds 可以增加 Docker image的安全性和可靠性,因為它可以在不同的階段中創建、編譯和打包應用程序,並將最終的可執行文件從前面的階段中提取,以減少image大小和提高安全性。 範例: ``` # 第一個階段:基於 Python 官方映像創建 build 階段 FROM python:3.9-slim-buster AS build RUN apt-get update && \ apt-get install -y build-essential && \ apt-get clean WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY . . RUN python setup.py install # 第二個階段:基於輕量級映像創建運行階段 FROM python:3.9-slim-buster AS runtime WORKDIR /app COPY --from=build /usr/local/lib/python3.9/site-packages/ /usr/local/lib/python3.9/site-packages/ COPY --from=build /app /app EXPOSE 8000 CMD ["python", "app.py"] ``` 在這個 Dockerfile 中,有兩個階段:build 階段和 runtime 階段。第一個階段使用官方的 Python 映像,安裝編譯工具和其他必要的Library文件,然後從 requirements.txt 安裝應用程序的依賴關係,最後使用setup.py安裝應用程序本身。這個階段創建一個中間映像,其中包含完整的 Python 環境和應用程序。 第二個階段使用輕量級的 Python 映像,並從第一個階段提取應用程序,將其複製到新的runtime image中,最後將端口暴露並運行應用程序。 這種方式的好處是可以減少映像大小,因為第二個階段只包含運行應用程序所需的最小必需品,並且可以減少潛在的安全風險,因為只有必要的文件被複製到runtime image中。這種方法也可以使開發人員更容易維護和更新應用程序,因為它們可以使用單一的 Dockerfile 來定義多個階段和任意數量的image。 ### Added Layers 與Base Image相同原則:Add透過上游maintainer更新過後的package ### Code dependencies、Code 透過弱掃工具的建議減少dependencies弱點(移除沒用到的) ![](https://i.imgur.com/zaWSxHE.png) ## 總結 Comtainer不可能沒有弱點,但需要對弱點修補排出優先等級(例如CVSS的Exploitability可利用性或Impact影響性) ![](https://i.imgur.com/u5VNlke.png) 能做的事就是遵循以下這三件事 ![](https://i.imgur.com/QRf5Lsb.png) ### Using base images * Standing on the shoulder of software giants (ubuntu、debian、alpine、python、ruby、node...) ### Distinct responsibilities * 建立屬於自己組織的Harden、config過的base image,當作其他的image的baseline * Rebuild and set a new baseline often! ![](https://i.imgur.com/YtkVCtv.png) ![](https://i.imgur.com/AIGNMMH.png) ![](https://i.imgur.com/p0rrGzc.png)