爲什麼你需要更小巧的容器?

這篇文章出人意料地登上了黑客新聞的頭版,並在那裏引發了一場富有成效的討論。我將試着總結一下主要的要點:

以下是原文。

我最近在破解容器時注意到,Docker 開始在構建輸出中突出 Docker 掃描命令。我已經忽略它的存在有一段時間了,所以是時候嘗試一下了。

掃描官方 Python 鏡像

Docker 掃描命令使用一個第三方工具,稱爲 Snyk Container。顯然,這是某種漏洞掃描器。所以,我決定,主要是爲了好玩,掃描我的一個鏡像。這是一件非常基本的事情:

# latest stable at the time
FROM python:3.9

RUN pip install Flask

COPY server.py server.py

ENV FLASK_APP=server.py
ENV FLASK_RUN_PORT=5000
ENV FLASK_RUN_HOST=0.0.0.0

EXPOSE 5000

CMD ["flask""run"]

我運行 docker build -t python-flask,然後容器掃描 python-flask。令我非常驚訝的是,產生大量的輸出!下面是一段摘錄:

Testing python-flask...

✗ Low severity vulnerability found in unbound/libunbound8
  Description: Improper Input Validation
  Info: https://snyk.io/vuln/SNYK-DEBIAN10-UNBOUND-534899
  Introduced through: mysql-defaults/default-libmysqlclient-dev@1.0.5
  From: mysql-defaults/default-libmysqlclient-dev@1.0.5 > mariadb-10.3/libmariadb-dev-compat@1:10.3.27-0+deb10u1 > mariadb-10.3/libmariadb-dev@1:10.3.27-0+deb10u1 > gnutls28/libgnutls28-dev@3.6.7-4+deb10u6 > gnutls28/libgnutls-dane0@3.6.7-4+deb10u6 > unbound/libunbound8@1.9.0-2+deb10u2

✗ Low severity vulnerability found in tiff/libtiff5
  Description: Out-of-Bounds
  Info: https://snyk.io/vuln/SNYK-DEBIAN10-TIFF-1079067
  Introduced through: imagemagick@8:6.9.10.23+dfsg-2.1+deb10u1, imagemagick/libmagickcore-dev@8:6.9.10.23+dfsg-2.1+deb10u1
  From: imagemagick@8:6.9.10.23+dfsg-2.1+deb10u1 > imagemagick/imagemagick-6.q16@8:6.9.10.23+dfsg-2.1+deb10u1 > imagemagick/libmagickcore-6.q16-6@8:6.9.10.23+dfsg-2.1+deb10u1 > tiff/libtiff5@4.1.0+git191117-2~deb10u2
  From: imagemagick/libmagickcore-dev@8:6.9.10.23+dfsg-2.1+deb10u1 > imagemagick/libmagickcore-6.q16-dev@8:6.9.10.23+dfsg-2.1+deb10u1 > tiff/libtiff-dev@4.1.0+git191117-2~deb10u2 > tiff/libtiff5@4.1.0+git191117-2~deb10u2
  From: imagemagick/libmagickcore-dev@8:6.9.10.23+dfsg-2.1+deb10u1 > imagemagick/libmagickcore-6.q16-dev@8:6.9.10.23+dfsg-2.1+deb10u1 > tiff/libtiff-dev@4.1.0+git191117-2~deb10u2 > tiff/libtiffxx5@4.1.0+git191117-2~deb10u2 > tiff/libtiff5@4.1.0+git191117-2~deb10u2
  and 3 more...

...

✗ High severity vulnerability found in gcc-8
  Description: Insufficient Entropy
  Info: https://snyk.io/vuln/SNYK-DEBIAN10-GCC8-469413
  Introduced through: gcc-defaults/g++@4:8.3.0-1, libtool@2.4.6-9, imagemagick@8:6.9.10.23+dfsg-2.1+deb10u1, meta-common-packages@meta
  From: gcc-defaults/g++@4:8.3.0-1 > gcc-8@8.3.0-6
  From: libtool@2.4.6-9 > gcc-8@8.3.0-6
  From: gcc-defaults/g++@4:8.3.0-1 > gcc-8/g++-8@8.3.0-6 > gcc-8@8.3.0-6
  and 23 more...

