本番環境で稼働中のDockerイメージの脆弱性チェックを定期的に行なっていますか?
デプロイ時に脆弱性チェックをする方法はこちらの記事に書いていますが、運用フェーズに入ってからのセキュリティ対策について書いていませんでした。むしろ長い運用フェーズの方が脆弱性が多く発見されるので定期的なチェックは必須です。しかし、定期的なチェックは面倒だしコストがかかります。
そこで、GitHub ActionsとTrivyを使って手軽に定期的に脆弱性スキャンが行える方法をご紹介します。ただスキャンするだけでは運用時には辛いので、脆弱性が発見されたらGitHubのIssueが作成されるようにします。そうすれば何に対処すればいいか各リポジトリごとに管理できますし、プルリクとIssueを関連づけてプルリクがマージされたらIssueもクローズみたいな運用をすれば対応済みかどうか分かりやすくなります。
GitHub Actions
Schedule
定期的にスキャンをするのでGitHub Actionsのschedule機能を使用します。schedule機能と言っても自体はcron
です。例えば毎週月曜日の9:00(JST)にCIを回したいのであれば以下のようになります。
GitHub ActionsはUTCで動くので注意
on:
schedule:
- cron: '0 0 * * 1'
必要なコマンドのインストール
Trivyはもちろんですが、Issueを作成する上で以下のコマンドのインストールをします。
コマンド | 説明 |
---|---|
Trivy | 脆弱性スキャンコマンド |
hub | Issue作成する |
pandoc | Trivyのスキャン結果をHTMLにする |
- name: Install commands
run: |
sudo apt install apt-transport-https gnupg
wget -qO - https://aquasecurity.github.io/trivy-repo/deb/public.key | sudo apt-key add -
echo deb https://aquasecurity.github.io/trivy-repo/deb $(lsb_release -cs) main | sudo tee -a /etc/apt/sources.list.d/trivy.list
sudo apt update
sudo apt install --no-install-recommends trivy
sudo snap install hub --classic
VERSION=$(curl --silent "https://api.github.com/repos/jgm/pandoc/releases/latest" | \
grep '"tag_name":' | \
sed -E 's/.*"([^"]+)".*/\1/')
curl -L -o pandoc.deb https://github.com/jgm/pandoc/releases/download/${VERSION}/pandoc-${VERSION}-1-amd64.deb
sudo dpkg -i pandoc.deb
Dockerイメージのスキャン
Trivyでスキャンする時のオプションはこちらを参考にしてください。ここではseverity(重大度)をHIGH・CRITICALにして、脆弱性を発見したらexit codeを1にします。
- name: Scan Image
run: trivy -q --severity HIGH,CRITICAL --exit-code 1 ${IMAGE_NAME} > tmp.txt
Issueの作成
脆弱性がなければ終了し、あればIssueをあげます。その前にIssueが見やすくなるようにTextベースのファイルをHTMLに変換します。echo -e "Security Alert\n" > result.html
のSecurity Alert
がIssueのタイトル、trivyのスキャン結果は説明欄に記載、hub
コマンドの-l
オプションでsecurity
ラベルがつくようになっています。
GITHUB_TOKEN
とGITHUB_PASSWORD
に関してですが、トークンだけあればパスワードは不要とドキュメントに書いてあったのですが認証エラーになったので両方書いてあります。中身の値はどちらも同じですが...
- name: Create Issue
if: failure()
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_PASSWORD: ${{ secrets.GITHUB_TOKEN }}
run: |
pandoc tmp.txt -o tmp.html
sed -i -e "s/<pre><code>//g" tmp.html
sed -i -e "s/<\/code><\/pre>//g" tmp.html
echo -e "Security Alert\n" > result.html
cat tmp.html >> result.html
sudo chown root:root /
hub issue create -F result.html -l security
以下はテスト用にCIを走らせてみた結果です。

いい感じですね
完成形
完成形のWorkflowを書いておきます。IMAGE_NAME
とGITHUB_USER
を自身の環境に合わせて変更すれば動作するはずです。
name: Vulnerability scan
on:
schedule:
- cron: '0 0 * * 1'
env:
IMAGE_NAME: alpine:3.10.1
GITHUB_USER: homoluctus
jobs:
scan:
name: Scan images
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@master
with:
ref: master
- name: Install commands
run: |
sudo apt install apt-transport-https gnupg
wget -qO - https://aquasecurity.github.io/trivy-repo/deb/public.key | sudo apt-key add -
echo deb https://aquasecurity.github.io/trivy-repo/deb $(lsb_release -cs) main | sudo tee -a /etc/apt/sources.list.d/trivy.list
sudo apt update
sudo apt install --no-install-recommends trivy
sudo snap install hub --classic
VERSION=$(curl --silent "https://api.github.com/repos/jgm/pandoc/releases/latest" | \
grep '"tag_name":' | \
sed -E 's/.*"([^"]+)".*/\1/')
curl -L -o pandoc.deb https://github.com/jgm/pandoc/releases/download/${VERSION}/pandoc-${VERSION}-1-amd64.deb
sudo dpkg -i pandoc.deb
- name: Pull images
run: docker pull ${IMAGE_NAME}
- name: Scan Image
run: trivy -q --severity HIGH,CRITICAL --exit-code 1 ${IMAGE_NAME} > tmp.txt
- name: Create Issue
if: failure()
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_PASSWORD: ${{ secrets.GITHUB_TOKEN }}
run: |
pandoc tmp.txt -o tmp.html
sed -i -e "s/<pre><code>//g" tmp.html
sed -i -e "s/<\/code><\/pre>//g" tmp.html
echo -e "Security Alert\n" > result.html
cat tmp.html >> result.html
sudo chown root:root /
hub issue create -F result.html -l security
- name: Notify Result to Slack
uses: homoluctus/slatify@master
if: always()
with:
type: ${{ job.status }}
channel: '#general'
job_name: ':sniper: *Vulnerability Scan*'
url: ${{ secrets.SLACK_WEBHOOK }}
これで定期的な脆弱性スキャンができるようになりました。
GitHub Actionsと様々なツールを組み合わせればDevOps/DevSecOpsが簡単に実現できますので、試してみる価値はあると思います。
余裕のある方はGitHubのdependabot
、Dockerfileのリンター・スキャナであるdockle
や有料ツールが豊富ですので、多角的に脆弱性チェックをするのもありでしょう。