關於容器鏡像安全,你作對了嗎? | IDCF

容器在近些年變得煊赫一時,提到容器就不能不提到鏡像,若是說容器是雲計算時代的核心內容之一,那麼鏡像就是容器這個核心的靈魂。因此鏡像的安全也就顯得尤其重要。
可是從下面的幾組數據能夠看到:鏡像的安全問題卻不那麼使人樂觀。java

1) Linux OS的漏洞呈逐年上漲趨勢

從2008年的不到300+,上升至2018年的2000+。並且近兩年呈指數級上升趨勢。nginx

2) 高危漏洞數量呈逐年上漲趨勢

從2014年的不到2000+,上升至2018年的4000+。git

3) Docker 鏡像廣泛存在漏洞

最受歡迎的鏡像好比nginx,ubuntu,java等廣泛存在漏洞,且多達數十個。github

4) 40%的受訪者表示,沒有在CI階段採起任何安全手段。

所以,保證鏡像安全,不只是保障雲平臺安全的重要一環,更是DevSecOps治理體系中一個重要的話題。docker

1、鏡像的特色

鏡像的本質、鏡像的來源以及鏡像的製做共同造就了鏡像的如下幾個特色:數據庫

  • 複雜性

鏡像內容的複雜性(既包括一些OS的各類庫、包,又包含一些Python或者Ruby等文件)、來源的複雜性(官方的、我的的)、Dockerfile 命令的複雜性(ADD和COPY的區別使用,CMD和ENTRYPOINT的區別使用,命令順序不一樣造就不一樣的鏡像)使得鏡像自己就變得很是複雜,若是考慮安全因素,那就更加複雜了。ubuntu

  • 便捷性

鏡像的製做是很是方便的,只要會寫Dockerfile,就能製做出鏡像,或者也可將既有容器製做成一個鏡像。並且鏡像的使用也是很是方便的,一個命令(docker run)就能將一個靜態的鏡像轉變爲一個動態的容器,偏偏是這種便捷性形成了鏡像的另一個特色,也就是下面的混亂性。vim

  • 混亂性

人人可製做鏡像,人人可管理鏡像,也就使得鏡像的種類、數量都是異常龐大的,並且針對某個特定功能的鏡像可達幾十個,甚至上百個,既有官方的,又有我的的,既有共有倉庫的,又有私有倉庫的。沒有一個行之有效的標準去規範的管理這些鏡像,就使得鏡像參差不齊,選用時較爲困難。segmentfault

上述的特色也就使得鏡像的安全變成了一個複雜且容易被忽略的點。然而再複雜,也有手段去完成這個複雜的工做,也就是下面要講的鏡像掃描。安全

2、鏡像掃描在SDLC中的位置

鏡像掃描是保證鏡像安全的一個強有力手段,其一般發生在軟件開發生命週期(SDLC: Software Development Life Cycle)的構建階段,以下所示:

image.png

現有的鏡像掃描大都是依賴於鏡像倉庫提供的掃描功能(內置鏡像掃描工具),通常流程以下:

image.png

  • 開發人員提交代碼變動;
  • 觸發一個構建流程;
  • 進行鏡像構建(docker build);
    鏡像鏡像推送(docker push);
  • 進行鏡像掃描(利用鏡像倉庫內置掃描工具進行);
  • 進行鏡像部署(docker run)。

這種流程有諸多弊端:

  • 掃描滯後

鏡像的掃描依賴於鏡像倉庫自帶的鏡像掃描功能,只有鏡像推送至鏡像倉庫纔會進行鏡像掃描,這種滯後的掃描會致使倉庫中保存有漏洞的鏡像。在DevSecOps中,但願作到的是:鏡像倉庫中存儲的是安全的、可隨時部署的鏡像。

  • 不能有效的終止CI/CD流程

成熟的DevSecOps CI/CD 應該是:當檢測到鏡像是不安全的,那麼就應該當即終止CI/CD流程,防止不安全的鏡像被部署到環境中。這種依賴於鏡像倉庫自帶掃描功能的滯後鏡像掃描,沒有辦法作到這一點,由於鏡像推送以後的掃描,和鏡像的部署是同時進行的。

  • 浪費資源