✗ High severity vulnerability found in djvulibre/libdjvulibre21
  Description: NULL Pointer Dereference
  Info: https://snyk.io/vuln/SNYK-DEBIAN10-DJVULIBRE-481572
  Introduced through: imagemagick/libmagickcore-dev@8:6.9.10.23+dfsg-2.1+deb10u1
  From: imagemagick/libmagickcore-dev@8:6.9.10.23+dfsg-2.1+deb10u1 > imagemagick/libmagickcore-6.q16-dev@8:6.9.10.23+dfsg-2.1+deb10u1 > djvulibre/libdjvulibre-dev@3.5.27.1-10 > djvulibre/libdjvulibre21@3.5.27.1-10
  From: imagemagick/libmagickcore-dev@8:6.9.10.23+dfsg-2.1+deb10u1 > imagemagick/libmagickcore-6.q16-dev@8:6.9.10.23+dfsg-2.1+deb10u1 > imagemagick/libmagickcore-6.q16-6-extra@8:6.9.10.23+dfsg-2.1+deb10u1 > djvulibre/libdjvulibre21@3.5.27.1-10
  From: imagemagick/libmagickcore-dev@8:6.9.10.23+dfsg-2.1+deb10u1 > imagemagick/libmagickcore-6.q16-dev@8:6.9.10.23+dfsg-2.1+deb10u1 > djvulibre/libdjvulibre-dev@3.5.27.1-10
  and 1 more...

✗ High severity vulnerability found in bluez/libbluetooth3
  Description: Double Free
  Info: https://snyk.io/vuln/SNYK-DEBIAN10-BLUEZ-1018718
  Introduced through: bluez/libbluetooth-dev@5.50-1.2~deb10u1
  From: bluez/libbluetooth-dev@5.50-1.2~deb10u1 > bluez/libbluetooth3@5.50-1.2~deb10u1
  From: bluez/libbluetooth-dev@5.50-1.2~deb10u1



Package manager:   deb
Project name:      docker-image|python-flask
Docker image:      python-flask
Platform:          linux/amd64

Tested 431 dependencies for known vulnerabilities, found 358 vulnerabilities.

For more free scans that keep your images secure, sign up to Snyk at https://dockr.ly/3ePqVcp

共發現漏洞 358 個,其中高級別 54 個,中級別 48 個。

