(本文首次發佈於 2023-01-01,於 2023-10-24 更新。)
根據 iThome 的報導,Google 釋出了一個新的免費開源軟體漏洞掃描工具 OSV-Scanner,可以幫助開發者自動掃描找出專案內的相依套件是否存有漏洞。看見這樣的好工具,我們第一時間當然要問一句,這玩意能夠放進我們的 CI Pipeline 嗎?是否能有助於我們及早發現程式碼中潛藏的資安問題呢?
因此本文,就讓我們試著在 GitLab CI Pipeline 中運用 OSV-Scanner 吧!
操作步驟
尋找可用的 Docker Image
老樣子,想要在 GitLab CI Pipeline 中試用一個新工具的第一步,當然是先找找看有沒有現成的 Docker image 可以使用。
在 2023/10/24 於 Docker Hub 上搜尋「osv-scanner」,目前都只能找到非 Google 官方建立的 Docker Image。
(截圖時間:2023/01/01)
不知為何這些 Docker 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。
或者如果你想要用偷懶一點的方式 Build image,那你只需要如下的 Dockerfile
即可。
FROM alpine:3.18
RUN apk update && apk add osv-scanner
WORKDIR /root/
在本文我就是用偷懶的方式,自行 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:1.3.3
script:
## set +e 是的特別的動作,下面會再說明
- set +e
## 讓 osv-scanner 吐出 JSON 格式的結果,然後儲存為 .json 檔案
### 2023-10-24 更新:
### 由於 osv scanner 在 1.3.3 版本依然沒有 --output 這個參數可以使用,因此只能自己存成檔案
### 但 1.3.3 版已經有提供 -f --format,並提醒參數 --json 將被棄用。
- osv-scanner -f 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 在執行 osv-scanner -f json -r . > osv-report.json
時,就會因為 Exit code = 1 而直接 failed 中斷整個 CI Job,並不會繼續執行將 osv-report.json
上傳 Job Artifacts 的動作。
(Job log 明確的指出,是因為 exit code 1
所以 failed。)(截圖日期:2023/01/01,當時還是舊版本的 osv-scanner,因此圖中是使用參數 --json
)
為了避開上述的問題,我們只好在 script:
一開始先執行 set +e
,取消 -e
模式,這樣我們的 CI Job 才能夠產出 osv-report.json
並完成上傳 Job Artifacts。
(有了 set +e
,Job 就不會 failed 而會繼續執行下去。)(截圖日期:2023/01/01,當時還是舊版本的 osv-scanner,因此圖中是使用參數 --json
)
(當然也就能夠順利執行上傳 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
的。