/dev/null

脳みそのL1キャッシュ

コンテナイメージ脆弱性スキャンツールの Trivy を使ってみた

はじめに

私が携わってる案件では ECR, ECS (Fargate) を使っていますが、コンテナイメージの脆弱性スキャンをやろうと思い ECR Image scanning を使ってみたところ、スキャンが割と雑で悩んでいました。 そこで類似ツールの Trivy を使ってみたら解決できたよという話です。

ECR Image scanning

ECR Image scanning は AWS のフルマネージドコンテナ脆弱性スキャンツールです。AWS で ECS, ECR あたりを使っている方だったら利用経験があったりするのではないでしょうか。

docs.aws.amazon.com

この ECR Image scanning は AWS マネジメントコンソールで「スキャン」ボタンをクリックするだけでお手軽に使える便利なサービスですが、使いにくい点がいくつかあります。

f:id:d2v:20201227111507p:plain

1. カーネル脆弱性を報告する

ECR image scanning は以下のようにカーネル脆弱性を報告することがありますが、Fargate を使っている場合だとそもそもホストをどうこうできないので、そんな状態でカーネル脆弱性を報告されても困るのです。

f:id:d2v:20201227111749p:plain

2. ディストリビューションで未対応の脆弱性を報告する

ディストリビューションで未対応の脆弱性を報告することもあります。例えば、Debian 10 (buster) ベースのコンテナイメージから以下の脆弱性が検出されましたが、

f:id:d2v:20201227113802p:plain

これは、現時点ではディストリビューションで未対応な脆弱性です。

f:id:d2v:20201227114017p:plain

security-tracker.debian.org

もちろん、ディストリビューションで未対応だからといって無条件で対応しなくていいというわけではありませんが、せめてディストリビューションで対応しているものと未対応のものを分けて表示してくれるともっと使いやすいのになーと思ったりします。

Trivy

Trivy は Teppei Fukuda という方が開発し、イスラエルの Aqua Security Software 社に買収されたコンテナイメージの脆弱性スキャンツールです。

github.com

Trivy には --ignore-unfixed オブションがあり、これをつけることによってディストリビューションで未対応の脆弱性を無視することができました。

試しに手元で nginx のコンテナイメージに対して --ignore-unfixed なし/ありでスキャンしてみましたが以下のような結果になりました。

オプションなし

$ trivy --severity=HIGH,CRITICAL nginx
2020-12-27T11:46:35.326+0900    WARN    You should avoid using the :latest tag as it is cached. You need to specify '--clear-cache' option when :latest image is changed
2020-12-27T11:46:39.028+0900    INFO    Detecting Debian vulnerabilities...

nginx (debian 10.5)
===================
Total: 51 (HIGH: 48, CRITICAL: 3)

+------------------+------------------+----------+-----------------------+-----------------------+--------------------------------------------------------------+
|     LIBRARY      | VULNERABILITY ID | SEVERITY |   INSTALLED VERSION   |     FIXED VERSION     |                            TITLE                             |
+------------------+------------------+----------+-----------------------+-----------------------+--------------------------------------------------------------+
| curl             | CVE-2020-8169    | HIGH     | 7.64.0-4+deb10u1      |                       | libcurl: partial password leak                               |
|                  |                  |          |                       |                       | over DNS on HTTP redirect                                    |
+                  +------------------+          +                       +-----------------------+--------------------------------------------------------------+
|                  | CVE-2020-8177    |          |                       |                       | curl: Incorrect argument check                               |
|                  |                  |          |                       |                       | can allow remote servers to                                  |
|                  |                  |          |                       |                       | overwrite local files...                                     |
+                  +------------------+          +                       +-----------------------+--------------------------------------------------------------+
|                  | CVE-2020-8231    |          |                       |                       | curl: Expired pointer                                        |
|                  |                  |          |                       |                       | dereference via multi API with                               |
|                  |                  |          |                       |                       | `CURLOPT_CONNECT_ONLY` option                                |
|                  |                  |          |                       |                       | set                                                          |
+                  +------------------+          +                       +-----------------------+--------------------------------------------------------------+
|                  | CVE-2020-8285    |          |                       |                       | curl: malicious FTP server can                               |
|                  |                  |          |                       |                       | trigger stack overflow when                                  |
|                  |                  |          |                       |                       | CURLOPT_CHUNK_BGN_FUNCTION is                                |
|                  |                  |          |                       |                       | used...                                                      |
+                  +------------------+          +                       +-----------------------+--------------------------------------------------------------+
|                  | CVE-2020-8286    |          |                       |                       | curl: inferior OCSP                                          |
|                  |                  |          |                       |                       | verification                                                 |
+------------------+------------------+          +-----------------------+-----------------------+--------------------------------------------------------------+
| gcc-8-base       | CVE-2018-12886   |          | 8.3.0-6               |                       | gcc: spilling of stack                                       |
...(snip)...