仔細查看掃描報告後,我發現的大部分漏洞可能與 Debian 有關(參見信息:https://snyk.io/vuln/SNYK-DEBIAN10-… 稍高一點,報告中很多項目都有)。

顯然,python:3.9 鏡像是基於成熟的 Debian 10 發行版。

114MB 的潛在安全漏洞

老實說,這是令人興奮的!我知道容器越厚,潛在的攻擊面就越高。但無論如何,我沒想到會有這麼大的規模。

好的,讓我們試着把鏡像瘦身……

FROM python:3.9-slim

RUN pip install Flask

COPY server.py server.py

ENV FLASK_APP=server.py
ENV FLASK_RUN_PORT=5000
ENV FLASK_RUN_HOST=0.0.0.0

EXPOSE 5000

CMD ["flask""run"]

掃描 python:3.9-slim 的鏡像給了我更好的結果:

Package manager:   deb
Project name:      docker-image|python-flask-slim
Docker image:      python-flask-slim
Platform:          linux/amd64

Tested 94 dependencies for known vulnerabilities, found 69 vulnerabilities.

共發現 69 個漏洞,其中高級別 14 個,中級別 8 個。

基礎鏡像每兆字節有一個漏洞……

我們能做得更好嗎?讓我們嘗試 python: 3.9-alpine:

FROM python:3.9-alpine

RUN pip install Flask

COPY server.py server.py

ENV FLASK_APP=server.py
ENV FLASK_RUN_PORT=5000
ENV FLASK_RUN_HOST=0.0.0.0

EXPOSE 5000

CMD ["flask""run"]

終於,0 已知的漏洞!

Package manager:   apk
Project name:      docker-image|python-flask-alpine
Docker image:      python-flask-alpine
Platform:          linux/amd64

✓ Tested 37 dependencies for known issues, no vulnerable paths found.

5.6 MB Alpine!

掃描無發佈的 Python 鏡像

另一個可能解決膨脹容器問題的方案是谷歌所謂的 “非發行版”Docker 鏡像。項目描述說它是 “語言聚焦 Docker 鏡像,減去操作系統”。儘管這在 Python 的情況下很難實現,因爲它的標準庫依賴於一些高級操作系統功能。

我花了一段時間纔想出一個可以工作的非發行版 Python 鏡像。大多數示例都展示瞭如何使用一些簡單的腳本。然而,安裝 Flask(或任何其他依賴項)比我預期的要困難得多。由於 gcr,Python 的無發行版容器需要多階段的構建過程。gcr.io/distroless/python3 鏡像既沒有 PIP,也沒有 easy_install。首先,我試圖利用構建鏡像中的虛擬環境,然後將其複製到運行時鏡像中,並修改 PATH 變量。但它並沒有很好地工作,因爲基本的非發行版鏡像在文件系統佈局上做了一些自以爲是的佈局:

預料之中的是,Linux distr 仍然存在,但是它比 debian 還要薄

所以,我最終得到了以下 Dockerfile,允許我在非發行版的 Python 鏡像中安裝 Flask:

# Build image
FROM python:3.7-slim AS build-env

RUN python -m pip install Flask

# Runtime image
FROM gcr.io/distroless/python3

COPY --from=build-env /usr/local/bin/flask /usr/local/bin/flask
COPY --from=build-env /usr/local/lib/python3.7/site-packages /usr/local/lib/python3.7/site-packages

WORKDIR /app

COPY server.py server.py

# Important line!
ENV PYTHONPATH=/usr/local/lib/python3.7/site-packages

ENV FLASK_APP=server.py
ENV FLASK_RUN_PORT=5000
ENV FLASK_RUN_HOST=0.0.0.0

EXPOSE 5000

CMD ["/usr/local/bin/flask""run"]

掃描它與 Docker 掃描輸出以下結果:

Package manager:   deb
Project name:      docker-image|python-flask-distroless
Docker image:      python-flask-distroless
Platform:          linux/amd64

Tested 25 dependencies for known vulnerabilities, found 37 vulnerabilities.

所以,只有 37 個漏洞:6 個嚴重程度高,8 箇中等。聽起來好像比原始的 python:3.9 鏡像減少了 90%!它甚至比 python:3.9-slim 中的漏洞更少。

因此,我們的基於 Alpine 的 Python 鏡像是一個贏家!

掃描 Go 鏡像

我喜歡完全從零開始構建容器鏡像的想法,避免將任何 distr 內容放入其中。但爲此,你需要一種對靜態構建有深刻支持的語言,例如 Go:

FROM scratch

COPY hello /
CMD ["/hello"]

得出以下結果…… 沒錯,這就是它!

Testing go-scratch...

Package manager:   linux
Project name:      docker-image|go-scratch
Docker image:      go-scratch
Platform:          linux/amd64

✓ Tested go-scratch for known vulnerabilities, no vulnerable paths found.

沒有 distr 並不意味着沒有漏洞。但它確實降低了攻擊的可能性。

相反的結論

根據我的經驗,膨脹的鏡像通常是使用默認的 From bloated_base,或者因爲人們爲了將來的調試 / 故障排除故意將額外的工具放入鏡像的結果。

第一種可能是 Docker 過去大規模營銷活動的結果。爲了普及容器,你需要給人們一些看起來很酷和方便的東西。而且能夠在一秒鐘內從你的開發機器上啓動一個成熟的 Linux distr(某種程度上),即使在今天看起來也很酷。一些本地的修補和 / 或實驗從 docker run -it ubuntu 中獲益良多。然而,我希望它從來沒有被用於生產。但是從一個成熟的 Debian,CentOS,或者 Ubuntu 開始,Dockerfile 的例子實在是太多了,至少要避免將其中一些滲透到我們的生產環境中。

第二個原因看起來更合理。但我有一種感覺,這只是第一眼看到的感覺。理想情況下,應該有另一種方法來調試你的容器化服務。這種方法不需要將所有潛在需要的工具打包到一個容器中。最近添加的 kubectl 調試功能很好地證明了這一假設。它允許將臨時容器注入運行中的 Pod 中,這樣的容器可以擁有調試所需的所有東西。

更小的容器不僅僅意味着更快的構建和更小的磁盤和網絡利用率,它們還意味着更安全。

原文鏈接:https://iximiuz.com/en/posts/thick-container-vulnerabilities/


本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/3qfuygLophrpKSm4VuEj0g