クラウドエンジニアブログ

Azure Pipelines で脆弱性スキャナー Trivy の使い方を検証してみた

佐藤 実

佐藤 実

こんにちは。 CI/CD を含むクラウドインフラの構築や技術支援を担当している、クラウドエンジニアの佐藤です。

突然ですが、Apache Log4j の脆弱性、皆さまの記憶に新しいのではないでしょうか?

自社の開発しているアプリ、または自社が使っているアプリに Apache Log4j ライブラリは使われているのか?使われているとして脆弱性のあるバージョンなのか?を急いで調べ、暫定対応や恒久対応を実施された事と思います。

私は以前、アプリ開発もしていました。バグや脆弱性は下流工程で問題が発生してから修正する工数より、上流工程で対応した方が工数が少なくて済みます。

そこで、上流工程にあたる Azure Pipelines の CI パイプラインに脆弱性スキャナーを組み込みます。コードがプッシュされる度にその時点の脆弱性情報データベースから対象のライブラリやパッケージを使っていないか自動的に検査する仕組みにします。

組み込む脆弱性スキャナーは、Trivy を使ってみたいと思います。私自身セキュリティーは専門外なので、他にもたくさんの脆弱性スキャナーはあると思います。

ちなみに、私の認識として Trivy は、オープンソースでコンテナーイメージの脆弱性をスキャンするお手軽なツールだと思っていました。ところが、Trivy のドキュメントを読むと、プログラミング言語のライブラリやパッケージの脆弱性もスキャンできるそうです。

という事で、インフラ構築目線ではありますが、Azure Pipelines で脆弱性スキャナー Trivy の使い方を検証してみました。


簡単な検証用アプリを作りローカルで Trivy を使ってみる

dotnet を使って、簡単な検証用アプリを作成します。
私の開発環境は .NET 7 がインストール済みです。
「 trivydemoapp 」という名前でアプリを作成し、ビルドが通る事を確認します。

$ dotnet --version
7.0.100

$ dotnet new mvc --name trivydemoapp

$ cd trivydemoapp

$ dotnet build


Installing Trivy のドキュメントを参考に Trivy をインストールします。
私の開発環境は「 Install from GitHub Release (Official) 」の方法でインストールしました。
インストールするバージョンは、現時点で最新のものを使用しました。 ※ Releases · aquasecurity/trivy

$ curl -LO https://github.com/aquasecurity/trivy/releases/download/v0.37.2/trivy_0.37.2_Linux-64bit.tar.gz

$ tar -xzf trivy_0.37.2_Linux-64bit.tar.gz

$ sudo mv trivy /usr/local/bin/

$ rm trivy_0.37.2_Linux-64bit.tar.gz


必要最小限のコマンドラインオプションで Trivy を実行してみます。
「 Downloading DB... 」と表示され DB をダウンロードしているのが確認できます。

$ trivy fs .
2023-02-14T01:32:28.344Z        INFO    Need to update DB
2023-02-14T01:32:28.344Z        INFO    DB Repository: ghcr.io/aquasecurity/trivy-db
2023-02-14T01:32:28.344Z        INFO    Downloading DB...
35.62 MiB / 35.62 MiB [-------------------------------------------------------------------------] 100.00% 22.60 MiB p/s 1.8s
2023-02-14T01:32:31.550Z        INFO    Vulnerability scanning is enabled
2023-02-14T01:32:31.550Z        INFO    Secret scanning is enabled
2023-02-14T01:32:31.550Z        INFO    If your scanning is slow, please try '--scanners vuln' to disable secret scanning
2023-02-14T01:32:31.550Z        INFO    Please see also https://aquasecurity.github.io/trivy/v0.37/docs/secret/scanning/#recommendation for faster secret detection
2023-02-14T01:32:39.617Z        INFO    Number of language-specific files: 0


あえて脆弱性のあるパッケージのバージョンを使ってみます。
使うパッケージは「 Newtonsoft.Json 」のバージョン「 12.0.1 」です。