鏡像是要佔據必定的磁盤空間的(有些鏡像大小上百M,甚至上G),在鏡像倉庫中保存有大量有漏洞的鏡像,就會佔據大量的磁盤空間,使倉庫的使用成本上升。

3、鏡像掃描前置

基於掃描滯後的不足,鏡像掃描的前置就顯得尤其重要了,將鏡像掃描的操做前置(以下圖綠色虛線方框所示):

image.png

讓其位於鏡像構建以後,鏡像推送以前,這樣一旦一個鏡像掃描結束,若是其結果是安全的,那麼就順利進行後續的操做(推送至鏡像倉庫並進行鏡像部署);若是掃描結果是不安全的,那麼就當即終止該CI/CD流程,並通知相應的人員。這樣就防止了不安全鏡像推送至鏡像倉庫。保證鏡像倉庫中存儲的鏡像都是安全的,並且節省了磁盤空間。同時,前置掃描對鏡像的操做空間會變得更大,好比能夠對鏡像作一些黑白名單、RBAC(Role Based Access Control)權限控制等。

對於前置的鏡像掃描操做,就須要藉助一些現有的鏡像掃描工具來幫助咱們完成這個操做。這些工具既有你們耳熟能詳的Clair,也有一些新貴好比Anchore,Trivy等,關於這些工具的具體使用和對比,會在後期有有一篇專門的文章來分析。

鏡像掃描只是幫助咱們,發現鏡像問題,而後解決鏡像問題,這只是鏡像問題的治療手段,然而對於鏡像問題,最好是要作到防止問題發生,也就是在構建鏡像的時候,儘量的根據一些最佳實踐來構建一些儘可能安全的鏡像,這也就是咱們接下來要講的鏡像安全的一些最佳實踐。這樣經過預防爲主,防治結合(防:根據最佳實踐構建安全鏡像;治:嵌入CI/CD中的前置鏡像掃描)的方法來確保鏡像的安全。

4、容器鏡像安全最佳實踐

4.1 儘可能選擇輕量的基礎鏡像

每一個鏡像都有一個基礎鏡像,也就是在 Dockerfile中的 FROM 中指定的鏡像,通常這個基礎鏡像就是一個Linux發行版,好比alpine,ubuntu等。在爲一個新項目選取基礎鏡像的時候,應該考慮這個項目的運行是否須要一個全量的操做系統(包含各類庫),若是說alpine就能能知足要求,就不要選擇ubuntu這個相對龐大的操做系統,做爲新項目的基礎鏡像。不一樣量級的操做系統,除了有鏡像大小的區別,更重要的是,操做系統包含的文件系統越多,攻擊面也就越大,包含的漏洞也就越多。

用Anchore對 openjdk:8-jdk-alpine和openjdk:8-jdk進行掃描,結果顯示openjdk:8-jdk有128個漏洞,而openjdk:8-jdk-alpine卻只有48個。並且openjdk:8-jdk-alpine的鏡像大小僅爲openjdk:8-jdk的三分之一不到。

image.png

4.2 添加非root用戶,以最小受權用戶運行容器

容器是和宿主機共享內核的,若是以root用戶啓動容器,也就意味着容器是有root權限去操做宿主機,這樣就使得宿主機的受攻擊面增大,潛在威脅係數提升。所以,應該指定一個非root的特定用戶,而後以此特定用戶來啓動容器。若是是經過Dockerfile的方式來構建鏡像,能夠在Dockerfile中添加以下代碼,來添加一個位於特定group的特定用戶,並以此特定用戶來啓動容器:

FROM your_base_image
RUN groupadd -r  devsecops && useradd -r  -g devops devsecops
USER devsecops
......(your other dockerfile steps)

4.3 不要將敏感信息暴漏在鏡像中

不要將token,密碼,ssh key等敏感信息,存儲在鏡像中,一旦鏡像被推送至公共鏡像倉庫,那麼就會形成上述敏感信息的泄漏。結果將是災難性的。若是在鏡像中必需要用到一些敏感信息,能夠採用docker提供的secret功能,或者經過多階段構建來完成。具體的使用能夠參考docker官網。

