在 GitLab CI 中使用 Google osv-scanner

DevSecOps 議題持續熱絡,目前市面上已經有許多可以放進 CI Pipeline 中的掃描工具,既然 Google 也推出了一個新的 Vulnerability 掃描工具,我們當然一定要將它塞進 GitLab CI 試試看啊!

根據 iThome 的報導,Google 釋出了一個新的免費開源軟體漏洞掃描工具 OSV-Scanner,可以幫助開發者自動掃描找出專案內的相依套件是否存有漏洞。看見這樣的好工具,我們第一時間當然要問一句,這玩意能夠放進我們的 CI Pipeline 嗎?是否能有助於我們及早發現程式碼中潛藏的資安問題呢?

因此本文,就讓我們試著在 GitLab CI Pipeline 中運用 OSV-Scanner 吧!

操作步驟

尋找可用的 Docker Image

老樣子,想要在 GitLab CI Pipeline 中試用一個新工具的第一步,當然是先找找看有沒有現成的 Docker image 可以使用。

在今天 2023/1/1 於 Docker Hub 上搜尋「osv-scanner」,只能找到兩個看起來並非是 Google 官方建立的 Image。

這兩個 Image 看起來都沒什麼人 Download 使用,稍微深入瀏覽後,可以發現 anmalkov/osv-scanner 的說明較完整,有興趣者可以嘗試看看。

anmalkov/osv-scanner 為例,我用它來嘗試掃描了手邊的一個專案,得到如下圖的結果,它依據 package-lock.json 的資訊,幫我找出許多的 Vulnerabilities,並且每一個 Vulnerability 都會提供一個 OSV URL,讓我可以了解更多的詳細資訊。

OSV URL 的網頁內容如下,會有完整的漏洞說明。

如果你想要自己 Build 一個 Image,則可以參考 GitHub Repo - osv-scanner ,在 Repo 中有提供 Dockerfile ,可以用來 Build image。在本文,我就是參考 GitHub Repo 的 Dockerfile,自行 Build 了一個可以讓我在 GitLab CI 中使用的 Image,並上傳 Docker Hub - chengweisdocker/osv-scanner-for-ci

下面我們就快速的運用 gitlab.com 做一個簡單的 DEMO,如何在 GitLab CI 中使用 osv-scanner

準備一份乾淨的程式碼

第一步先利用 Create from template 功能,建立一個乾淨的 Project,Template 選擇 NodeJS Express

準備 GitLab Runner

既然前面我們尋找了合適的 Docker image,當然代表接下來在 CI Pipeline 中,我們打算用 Container 的方式來執行 osv-scanner。因此,老樣子請為我們剛才準備好的 Project 準備一個能夠操控 Container 的 GitLab Runner,或者你也可以直接使用 gitlab.com 提供的 Shared Runners。

(如果不打算自己架設 GitLab Runner,那就先用公用的 Shared runners 吧!但要記得這是有 Free limit 限制的喔!)

建立 .gitlab-ci.yml

接著就在我們的 Project 中新增 .gitlab-ci.yml

# .gitlab-ci.yml
osv-scanner:
  # 我當然是使用我自己做好的 image
  image: chengweisdocker/osv-scanner-for-ci
  script:
  ## set +e 是的特別的動作,下面會再說明
  - set +e
  ## 讓 osv-scanner 吐出 JSON 格式的結果,然後儲存為 .json 檔案
  - /root/osv-scanner --json -r . > osv-report.json
  ## 印出來看看
  - cat osv-report.json
  ## 將 .json 上傳為 Artifats
  artifacts:
    paths:
    - osv-report.json

在上面的 script: 中,我們有使用了一個特別的動作 set +e,這是為什麼呢?

主要是因為 GitLab CI 在執行 Job 的過程中,會是以 set -e 的方式執行動作。也就是 GitLab CI 在執行 script: 內的各種指令時,只要任何一個指令的 Exit code / Return code 不等於 0 時,GitLab CI 就會立即判定 Job failed;而偏偏 osv-scanner 如果掃描到 Project 有使用不安全的套件時,就是會回傳 Exit code / Return code = 1(如果 osv-scanner 找不到可以掃描的檔案,則是回傳 Exit code / Return code = 128 )。

因此當 GitLab CI 在執行 /root/osv-scanner --json -r . > osv-report.json 時,就會因為 Exit code = 1 而直接 failed 中斷整個 CI Job,並不會繼續執行將 osv-report.json 上傳 Job Artifacts 的動作。

(Job log 明確的指出,是因為 exit code 1 所以 failed。)

為了避開上述的問題,我們只好在 script: 一開始先執行 set +e,取消 -e 模式,這樣我們的 CI Job 才能夠產出 osv-report.json 並完成上傳 Job Artifacts。

(有了 set +e,Job 就不會 failed 而會繼續執行下去。)

(當然也就能夠順利執行上傳 Job Artifacts 的動作。)

打開 osv-report.json 可以發現被掃出滿滿的 Vulnerabilities。

小結

在今天的文章中,我們簡單的試用了 osv-scanner,並且嘗試將它塞進 GitLab CI Pipeline 中。

osv-scanner 作為一個新興的 Vulnerability 掃描工具,不僅掃描速度快速,並且能跨多種程式語言一次掃描完畢,掃描結果也能輸出為常見的 JSON 格式。以這幾點來說 osv-scanner 的表現令人滿意,如果你還沒有為 Project 套用任何 Vulnerability 掃描工具,那麼不妨試試看 osv-scanner

另外今天也順便介紹了在 GitLab CI 中設置 set +e 的作法,如果你也有不得不讓 script: 持續執行下去的需求,那麼 set +e 就是你一定要學會的小技巧。但建議大家,可以更多的認識 set ,除了 -e+e 其實還有著不同的參數,有興趣者可以找個 Linux 環境試著用 set --help 查看一下。

最後,作為上面小技巧的延伸議題,如果我們換個角度想,其實 osv-scanner 在有發現 Vulnerability 時會回傳 exit code = 1 ,反而是一件好事;舉例來說假設你想要設置一條嚴格絕對不容任何 Vulnerability 的 CI Pipeline,那麼因為 exit code = 1 必然會導致 Job failed,意味著團隊非得要修正 Project 直到能通過掃描,不然 osv-scanner 可是不會回傳 exit code = 0 的。

參考資料

工商服務

如果你覺得艦長的文章對你有產生幫助,歡迎抖內(Donate),讓我可以將養家活口的力氣分一些在社群分享。歡迎支持我的著作《和艦長一起 30 天玩轉 GitLab》(第二版,2022/12/8 出版上市)

買書不只能抖內艦長,還能一併支持出版社與圖書通路商,一次抖內一舉數得!謝謝大家。

如果你也有 Liker ID 也可以幫忙艦長按個讚。(雖然不知道這個「按讚為賞」的服務是不是還活得下去 XD)

更多文章