您好,登錄后才能下訂單哦!
這篇文章主要介紹“dockerfile和鏡像安全舉例分析”,在日常操作中,相信很多人在dockerfile和鏡像安全舉例分析問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”dockerfile和鏡像安全舉例分析”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!
避免不必要的安裝包
一個容器一個進程
最小化layers的數量
排序多行參數
# Base images 基礎鏡像 FROM centos #MAINTAINER 維護者信息 MAINTAINER lorenwe #ENV 設置環境變量 ENV PATH /usr/local/nginx/sbin:$PATH #ADD 文件放在當前目錄下,拷過去會自動解壓 ADD nginx-1.13.7.tar.gz /tmp/ #RUN 執行以下命令 RUN rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7 \ && yum update -y \ && yum install -y vim less wget curl gcc automake autoconf libtool make gcc-c++ zlib zlib-devel openssl openssl-devel perl perl-devel pcre pcre-devel libxslt libxslt-devel \ && yum clean all \ && rm -rf /usr/local/src/* RUN useradd -s /sbin/nologin -M www #WORKDIR 相當于cd WORKDIR /tmp/nginx-1.13.7 RUN ./configure --prefix=/usr/local/nginx --user=www --group=www --with-http_ssl_module --with-pcre && make && make install RUN cd / && rm -rf /tmp/ COPY nginx.conf /usr/local/nginx/conf/ #EXPOSE 映射端口 EXPOSE 80 443 #ENTRYPOINT 運行以下命令 ENTRYPOINT ["nginx"] #CMD 運行以下命令 CMD ["-h"]
ENV 設置環境變量,簡單點說就是設置這個能夠幫助系統找到所需要運行的軟件,比如我上面寫的是 “ENV PATH /usr/local/nginx/sbin:$PATH”,這句話的意思就是告訴系統如果運行一個沒有指定路徑的程序時可以從 /usr/local/nginx/sbin 這個路徑里面找,只有設置了這個,后面才可以直接使用 ngixn 命令來啟動 nginx,不然的話系統會提示找不到應用。
ADD 用于添加文件,源文件可以是一個文件,或者是一個 URL 都行,如果源文件是一個壓縮包,在構建鏡像的時候會自動的把壓縮包解壓開來,示例寫的是ADD nginx-1.13.7.tar.gz /tmp/其中 nginx-1.13.7.tar.gz 這個壓縮包是必須要在 dockefile 文件目錄內。
RUN 就是執行命令,RUN 可以執行多條命令, 用 && 隔開就行,如果命令太長要換行的話在末尾加上 ‘\’ 就可以換行命令, yum clean all ,把所有的 yum 緩存清掉,這可以減少構建出來的鏡像大小,rm -rf /usr/local/src/清除用戶源碼文件,都是起到減少構建鏡像大小的作用,每用一次 RUN 命令就會生成一層鏡像。
當 ENTRYPOINT 和 CMD 都存在時 CMD 中的命令會以 ENTRYPOINT 中命令的參數形式來啟動容器,例如上面的示例 dockerfile,在啟動容器時會以命令為 nginx -h來啟動容器,遺憾的是這樣不能保持容器運行,所以可以這樣啟動 docker run -it lorenwe/centos_nginx -c /usr/local/nginx/conf/nginx.conf,那么容器啟動時運行的命令就是 nginx -c /usr/local/nginx/conf/nginx.conf,可以自定義啟動參數了。
如果一個服務不需要任何權限即可運行,可以使用USER指令改變為非Root用戶,只需在Dockerfile中添加RUN指令 RUN groupadd -r postgres && useradd -r -g postgres postgres
VOLUME指令用于公開docker容器創建的數據庫存儲區域,配置,文件或者文件夾,建議使用VOLUME來維護用戶服務可變的部分,即把可變的數據公開的外部存儲。
Docker默認使用root用戶運行容器。 然后將該名稱空間映射到正在運行的容器中的root用戶時,這意味著該容器可能對Docker主機具有root訪問權限。 如果容器本身具有漏洞,則由root用戶在容器上運行應用程序可以進一步擴大攻擊面,并為特權升級提供簡便的途徑。 為了最大程度地減少曝光,請選擇在Docker映像中為應用程序創建一個專用用戶和一個專用組; 在Dockerfile中使用USER指令來確保容器以最小的特權訪問來運行應用程序。 圖像中可能不存在特定用戶; 使用Dockerfile中的說明創建該用戶
FROM ubuntu:latest RUN useradd -r -u 1001 -g appuser appuser USER appuser ENTRYPOINT [“sleep”, “infinity”]
FROM ubuntu RUN mkdir /app RUN groupadd -r lirantal && useradd -r -s /bin/false -g lirantal lirantal WORKDIR /app COPY . /app RUN chown -R lirantal:lirantal /app USER lirantal CMD node index.js
創建一個沒有密碼,沒有設置主目錄并且沒有shell的系統用戶(-r)
將創建的用戶添加到先前創建的現有組中(使用groupadd)
與創建的組關聯,將最終參數集添加到我們要創建的用戶名中
Docker內容信任(DCT)
Docker Content Trust(DCT)提供了使用數字簽名處理發送到遠程Docker注冊表和從遠程Docker注冊表接收的數據的功能。這些簽名允許客戶端或運行時驗證特定鏡像標簽的完整性和發布者。
如果使用者啟用DCT,則他們只能使用受信任的鏡像進行拉取,運行或構建。 啟用DCT有點像對注冊表應用“過濾器”。 消費者僅“看到”簽名的鏡像標簽,而對他們而言“不可見”的是不太希望使用的未簽名的鏡像標簽。
簽名映像的前提條件是已連接公證服務器的Docker注冊表(例如Docker Hub或Docker Trusted Registry)。在Docker CLI中,我們可以使用$ docker trust命令語法簽署并推送容器映像。
將委托私鑰添加到本地Docker信任庫中。 (默認情況下,它存儲在~/.docker/trust/中)。如果使用$ docker trust key generate生成委托密鑰,則私鑰會自動添加到本地信任存儲中。如果要導入單獨的密鑰(例如,從UCP客戶端捆綁包中導入),則需要使用$ docker trust key load命令。接下來,需要將委派公鑰添加到Notary服務器。 這特定于公證人中稱為全局唯一名稱(GUN)的特定鏡像倉庫。 如果這是您第一次向該鏡像倉庫添加委派,則此命令還將使用本地Notary規范根密鑰來啟動存儲庫。
# 生成key $ docker trust key generate jeff # 或者使用已有的key $ docker trust key load key.pem --name jeff # 配置DCT的環境變量,啟用DCT $ export DOCKER_CONTENT_TRUST=1 #對鏡像打標簽,從而可以將其推送到目標鏡像庫。本例中,會將其推送到位于我 Docker Hub 個人賬戶命名空間下的鏡像庫。 $ docker image tag alpine:latest nigelpoulton/dockerbook:v1 # 登錄到 Docker Hub(或其他鏡像庫)以便推送鏡像。 $ docker login # 使用push推送鏡像 $ docker push dtr.example.com/admin/demo:1 # 查看標簽或存儲庫的遠程信任數據 $ docker trust inspect --pretty dtr.example.com/admin/demo:1
Docker Enterprise Engine中的Docker Content Trust阻止用戶使用來自未知來源的容器映像,也將阻止用戶從未知來源的基礎層構建容器映像。 受信任的來源可能包括在Docker Hub上找到的Official Docker Images或用戶受信任的來源,其中包含使用上述命令簽名的存儲庫和標簽。
引擎簽名驗證可防止以下情況:
docker容器運行的未簽名或更改鏡像。
docker 拉取未簽名或更改的鏡像。
docker build其中FROM鏡像未簽名或未擦除。
獲取鏡像時,通過配置 docker 守護進程/etc/docker/daemon.json配置獲取可信來源的鏡像。Docker CE 不支持
{ "content-trust": { "trust-pinning": { "official-library-images": true }, "mode": "enforced" } }
拉去鏡像
$ docker pull dtr.example.com/user/image:1 Error: remote trust data does not exist for dtr.example.com/user/image: dtr.example.com does not have trust data for dtr.example.com/user/image $ docker pull dtr.example.com/user/image@sha256:d149ab53f8718e987c3a3024bb8aa0e2caadf6c0328f1d9d850b2a2a67f2819a sha256:ee7491c9c31db1ffb7673d91e9fac5d6354a89d0e97408567e09df069a1687c1: Pulling from user/image ff3a5c916c92: Pull complete a59a168caba3: Pull complete Digest: sha256:ee7491c9c31db1ffb7673d91e9fac5d6354a89d0e97408567e09df069a1687c1 Status: Downloaded newer image for dtr.example.com/user/image@sha256:ee7491c9c31db1ffb7673d91e9fac5d6354a89d0e97408567e09df069a1687c1
如果不是這樣的話增加了鏡像文件大小,增加了受攻擊面。
一些開源的鏡像掃描工具
Anchore Engine:Anchore Engine是用于分析容器鏡像的工具。 除了基于CVE的安全漏洞報告之外,Anchore Engine還可以使用自定義策略評估Docker映像。策略基于白名單或黑名單、憑據、文件內容、配置類型或其他用戶生成的提示。打包為Docker容器映像的Anchore可以獨立運行,也可以在業務平臺(例如Kubernetes)上運行。 它還可以與 CI/CD 的 Jenkins 和 GitLab 集成。
Clair:Clair 攝取了許多漏洞數據源,例如Debian Security Bug Tracker,Ubuntu CVE Tracker和Red Hat Security Data。 由于Clair使用了許多CVE數據庫,因此其審核是全面的。Clair首先為容器映像中的特征列表建立索引。 然后,使用Clair API,開發人員可以在數據庫中查詢與特定圖像有關的漏洞。。
dagda:a tool to perform static analysis of known vulnerabilities, trojans, viruses, malware & other malicious threats in docker images/containers and to monitor the docker daemon and running docker containers for detecting anomalous activities
OpenScap:一套自動審核工具,用于按照NIST認證的安全內容自動化協議(SCAP)來檢查軟件中的配置和已知漏洞。 不是特定用于容器的,但確實包含一定程度的支持。
介紹下 Clair
安裝過程:
$ mkdir $PWD/clair_config $ curl -L https://raw.githubusercontent.com/coreos/clair/master/config.yaml.sample -o $PWD/clair_config/config.yaml $ docker run -d -e POSTGRES_PASSWORD="password" -p 5432:5432 postgres:9.6 $ docker run --net=host -d -p 6060-6061:6060-6061 -v $PWD/clair_config:/config quay.io/coreos/clair:latest -config=/config/config.yaml
config.yaml的配置文件需要做下修改(對應行)
source: host=localhost port=5432 user=postgres password=password sslmode=disable statement_timeout=60000
測試部署成功
[root@localhost ~]# curl -X GET -I http://localhost:6061/health HTTP/1.1 200 OK Server: clair Date: Wed, 18 Mar 2020 13:32:33 GMT Content-Length: 0 [root@localhost ~]# curl http://localhost:6060/v1/namespaces ...
API 接口使用不方便,整合其他工具https://github.com/quay/clair/blob/master/Documentation/integrations.md
安裝第三方客戶端 claircli,執行掃描,本地生成 html 的報告。
[root@localhost home]# pip install claircli [root@localhost home]# claircli -l 127.0.0.1 postgres 2020-03-18 21:45:50,870|INFO|Starting local http server 2020-03-18 21:45:50,871|INFO|Local http server serving at port: 10963 2020-03-18 21:45:50,872|INFO|*****************************1****************************** 2020-03-18 21:45:50,872|INFO|Analyzing <Image: postgres> 2020-03-18 21:45:56,449|INFO|Push layer [1/14]: 5c77fc16775dbda7fafd2db94684c22de93066e29dd686a2f46d995615458476 2020-03-18 21:45:56,715|INFO|Push layer [2/14]: 54a426d01ba59fb558c7cf6681c6840736e5d0654a62f0c383d227637cdee0db 2020-03-18 21:45:56,777|INFO|Push layer [3/14]: a31210340f3a4905656af9be0ee9ffe3291380e6764c5d2d62831c2626451231 2020-03-18 21:45:56,787|INFO|Push layer [4/14]: fb1bc94faf7fe27b7f7a36c980c8407d9f28bab2c047cf389dda8eb9349cfa32 2020-03-18 21:45:56,801|INFO|Push layer [5/14]: 8f5652501fa074cb5b9d54c6dceaa966c6591000837076de4c8aaf90ad3c919a 2020-03-18 21:45:56,834|INFO|Push layer [6/14]: 3f89d1179df8c1c036baf12dd6204a6f17f752e3c0f96b0d25eb408bcb6f2313 2020-03-18 21:45:56,876|INFO|Push layer [7/14]: 1034326be7395271eed2e8e3fbb6e8719ec21533776646eda190ab6d5d690404 2020-03-18 21:45:56,886|INFO|Push layer [8/14]: eba8f87a20b5efae0ab4540e5932e3920879ffbfcde08fd2664bd35a8392a48e 2020-03-18 21:45:56,896|INFO|Push layer [9/14]: 9fcb1e2984e4683b4c8e724b64836097b19d03e77f98fbe226ffd581fdfe0bcd 2020-03-18 21:45:57,101|INFO|Push layer [10/14]: 17685e9204242fce5aa038a05cf160bd4a7f6b516bb461a5c8ca5977f2fa1e74 2020-03-18 21:45:57,110|INFO|Push layer [11/14]: 4a4b72a0e224e07071b6d60e8c4335b5996ff58f894fc3c10e7bbf523de924e8 2020-03-18 21:45:57,121|INFO|Push layer [12/14]: 02053f40fe92249821c297ab7b9a10ee2071b005c541e022d74c3d1fbde5a28f 2020-03-18 21:45:57,132|INFO|Push layer [13/14]: 92e8c07039ed217658e3d78e3681dc19bcf8193caee4c85445ffa2a77cce1925 2020-03-18 21:45:57,142|INFO|Push layer [14/14]: 9d681078d309476626ccd11c7d2fa2f9010d6d4f67b3dd935075fd9ab16fad88 2020-03-18 21:45:57,153|INFO|Fetch vulnerabilities for <Image: postgres> 2020-03-18 21:45:57,172|INFO|Defcon1 : 0 2020-03-18 21:45:57,172|INFO|Critical : 0 2020-03-18 21:45:57,172|INFO|High : 0 2020-03-18 21:45:57,172|INFO|Medium : 0 2020-03-18 21:45:57,172|WARNING|Low : 10 2020-03-18 21:45:57,173|WARNING|Negligible : 47 [root@localhost home]# ls clair-postgres.html
HEALTHCHECK指令具有兩種形式:
HEALTHCHECK [OPTIONS] CMD命令(通過在容器內部運行命令來檢查容器的運行狀況)
HEALTHCHECK NONE(禁用從基本映像繼承的任何健康檢查)
HEALTHCHECK指令告訴Docker如何測試容器以檢查其是否仍在工作。這樣可以檢測到諸如Web服務器陷入無限循環并且無法處理新連接的情況,即使服務器進程仍在運行。
指定容器的運行狀況檢查后,除了其正常狀態外,它還具有運行狀況。此狀態最初開始。只要運行狀況檢查通過,它就會變得健康(無論以前處于什么狀態)。在一定數量的連續故障之后,它變得不健康。
在CMD之前可以顯示的選項是:
--interval=DURATION (default: 30s)
--timeout=DURATION (default: 30s)
--start-period=DURATION (default: 0s)
--retries=N (default: 3)
運行狀況檢查將首先在容器啟動后的間隔秒數內運行,然后在每次之前的檢查完成后的間隔秒數內運行。
如果單次檢查花費的時間超過超時秒數,則認為檢查失敗,需要重新嘗試連續進行的健康檢查失敗,才能將容器視為不健康。
開始時間段為需要時間進行引導的容器提供了初始化時間。在此期間的探針故障將不計入最大重試次數。但是,如果運行狀況檢查在啟動期間成功,則認為該容器已啟動,并且所有連續失敗將計入最大重試次數。
Dockerfile中只能有一條HEALTHCHECK指令。如果您列出多個,則只有最后一個“健康檢查”才會生效。
CMD關鍵字后面的命令可以是shell命令(例如HEALTHCHECK CMD / bin / check-running)或exec數組(與其他Dockerfile命令一樣;有關詳細信息,請參見ENTRYPOINT)。
命令的退出狀態指示容器的健康狀態。可能的值為:
0:成功-容器健康且可以使用
1:不健康-容器無法正常工作
2:保留-請勿使用此退出代碼
例如,要每五分鐘檢查一次,以便網絡服務器能夠在三秒鐘內為網站的首頁提供服務:
HEALTHCHECK --interval=5m --timeout=3s \ CMD curl -f http://localhost/ || exit 1
為了幫助調試失敗的探針,該命令在stdout或stderr上寫入的任何輸出文本(UTF-8編碼)都將以健康狀態存儲,并可以通過docker inspect查詢。此類輸出應保持簡短(當前僅存儲前4096個字節)。
當容器的健康狀態發生變化時,將以新狀態生成health_status事件。
在Dockerfile上的一行中添加更新指令將導致更新層被緩存。 當您以后再使用同一指令構建任何映像時,這將導致使用先前本地緩存的更新層,從而有可能阻止將任何新的更新應用于以后的構建。
在安裝軟件包時,應同時使用更新說明,安裝說明和版本說明。 這樣可以防止緩存并強制提取所需的版本。 或者,可以在docker構建過程中使用--no-cache標志,以避免使用緩存的圖層。
docker build [OPTIONS] PATH | URL | --no-cache
可執行文件上可以設置兩種特殊權限:設置用戶ID(setuid)和設置組ID(sgid)。 這些權限允許使用所有者或組的特權來執行要執行的文件。 例如,如果文件由root用戶擁有并且設置了setuid位,則無論是誰執行該文件,它都將始終以root用戶特權運行。
應用程序可能不需要任何setuid或setgid二進制文件。 如果可以禁用或刪除此類二進制文件,則可以停止將它們用于緩沖區溢出,路徑遍歷/注入和特權升級攻擊的任何可能性。
setuid位此位用于具有可執行權限的文件。 setuid位僅表示運行可執行文件時,它將權限設置為創建它的用戶(所有者),而不是將其設置為啟動它的用戶。 類似地,有一個setgid位對gid做同樣的事情。setgid會影響文件和目錄。 當在文件上使用時,它以擁有該文件的用戶組的特權執行,而不是以執行該文件的用戶組的特權執行。將目錄設置為該位后,該目錄中的文件集將與父目錄的組具有相同的組,而不是創建這些文件的用戶的組。 這用于文件共享,因為屬于父目錄組的所有用戶現在都可以對其進行修改。
在 linux 里查找和刪除有 setuid 權限的文件
find / -perm +6000 -type f -exec \ ls -ld {} \; 2> /dev/null # 在容器里查找 $ docker run debian find / -perm +6000 -type f -exec ls -ld {} \; 2> /dev/null
運行容器時刪除 setuid 權限
$ docker run -d --cap-drop SETGID --cap-drop SETUID <container_id>
在 dockerfile build 成功后執行 setuid 和 setgid 的檢查
docker run --rm defanged-debian find / -perm +6000 -type f -exec ls -ld {} \; 2> /dev/null | wc -l
結果為 0 表示創建的鏡像沒有特殊權限的文件。
COPY指令僅將文件從本地主機復制到容器文件系統。 ADD指令可能會從遠程URL檢索文件并執行諸如將它們解壓縮之類的操作。 因此,ADD指令會帶來安全風險。 例如,惡意文件可能直接從URL訪問而無需掃描,或者可能存在與解壓縮程序有關的漏洞。
dockerfile 自身訪問權限可能存在訪問控制漏洞,另外有權限在 docker 主機上運行docker history的用戶都能看到 dockerfile 中的密鑰信息。
以下示例 Dockerfile 只是為了證明可以訪問密鑰,密鑰信息顯示在構建輸出中。 構建的最終鏡像沒有密鑰文件:
$ docker build --no-cache --progress=plain --secret id=mysecret,src=mysecret.txt . ... #8 [2/3] RUN --mount=type=secret,id=mysecret cat /run/secrets/mysecret #8 digest: sha256:5d8cbaeb66183993700828632bfbde246cae8feded11aad40e524f54ce7438d6 #8 name: "[2/3] RUN --mount=type=secret,id=mysecret cat /run/secrets/mysecret" #8 started: 2018-08-31 21:03:30.703550864 +0000 UTC #8 1.081 WARMACHINEROX #8 completed: 2018-08-31 21:03:32.051053831 +0000 UTC #8 duration: 1.347502967s #9 [3/3] RUN --mount=type=secret,id=mysecret,dst=/foobar cat /foobar #9 digest: sha256:6c7ebda4599ec6acb40358017e51ccb4c5471dc434573b9b7188143757459efa #9 name: "[3/3] RUN --mount=type=secret,id=mysecret,dst=/foobar cat /foobar" #9 started: 2018-08-31 21:03:32.052880985 +0000 UTC #9 1.216 WARMACHINEROX #9 completed: 2018-08-31 21:03:33.523282118 +0000 UTC #9 duration: 1.470401133s ...
最佳的方法是從網絡服務器上獲取密鑰信息
FROM busyboxRUN echo "The secret is: " && \ wget -O - -q http://localhost:8000/secret.txt
通常是集成到 devops 的過程中
dependency check,支持各種語言,持續社區更新,有命令行、docker部署、豐富的報告格式。原理是基于開源的 NVD 開源漏洞數據庫來監測安全漏洞的,缺點是基于文件名來使用Lucene分詞匹配cpe不準確,這個環節引入一部分誤報的問題。
dependency track,是owasp新出的工具,界面較好,方便管理。
SAP公司開源了Java和Python SCA 工具,提供靜態代碼安全性測試功能。
對于node應用,有npm audit fix命令可以自動升級版本,原理是通過nodesecurity.io的接口查詢漏洞,詳情參看https://www.npmjs.com/solutions/security-compliance。
如果基于github,那么有snyk.io,git alert、lgtm、sonar oss免費服務可以使用。另外gitlab企業版,也直接提供了安全功能。
商業產品
到此,關于“dockerfile和鏡像安全舉例分析”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。