4.4 不要安裝不須要的包

不少鏡像中都經過"apt-get update && apt-get install xxx" 或者"yum update && yum install xxx"的方式來安裝軟件包,可是切記:只安裝與應用程序運行有關的包,不要安裝非必須的包。好比在數據庫鏡像中安裝vim。安裝的包越多,鏡像的複雜性就越高,依賴也越多,不只致使容器鏡像的體積變大,還使得鏡像的受攻擊面變大,安全性下降。

當以ubuntu:16.04爲基礎鏡像時,執行 "apt-get update && apt-get install vim telnet curl -y"命令和不執行此命令的鏡像,其漏洞數量和鏡像體積都是不同的。詳細對好比下圖。

image.png

4.5 對Dockerfile進行掃描

能夠用Dockerfile掃描工具(好比Hadolint)來對Dockerfile來進行掃描,以發現Dockerfile中的不規範寫法或者一些可能引發安全問題的構建命令。好比用Hadolint掃描以下的Dockerfile:

FROM alpine
RUN apk add busybox-extras

能夠看到以下輸出結果:

/dev/stdin:1 DL3006 Always tag the version of an image explicitly
/dev/stdin:2 DL3018 Pin versions in apk add. Instead of `apk add <package>` use `apk add <package>=<version>`
/dev/stdin:2 DL3019 Use the `--no-cache` switch to avoid the need to use `--update` and remove `/var/cache/apk/*` when done installing packages

結果提示,基礎鏡像(alpine)應該要指定tag(DL3006提示所示),安裝包時(apk add) 要指定包(busybox-extras)的版本(DL3018提示所示)。

4.6 不要選取未知來源且沒有維護的鏡像

當選取基礎鏡像時,不要選取來源未知(不知道這個鏡像的做者是何方神聖,不知道Dockerfile的內容,不知道基礎鏡像的內容)、中止維護(最後一次更新是幾個月甚至幾年前,這段時間積累了多少問題,天知道)的鏡像。由於不能肯定鏡像中包含的內容是不是安全的。更不要僅以鏡像被拉取的次數、Star數量做爲指標來決定是否使用鏡像,由於這個次數是能夠被刷上去的。必定要儘可能選取官方的、Dockerfile內容明確的,更新頻繁的鏡像,若是沒有符合條件的鏡像,能夠嘗試本身製做鏡像。

上述幾點只是構建安全、規範鏡像的一部分手段,本文只是列出來一些重要,並且常見的。其餘還有諸如使用鏡像簽名來防止鏡像被篡改、構建受信的鏡像倉庫並經過RBAC和黑名單等機制來對鏡像的拉取和推送等作權限控制等手段來進一步保證鏡像的安全。限於篇幅,本文再也不進一步深刻探討,感興趣的,能夠深刻進行研究。

5、總結

沒有絕對的安全,也沒有一勞永逸的安全,只有永不止步的行動。鏡像掃描只是經過工具幫助咱們來發現安全問題,而後去有目標的解決問題,屬於一種治療手段;可以未雨綢繆,預防問題的發生纔是最重要的,因此,應該養成良好的習慣:從安全的角度出發,結合上述的最佳實踐,來構建安全,規範的鏡像。以"預防爲主,防治結合"的方式來進一步確保鏡像的安全。

來源:CIO Talk

做者:馬景賀

馬景賀,人稱小馬哥,曾作過LTE 4G網絡協議開發,後轉向DevOps,對於Cloud Native DevSecOps進行佈道,喜歡研究docker,kubernetes,istio等Cloud Native相關技術,樂於分享,運營着DevOps SIG公衆號。在大連DevOps社區活動上,舉辦DevOps Workshop活動。

參考資料

5月每週四晚8點,【冬哥有話說】質量與測試專場。公衆號留言「質量」可獲取地址

  • 0506 朱少民 《如何最大化軟件測試效能》
  • 0513 陳琦 《數據驅動測試》
  • 0520 陳霽 《沒錯,去QA是提升質量最有效的方法!》
  • 0527 施慧斌 《DevOps實踐之持續測試》
相關文章
相關標籤/搜索