オプションあり

$ trivy --severity=HIGH,CRITICAL --ignore-unfixed=true nginx                                                                                                                                      chore/change-workflow
2020-12-27T11:46:46.067+0900    WARN    You should avoid using the :latest tag as it is cached. You need to specify '--clear-cache' option when :latest image is changed
2020-12-27T11:46:46.156+0900    INFO    Detecting Debian vulnerabilities...

nginx (debian 10.5)
===================
Total: 17 (HIGH: 17, CRITICAL: 0)

+------------------+------------------+----------+-----------------------+-----------------------+------------------------------------+
|     LIBRARY      | VULNERABILITY ID | SEVERITY |   INSTALLED VERSION   |     FIXED VERSION     |               TITLE                |
+------------------+------------------+----------+-----------------------+-----------------------+------------------------------------+
| libgssapi-krb5-2 | CVE-2020-28196   | HIGH     | 1.17-3                | 1.17-3+deb10u1        | krb5: unbounded recursion          |
|                  |                  |          |                       |                       | via an ASN.1-encoded               |
|                  |                  |          |                       |                       | Kerberos message in                |
|                  |                  |          |                       |                       | lib/krb5/asn.1/asn1_encode.c       |
|                  |                  |          |                       |                       | may lead...                        |
+------------------+------------------+          +-----------------------+-----------------------+------------------------------------+
| libjpeg62-turbo  | CVE-2020-13790   |          | 1:1.5.2-2             | 1:1.5.2-2+deb10u1     | libjpeg-turbo: heap-based          |
|                  |                  |          |                       |                       | buffer over-read in                |
|                  |                  |          |                       |                       | get_rgb_row() in rdppm.c           |
+------------------+------------------+          +-----------------------+-----------------------+------------------------------------+
...(snip)...

このように --ignore-unfixed オブションをつけるとディストリビューションで未対応の脆弱性がフィルタされて、検出件数が 51 から 17 になりました。

また、Trivy ではカーネル脆弱性を検出しなかったのですが、これは ECR Image scanning とスキャン方法が違うことに起因してるんですかねー。(強いひと教えて)

GitHub Actions のワークフローに組み込む

Trivy の GitHub Action があるので GitHub Actions で CI 環境を構築している方はすぐに導入できます。

github.com

私が携わっている案件では、以下のようなワークフローファイルを書いて、ビルドしたコンテナイメージを ECR から引っ張ってきてスキャンするようにしています。

...(sinp)...
  container-security-scan:
    needs: build
    runs-on: ubuntu-latest
    env:
      ECR_REPOSITORY_IMAGE_TAGGED: ${{ needs.build.outputs.repository_url }}
    steps:
      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v1
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY }}
          aws-secret-access-key: ${{ secrets.AWS_ACCESS_SECRET_KEY }}
          aws-region: ap-northeast-1
      - name: Login to Amazon ECR
        uses: aws-actions/amazon-ecr-login@v1
      - name: Pull Docker image
        run: |
          docker pull $ECR_REPOSITORY_IMAGE_TAGGED
      - name: Run Trivy vulnerability scanner
        uses: aquasecurity/trivy-action@master
        with:
          image-ref: ${{ env.ECR_REPOSITORY_IMAGE_TAGGED }}
          format: "table"
          exit-code: "1"
          ignore-unfixed: true
          severity: "CRITICAL,HIGH"

おわりに

今のところ Trivy には満足しています。