<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
本文介紹了 12 個優化 Docker 映象安全性的技巧。每個技巧都解釋了底層的攻擊載體,以及一個或多個緩解方法。這些技巧包括了避免洩露構建金鑰、以非 root 使用者身份執行,或如何確保使用最新的依賴和更新等。
當你是剛開始使用 Docker 的新手時,你很可能會建立不安全的 Docker 映象,使攻擊者很容易藉此接管容器,甚至可能接管整個主機,然後滲透到你公司的其他基礎設施中。
可以被濫用來接管你的系統的攻擊向量有很多,例如:
啟動的應用程式(在你 Dockerfile 的 ENTRYPOINT 中指定)以 root 使用者身份執行。這樣一來,一旦攻擊者利用了一個漏洞並獲得了 shell 許可權,他們就可以接管 Docker 守護程式所執行的主機。
你的映象是基於一個過時的和 / 或不安全的基礎映象,其中包含(現在)眾所周知的安全漏洞。
你的映象包含了一些工具(如 curl、apt 等),一旦攻擊者獲得了某種存取權,就可以通過這些工具將惡意軟體載入到容器中。
下面的各個章節講解了能夠優化你的映象安全性的各種方法。它們是按重要性 / 影響程度排序的,也就是說排名靠前的方法更重要。
構建金鑰是隻在構建 Docker 映象時需要的憑證(不是在執行時)。例如,你可能想在你的映象中包含某個應用程式的一個編譯版本,這個應用的原始碼是閉源的,並且其 Git 儲存庫是有存取保護的。在構建映象時,你需要克隆 Git 儲存庫(這需要構建金鑰,例如該儲存庫的 SSH 存取金鑰),從原始碼構建應用程式,然後再刪除原始碼(和金鑰)。
“洩露“構建金鑰是說你不小心把這種金鑰烘焙到了你的映象的某個層中。這種情況很嚴重,因為拉取你的映象的所有人都可以檢索到這些機密。這個問題源於這樣一個事實,即 Docker 映象是以純粹的加法方式逐層構建的。你在一個層中刪除的檔案只是被“標記”為已刪除,但拉取你映象的人們仍然可以使用高階工具存取它們。
可以使用以下兩種方法之一來避免洩露構建金鑰。
Docker 多階段構建(官方檔案)有許多用例,例如加快你的映象構建速度,或減少映象大小。本系列的其他文章會詳細介紹其他用例。總之,你也可以通過多階段構建來避免洩露構建金鑰,如下所示:
建立一個階段 #A,將憑證複製到其中,並使用它們來檢索其他工件(例如上述例子中的 Git 儲存庫)和執行進一步的步驟(例如編譯一個應用程式)。階段 #A 的構建確實包含了構建的金鑰!
建立一個 #B 階段,其中你只從 #A 階段複製非加密的工件,例如一個已編譯的應用程式。
只發布 / 推播階段 #B 的映象
背景知識
如果你使用 docker build 進行構建,可以實際執行構建的後端選項不止一個。其中較新和較快的後端是 BuildKit,你需要在 Linux 上設定環境變數 DOCKER_BUILDKIT=1 來顯式啟用它。注意,BuildKit 在 Windows/MacOS 的 Docker for Desktop 上是預設啟用的。
正如這裡的檔案所解釋的(閱讀它們以瞭解更多細節),BuildKit 構建引擎支援 Dockerfile 中的額外語法。要使用構建金鑰,請在你的 Dockerfile 中放入類似下面這樣的內容:
RUN --mount=type=secret,id=mysecret,dst=/foobar <command to run>
當 RUN 語句被執行時,金鑰將對這個構建容器可用,但不會將金鑰本身(這裡是:/foobar 資料夾)放入構建的映象中。你需要在執行 docker build 命令時指定金鑰的原始檔 / 資料夾(位於主機上)的路徑,例如:
docker build --secret id=mysecret,src=mysecret.txt -t sometag
不過有一點需要注意:你不能通過 docker-compose up --build 來構建需要金鑰的映象,因為 Docker-compose 還不支援用於構建的 --secret 引數,見 GitHub 問題。如果你依賴 docker-compose 的構建,請使用方法 1(多階段構建)。
你應該一直在一個乾淨的環境中構建和推播映象(例如 CI/CD 管道),其中構建代理會將你的儲存庫克隆到一個新目錄。
使用本地開發機器進行構建的問題是,你的本地 Git 儲存庫的“工作樹“可能是髒的。例如,它可能包含有開發過程中需要的金鑰檔案,例如對中轉甚至生產伺服器的存取金鑰。如果沒有通過.dockerignore 排除這些檔案,那麼 Dockerfile 中的“COPY . .“等語句可能會意外導致這些金鑰洩露到最終映象中。
預設情況下,當有人通過“docker runyourImage:yourTag“執行你的映象時,這個容器(以及你在 ENTRYPOINT/CMD 中的程式)會以 root 使用者身份執行(在容器和主機上)。這給了一個使用某種漏洞在你的執行容器中獲得 shell 許可權的攻擊者以下權力:
對主機上所有顯式掛載到容器中的目錄的無限制寫許可權(因為是 root)。
能夠在容器中做 Linux 根使用者可以做的一切事情。例如,攻擊者可以安裝他們需要的額外工具來載入更多的惡意軟體,比如說通過 apt-get install(非 root 使用者無法做到這一點)。
如果你的映象容器是用 docker run --privileged 啟動的,攻擊者甚至可以接管整個主機。
為了避免這種情況,你應該以非 root 使用者(你在 docker build 過程中建立的一些使用者)的身份執行你的應用程式。在你的 Dockerfile 中的某個地方(通常是在結尾處)放置以下語句
# Create a new user (including a home-directory, which is optional) RUN useradd --create-home appuser # Switch to this user USER appuser
Dockerfile 中所有在 USER appuser 語句之後的命令(如 RUN、CMD 或 ENTRYPOINT)都將以這個使用者執行。這裡有一些需要注意的地方:
在切換到非 root 使用者之前,你通過 COPY 複製到映象中的檔案(或由某些 RUN 命令建立的檔案)是由 root 使用者擁有的,因此以非 root 使用者身份執行的應用程式無法寫入。為了解決這個問題,請把建立和切換到非 root 使用者的程式碼移到 Dockerfile 的開頭。
如果這些檔案是在 Dockerfile 的開頭以根使用者身份建立的(儲存在 /root/ 下面,而不是 /home/appuser/ 下面),那麼你的程式期望在使用者的主目錄中的某個地方(例如~/.cache)的檔案,現在從應用程式的視角來看可能突然消失了。
如果你的應用程式監聽一個 TCP/UDP 埠,就必須使用大於 1024 的埠。小於等於 1024 的埠只能以 root 使用者身份使用,或者以一些高階 Linux 能力來使用,但你不應該僅僅為了這個目的而給你的容器這些能力。
如果你使用的基礎映象包含了某個真正的 Linux 發行版(如 Debian、Ubuntu 或 alpine 映象)的全部工具集,其中包括一個軟體包管理器,建議使用該軟體包管理器來安裝所有可用的軟體包更新。
基礎映象是由某人維護的,他設定了 CI/CD 管道計劃來構建基礎映象,並定期推播到 Docker Hub。你無法控制這個時間間隔,而且經常發生的情況是,在該管道將更新的 Docker 映象推播到 Docker Hub 之前,Linux 發行版的包登入檔(例如通過 apt)中已經有了安全修補程式。例如,即使基礎映象每週推播一次,也有可能在最近的映象釋出幾小時或幾天後出現安全更新。
因此,最好總是執行更新本地軟體包資料庫和安裝更新的包管理器命令,採用無人值守模式(不需要使用者確認)。每個 Linux 發行版的這個命令都不一樣。
例如,對於 Ubuntu、Debian 或衍生的發行版,使用 RUN apt-get update && apt-get -y upgrade
另一個重要的細節是,你需要告訴 Docker(或你使用的任何映象構建工具)來重新整理基礎映象。否則,如果你參照一個基礎映象,比如 python:3(而 Docker 在其本地映象快取中已經有了這樣一個映象),Docker 甚至不會檢查 Docker Hub 上是否存在更新的 python:3 版本。為了擺脫這種行為,你應該使用這個命令:
docker build --pull <rest of the build command>
這可以確保 Docker 在構建映象之前拉取你的 Dockerfile 中 FROM 語句中提到的映象的更新。
你還應該注意 Docker 的層快取機制,它會讓你的映象變得陳舊,因為 RUN <install apt/etc. updates>命令的層是快取的,直到基礎映象維護者釋出新版本的基礎映象才重新整理。如果你發現基礎映象的釋出頻率相當低(比如少於一週一次),那麼定期(比如每週一次)重建你的映象並禁用層快取是個好主意。你可以執行以下命令來做到這一點:
docker build --pull --no-cache <rest of the build command>
5定期更新第三方依賴
你編寫的軟體是基於第三方的依賴,也就是由其他人制作的軟體。這包括了:
你的映象下面的基礎 Docker 映象,或
你作為自己應用程式的一部分使用的第三方軟體元件,例如通過 pip/npm/gradle/apt/……安裝的元件。
如果你的映象中的這些依賴過時了,就會增加攻擊面,因為過時的依賴往往有可利用的安全漏洞。
你可以定期使用 SCA(軟體元件分析)工具來解決這個問題,比如 Renovate Bot。這些工具(半)自動將你宣告的第三方依賴更新為最新版本,例如在你的 Dockerfile、Python 的 requirements.txt、NPM 的 packages.json 等檔案中宣告的列表。你需要設計你的 CI 管道,使 SCA 工具所做的更改自動觸發你的映象的 re-build。
這種自動觸發的映象重建對於處在只維護模式,但程式碼仍將被客戶在生產環境中使用(客戶希望它是安全的)的專案特別有用。在維護期間,你不再開發新的特性,也不會構建新的映象,因為沒有新的提交(由你做出)來觸發新的構建。然而,由 SCA 工具做出的提交確實會再次觸發映象構建。
你可以在我的相關博文中找到更多關於 Renovate bot 的細節。
即使你執行了上述建議,比如說你的映象總是使用最新的第三方依賴,它仍然可能是不安全的(例如一個依賴已經被棄用的情況)。在這種情況下,“不安全“意味著一個(或多個)依賴有已知的安全漏洞(在一些 CVE 資料庫中註冊)。
出於這個原因,你可以給你的 Docker 映象提供某種工具來掃描所有包含的檔案,以找到這種漏洞。這些工具有兩種形式:
你顯式呼叫的 CLI 工具(例如在 CI 管道中),比如說 Trivy(OSS,在 CI 管道中非常容易使用,見 Trivy 檔案)、Clair(OSS,但設定和使用比 Trivy 更復雜),或 Snyk(通過“docker scan“整合到 Docker CLI 中,見 cheat sheet,但只有有限的免費計劃!)
整合到你推播映象的映象註冊中心的掃描器,如 Harbor(內部使用 Clair 或 Trivy)。還有一些商業產品,如 Anchore。
因為這些掃描器是通用的,它們還試圖覆蓋一大堆包登入檔,所以可能不會特別為你在自己專案中使用的程式語言或包登入檔客製化。有時,你應該調查你的程式語言生態系統提供了哪些工具。例如,對於 Python 來說就有一個專門針對 Python 包的安全工具。
有時,問題來自於你在 Dockerfile 中放置的語句,這些語句是不好的實踐(但你沒有意識到)。為此可以使用諸如 checkov、Conftest、trivy 或 hadolint 等工具,它們是 Dockerfile 的 linter。為了選擇正確的工具,你需要檢視它的預設規則 / 政策。例如,hadolint 比 checkov 或 conftest 提供的規則更多,因為它是專門針對 Dockerfiles 的。這些工具也是相互補充的,因此在你的 Dockerfiles 上執行多個工具(如 hadolint 和 trivy)確實是有意義的。不過要做好準備,因為你需要維護“忽略檔案“,在這個檔案中的規則會被忽略——可能是由於誤報而有意忽略它們,或者是你準備故意破壞規則。
為了驗證你使用的基礎映象確實是由該映象背後的公司構建和推播的,你可以使用 Docker 內容信任(見官方檔案)特性。只需在執行 docker build 或 docker pull 時將 DOCKER_CONTENT_TRUST 環境變數設為“1“即可啟用該特性。Docker 守護行程將拒絕提取沒有經過釋出者簽名的映象。
不幸的是,大約一年前開始社群就不再以這種方式簽名映象了。就連 Docker Inc. 也在 2020 年 12 月停止了簽名官方 Docker 映象,也沒有官方解釋。問題更大的是如果你使用“docker pull docker:latest”這樣的命令,只會下載一個過時很久的映象。
你可以檢視一下映象簽名的其他實現,比如說 cosign(不過我還沒試過)。
安全問題通常來源於其他人的程式碼,也就是流行的第三方依賴。因為它們應用廣泛,所以在駭客那裡是“有利可圖“的。然而,有時是你自己的程式碼在作怪。例如,你可能不小心實現了 SQL 注入的可能性、堆疊溢位的錯誤,等等。
為了找到這些問題,你可以使用所謂的 SAST(靜態應用安全測試)工具。一方面,有一些特定於程式語言的工具(你必須單獨研究),如 Python 的 bandit,或 Java 的 Checkstyle/Spotbugs。另一方面,還有一些支援多種程式語言和框架的工具套件(其中一些是非免費 / 商業的),如 SonarQube(對於它還有 SonarLint IDE 外掛)。
在實踐中,安全掃描有兩種基本方法:
連續(自動)掃描:你建立一個 CI 作業,在每次推播時掃描你的程式碼。這可以讓你的程式碼安全性保持在一個較高的水平上,但你必須弄清楚如何忽略誤報(這是一項持續的維護工作)。如果你使用 GitLab,可能還會發現 GitLab 的免費 SAST 功能很有趣。
不定期(手動)掃描:團隊中一些有安全意識的成員在本地執行安全檢查,例如每月一次或每次釋出前,並手動檢視結果。
docker-slim 工具可以獲取大型 Docker 映象,臨時執行它們,分析哪些檔案在臨時容器中是被真正使用的,然後生成一個新的、單層的 Docker 映象——其中所有未使用的檔案都會被刪除。這樣做有兩個好處:
映象被縮小
映象變得更加安全,因為不需要的工具被刪除了(例如 curl 或包管理器)。
請參考我之前文章中的 Docker slim 部分以瞭解更多細節。
一個映象中儲存的軟體(如 CLI 工具等)越多,攻擊面就越大。使用“最小“的映象是一個很好的實踐,它越小越好(無論如何這是一個很好的優勢),並且應該包含儘可能少的工具。最小的映象甚至超越了“優化體積“的映象(如 alpine 或:-slim,如 python:3.8-slim):前者沒有任何包管理器。這使攻擊者很難載入額外的工具。
最安全的最小基礎映象是 SCRATCH,它完全不包含任何東西。只有當你在映象中放置自包含的二進位制檔案時,才能用 FROM SCRATCH 啟動你的 Dockerfile——這些二進位制檔案烘焙進了所有的依賴(包括 C-runtimes)。
如果 SCRATCH 不適合你,谷歌的無發行版(distroless)映象可以是一個很好的選擇,特別是當你正在為常見的程式語言(如 Python 或 Node.js)構建應用程式,或者需要一個最小的 Debian 基礎映象時。
不幸的是,最小映象有幾個需要注意的地方:
無發行版的注意事項:
不建議使用谷歌在 gcr.io 上釋出的針對特定程式語言的映象,因為那裡只有一個 latest 版本標籤,以及 major 版本的標籤(例如 python 的“3“,或 Node 的“12“)。你無法控制具體的語言執行時版本(例如是否使用 Python 3.8.3 或 3.8.4 等),這破壞了你的映象構建的可重用性。
客製化(和構建你自己的)無發行版映象是相當複雜的:你需要熟悉 Bazel 的構建系統並自己構建映象。
注意:如果你唯一需要的客製化是“以非 root 使用者身份執行程式碼”,那麼每個無發行版基礎映象中都有一個預設的非 root 使用者,詳見這裡。
最小基礎映象的常規注意事項:
使用最小基礎映象偵錯容器是很棘手的,因為有用的工具(比如 /bin/sh)現在不見了。
對於 Docker,你可以執行第二個偵錯容器(它確實有一個 shell 和偵錯工具,例如 alpine:latest),並使其共用你的最小容器的 PID 名稱空間,例如通過 docker run -it --rm --pid=container:
--cap-add SYS_PTRACE alpine sh對於 Kubernetes,你可以使用短期容器,見這裡的例子
一個受信任的映象指的是經過某人(要麼是你自己的組織,要麼是其他人)按照比如說某種安全級別稽核的映象。這對具有高安全要求和規定的受管制行業(銀行、航空航天等)來說可能特別重要。
雖然你自己可以通過從頭開始建立可信的映象來完成審計工作,但這是不可取的。因為你(這個映象的構建者)必須確保所有與審計有關的任務都已完成,並有正確的記錄(例如記錄映象中的包列表、執行的 CVE 檢查及其結果等等)。這項任務非常繁重。相反,我們建議將這項工作外包出去,使用商業性的“可信登入檔“——它提供了一套選定的可信映象,如 RedHat 的通用基礎映象(UBI)。RedHat 的 UBI 現在也可以在 Docker Hub 上免費獲取。
在 Docker Hub 上託管的映象沒有經過審計。它們是“按原樣“提供的。它們可能是不安全的(甚至包含惡意軟體),而且沒有人會通知你這一點。因此,使用 Docker Hub 中不安全的基礎映象也會讓你的映象變得不安全。
另外,你不應該把審計和上面提到的 Docker 的內容信任混為一談!內容信任只確認來源(映象上傳者)的身份,並不會確認與映象安全性有關的任何事實。
Linux capabilities 是 Linux 核心的一個特性,它允許你控制一個應用程式可以使用哪些核心特性,例如一個程序是否可以傳送訊號(如 SIGKILL)、設定網路介面、掛載磁碟,或偵錯程序等。完整的列表見這裡。一般來說,你的應用程式需要的功能越少越好。
啟動你的映象容器的所有人都可以給予(或拿走)這些能力,例如通過呼叫“docker run --cap-drop=ALL “。預設情況下 Docker 會放棄所有能力,除了這裡定義的那些以外。你的應用程式可能不需要所有這些功能。
作為一個最佳實踐,你可以嘗試啟動你的映象容器,放棄所有能力(使用 --cap-drop=ALL),看看它是否仍然正常工作。如果不能,請搞清楚哪些功能是缺失的,並且你是否真的需要它們。然後請記錄你的映象需要哪些功能(以及為什麼),這會給執行你映象的使用者帶去更多信心。
提升你的映象安全性並非閒庭信步。你需要花時間來評估和實施每一種實踐。本文中的列表應該可以節省你的時間,因為收集和排序重要步驟的工作已經為你做好了。
所幸,提升你的應用程式的安全性是一個迭代過程。你可以從小處著手,每次實施一個步驟。不過你確實需要得到管理層的支援。這有時是很難辦的,特別是有時你的經理會對建議有抵觸情緒,他們可能傾向於從過去的經驗來做推斷(“我們,或我們的客戶,以前從未被黑過,那麼為什麼這種問題現在會發生在我們身上?我們需要的是特性!“)。你有幾個選擇:可以說服你的經理為安全性分配資源。例如,如果你有一個直接接觸客戶的渠道(你在為其構建軟體),那麼可以說服他們,讓他們要求把安全性作為一個“特性“。或者在你的行業中尋找安全漏洞的報告(例如一個直接的競爭對手受到了影響),以證明駭客攻擊確實發生了,甚至你的行業也出了問題,而且它們有嚴重的(財務)影響。
到此這篇關於優化Docker映象安全性的12個技巧的文章就介紹到這了,更多相關優化Docker映象安全性內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
原文連結:
https://www.augmentedmind.de/2022/02/20/optimize-docker-image-security/
作者 | Marius 譯者 | 王強 策劃 | 閆園園
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45