$ dotnet add package Newtonsoft.Json -v 12.0.1

$ dotnet list package
Project 'trivydemoapp' has the following package references
   [net7.0]: 
   Top-level Package      Requested   Resolved
   > Newtonsoft.Json      12.0.1      12.0.1  

$ dotnet build


再度 Trivy を実行します。
Newtonsoft.Json ライブラリは、Severity が「 HIGH 」、Fixed Version が「 13.0.1 」という脆弱性スキャン結果が表示されています。

$ trivy fs .
2023-02-14T01:34:05.019Z        INFO    Vulnerability scanning is enabled
2023-02-14T01:34:05.019Z        INFO    Secret scanning is enabled
2023-02-14T01:34:05.019Z        INFO    If your scanning is slow, please try '--scanners vuln' to disable secret scanning
2023-02-14T01:34:05.019Z        INFO    Please see also https://aquasecurity.github.io/trivy/v0.37/docs/secret/scanning/#recommendation for faster secret detection
2023-02-14T01:34:12.936Z        INFO    Number of language-specific files: 1
2023-02-14T01:34:12.936Z        INFO    Detecting dotnet-core vulnerabilities...

bin/Debug/net7.0/trivydemoapp.deps.json (dotnet-core)

Total: 1 (UNKNOWN: 0, LOW: 0, MEDIUM: 0, HIGH: 1, CRITICAL: 0)
┌─────────────────┬─────────────────────┬──────────┬───────────────────┬───────────────┬───────────────────────────────────────────────────┐
│     Library     │    Vulnerability    │ Severity │ Installed Version │ Fixed Version │                       Title                       │
├─────────────────┼─────────────────────┼──────────┼───────────────────┼───────────────┼───────────────────────────────────────────────────┤
│ Newtonsoft.Json │ GHSA-5crp-9r3c-p9vr │ HIGH     │ 12.0.1            │ 13.0.1        │ Improper Handling of Exceptional Conditions in    │
│                 │                     │          │                   │               │ Newtonsoft.Json                                   │
│                 │                     │          │                   │               │ https://github.com/advisories/GHSA-5crp-9r3c-p9vr │
└─────────────────┴─────────────────────┴──────────┴───────────────────┴───────────────┴───────────────────────────────────────────────────┘


Fixed Version である「 13.0.1 」に変更して、脆弱性スキャンの結果を確認します。
脆弱性の解消が確認できました。

$ dotnet add package Newtonsoft.Json -v 13.0.1

$ dotnet list package
Project 'trivydemoapp' has the following package references
   [net7.0]: 
   Top-level Package      Requested   Resolved
   > Newtonsoft.Json      13.0.1      13.0.1  

$ dotnet build

$ trivy fs .
2023-02-14T01:35:31.850Z        INFO    Vulnerability scanning is enabled
2023-02-14T01:35:31.850Z        INFO    Secret scanning is enabled
2023-02-14T01:35:31.850Z        INFO    If your scanning is slow, please try '--scanners vuln' to disable secret scanning
2023-02-14T01:35:31.850Z        INFO    Please see also https://aquasecurity.github.io/trivy/v0.37/docs/secret/scanning/#recommendation for faster secret detection
2023-02-14T01:35:39.652Z        INFO    Number of language-specific files: 1
2023-02-14T01:35:39.652Z        INFO    Detecting dotnet-core vulnerabilities...


後ほど、Azure Pipelines で Trivy の脆弱性スキャン結果を確認するため、あえて脆弱性のあるバージョンに戻しておきます。

$ dotnet add package Newtonsoft.Json -v 12.0.1

Azure DevOps に Trivy エクステンションをインストールする

Azure DevOps の「 Organization Settings 」から「 Extensions 」を開きます。
「 Browse marketplace 」をクリックします。


検索ボックスに「 trivy 」を入力して検索します。
Aqua Security の「 trivy 」をクリックします。


「 Get it free 」をクリックします。


「 Install 」をクリックします。


「 Proceed to organization 」をクリックします。


Azure DevOps の「 Organization Settings 」から「 Extensions 」を開きます。
「 trivy by Aqua Security 」が表示されているのを確認します。

CI パイプラインを作って Trivy の動作を確認する

ローカルにある検証用アプリを Azure Repos の Git リポジトリにプッシュします。

$ dotnet new gitignore

$ git init

$ git add -A

$ git commit -m "first commit"

$ git branch -m main

$ az repos create \
  --org https://dev.azure.com/ceblog/ \
  --project ceblog \
  --name trivydemoapp

$ git remote add origin https://ceblog@dev.azure.com/ceblog/ceblog/_git/trivydemoapp

$ git push -u origin --all

Git リポジトリにプッシュできました。


Azure DevOps Pipelines Task for Trivy のドキュメントを参考に Azure Pipelines の YAML を作成します。
ファイル名は「 azure-pipelines.yml 」です。

trigger:
- main

pool:
  vmImage: ubuntu-latest

steps:
- task: UseDotNet@2
  inputs:
    version: 7.x
- task: DotNetCoreCLI@2
  displayName: DotNetBuild
  inputs:
    command: build
- task: trivy@1
  inputs:
    path: .


azure-pipelines.yml を Git リポジトリにプッシュします。

$ git add -A

$ git commit -m "add azure-pipelines.yml"

$ git push


Azure Pipelines を作成すると自動的に CI パイプラインが動き出します。

$ az pipelines create \
  --name trivydemoapp-ci \
  --repository trivydemoapp \
  --repository-type tfsgit \
  --yml-path azure-pipelines.yml


CI パイプラインの詳細を確認すると「 trivy 」タスクが失敗しています。
ログを確認すると「 docker run 」や「 aquasec/trivy:latest 」と表示されているので、Docker コンテナーで Trivy が実行されている事がわかります。
「 20230214.1 」をクリックします。


「 #20230214.1 」の左側に赤のバツアイコンが表示されています。
「 Trivy 」タブをクリックします。


Newtonsoft.Json ライブラリは、Severity が「 HIGH 」である事がわかります。
ID 列の「 GHSA... 」をクリックします。


Patched versions で「 13.0.1 」が確認できます。
CVSS が 10 段階で「 7.5 」である事が確認できます。
ちなみに Apache Log4j の時は 10 段階で 10 でした。 ※ Remote code injection in Log4j · CVE-2021-44228


例えば、ある組織やチームでは、脆弱性スキャンは情報として扱い、CI パイプラインは止めたくない場合があったりします。
Trivy のオプションに「 exitCode 」があるので、値を「 0 」にして再度 CI パイプラインを動かしてみます。
azure-pipelines.yml の一番最後に「 exitCode: 0 」を追加します。

trigger:
- main

pool:
  vmImage: ubuntu-latest

steps:
- task: UseDotNet@2
  inputs:
    version: 7.x
- task: DotNetCoreCLI@2
  displayName: DotNetBuild
  inputs:
    command: build
- task: trivy@1
  inputs:
    path: .
    exitCode: 0


azure-pipelines.yml を Git リポジトリにプッシュします。

$ git add -A

$ git commit -m update

$ git push


CI パイプラインの詳細を確認すると「 trivy 」タスクが成功しています。
「 20230214.2 」をクリックします。


「 #20230214.2 」の左側に緑のチェックアイコンが表示されています。
「 Trivy 」タブをクリックします。
最初に実行した CI パイプラインと同様に Newtonsoft.Json の脆弱性スキャンの結果が表示されています。

エクステンションを使わずに Trivy を CI パイプラインに組み込む

Azure Pipelines の Trivy エクステンションを追加する GUI を見ると、trivy コマンドラインのオプションが少ない事がわかります。


azure-pipelines.yml の trivy タスクを Bash タスクに変更して、ローカルで trivy をインストールしたのと同じように組み込みます。

trigger:
- main

pool:
  vmImage: ubuntu-latest

steps:
- task: UseDotNet@2
  inputs:
    version: 7.x
- task: DotNetCoreCLI@2
  displayName: DotNetBuild
  inputs:
    command: build
- task: Bash@3
  inputs:
    targetType: inline
    script: |
      curl -LO https://github.com/aquasecurity/trivy/releases/download/v0.37.2/trivy_0.37.2_Linux-64bit.tar.gz
      tar -xzf trivy_0.37.2_Linux-64bit.tar.gz -C /tmp/
      /tmp/trivy fs .


azure-pipelines.yml を Git リポジトリにプッシュします。

$ git add -A

$ git commit -m update

$ git push


CI パイプラインの詳細を確認すると「 Bash 」タスクが成功しています。
ローカルで Trivy を実行した時のように、脆弱性スキャンの結果が表示されています。
「 20230214.3 」をクリックします。


Trivy をコマンドラインで実行したので、赤枠のところに「 Trivy 」タブがありません。

Trivy の脆弱性スキャン結果を CI パイプラインの結果タブに表示する

Trivy コマンドラインは、実行結果を SARIF (Static Analysis Results Interchange Format) 形式で出力する事ができます。
SARIF を「 Scans 」タブとして表示できるエクステンションを Azure DevOps に追加します。
Marketplace から「 sarif 」を検索し、「 SARIF SAST Scans Tab 」をクリックします。


「 Get it free 」をクリックします。


「 Install 」をクリックします。


Azure DevOps の「 Organization Settings 」から「 Extensions 」を開きます。
「 SARIF SAST Scans Tab 」が表示されているのを確認します。


azure-pipelines.yml の Bash タスクで SARIF ファイル出力「 --format sarif --output trivy-results.sarif 」を追加します。
PublishBuildArtifacts タスクを追加します。
「 CodeAnalysisLogs 」という名前の ArtifactName に SARIF ファイルを登録します。

trigger:
- main

pool:
  vmImage: ubuntu-latest

steps:
- task: UseDotNet@2
  inputs:
    version: 7.x
- task: DotNetCoreCLI@2
  displayName: DotNetBuild
  inputs:
    command: build
- task: Bash@3
  inputs:
    targetType: inline
    script: |
      curl -LO https://github.com/aquasecurity/trivy/releases/download/v0.37.2/trivy_0.37.2_Linux-64bit.tar.gz
      tar -xzf trivy_0.37.2_Linux-64bit.tar.gz -C /tmp/
      /tmp/trivy fs --format sarif --output trivy-results.sarif . 
- task: PublishBuildArtifacts@1
  inputs:
    PathtoPublish: trivy-results.sarif
    ArtifactName: CodeAnalysisLogs


azure-pipelines.yml を Git リポジトリにプッシュします。

$ git add -A

$ git commit -m update

$ git push


CI パイプラインの詳細を確認すると「 Bash 」タスクが成功しています。
SARIF ファイルを出力したため、Trivy コマンドライン実行時に表示された脆弱性スキャンの結果が表示されなくなりました。 「 20230214.4 」をクリックします。


「 Scans 」タブをクリックします。
Newtonsoft.Json の脆弱性スキャンの結果が表示されています。

まとめ

  • Trivy エクステンションで手軽にライブラリやパッケージの脆弱性スキャンができる事がわかりました。
  • Trivy のコマンドライン実行方法も試し、より細かくオプション指定できる事がわかりました。
  • エクステンションでもコマンドライン実行でも、CI パイプラインの結果タブにスキャン結果を表示する事ができました。

CI パイプラインでコードの静的解析や E2E テストを組み込む例は多いと思います。今回検証したライブラリやパッケージの脆弱性スキャンも CI パイプラインに組み込んでみてはいかがでしょうか?

このブログ記事が誰かの何かの参考になればうれしいです。 最後まで読んで頂き、ありがとうございます。

お問い合わせ

製品・サービスに関するお問い合わせはお気軽にご相談ください。

ピックアップ

セミナー情報
クラウドエンジニアブログ
clouXion
メールマガジン登録