GitHub Actions+TrivyでECR上のイメージを脆弱性診断したい

## Trivyってなに？

手軽に脆弱性スキャンが行えるツール。Docker Imageとかいい感じにスキャンできる。
Github Actionsと組み合わせて、手軽に定期実行できそうだと思ったので色々調べた。

## Macへのインストール方法

闇雲に入れるのもいいが、手元で確認したかったのローカルにもインストールした。

```bash
% brew install trivy
```

## 動作確認

```bash
% trivy image node:16-alpine
% trivy image awesome-app
```

### before

「node:16-alpine」を対象にスキャンかけたら脆弱性が確認できた。

```bash
❯ trivy image node:16-alpine
2021-10-05T07:42:09.462Z        INFO    Detected OS: alpine
2021-10-05T07:42:09.462Z        INFO    Detecting Alpine vulnerabilities...
2021-10-05T07:42:09.466Z        INFO    Number of language-specific files: 0

node:16-alpine (alpine 3.13.5)
==============================
Total: 5 (UNKNOWN: 0, LOW: 0, MEDIUM: 0, HIGH: 2, CRITICAL: 3)

+--------------+------------------+----------+-------------------+---------------+---------------------------------------+
|   LIBRARY    | VULNERABILITY ID | SEVERITY | INSTALLED VERSION | FIXED VERSION |                 TITLE                 |
+--------------+------------------+----------+-------------------+---------------+---------------------------------------+
| apk-tools    | CVE-2021-36159   | CRITICAL | 2.12.5-r0         | 2.12.6-r0     | libfetch before 2021-07-26, as        |
|              |                  |          |                   |               | used in apk-tools, xbps, and          |
|              |                  |          |                   |               | other products, mishandles...         |
|              |                  |          |                   |               | -->avd.aquasec.com/nvd/cve-2021-36159 |
+--------------+------------------+          +-------------------+---------------+---------------------------------------+
| libcrypto1.1 | CVE-2021-3711    |          | 1.1.1k-r0         | 1.1.1l-r0     | openssl: SM2 Decryption               |
|              |                  |          |                   |               | Buffer Overflow                       |
|              |                  |          |                   |               | -->avd.aquasec.com/nvd/cve-2021-3711  |
+              +------------------+----------+                   +               +---------------------------------------+
|              | CVE-2021-3712    | HIGH     |                   |               | openssl: Read buffer overruns         |
|              |                  |          |                   |               | processing ASN.1 strings              |
|              |                  |          |                   |               | -->avd.aquasec.com/nvd/cve-2021-3712  |
+--------------+------------------+----------+                   +               +---------------------------------------+
| libssl1.1    | CVE-2021-3711    | CRITICAL |                   |               | openssl: SM2 Decryption               |
|              |                  |          |                   |               | Buffer Overflow                       |
|              |                  |          |                   |               | -->avd.aquasec.com/nvd/cve-2021-3711  |
+              +------------------+----------+                   +               +---------------------------------------+
|              | CVE-2021-3712    | HIGH     |                   |               | openssl: Read buffer overruns         |
|              |                  |          |                   |               | processing ASN.1 strings              |
|              |                  |          |                   |               | -->avd.aquasec.com/nvd/cve-2021-3712  |
+--------------+------------------+----------+-------------------+---------------+---------------------------------------+
```

### after

アップデートしたら0件になったのが確認できた。

```bash
❯ docker pull node:16-alpine
〜略〜

❯ trivy image node:16-alpine
2021-10-05T07:43:57.359Z        INFO    Detected OS: alpine
2021-10-05T07:43:57.359Z        INFO    Detecting Alpine vulnerabilities...
2021-10-05T07:43:57.361Z        INFO    Number of language-specific files: 0

node:16-alpine (alpine 3.13.6)
==============================
Total: 0 (UNKNOWN: 0, LOW: 0, MEDIUM: 0, HIGH: 0, CRITICAL: 0)
```

## ECR向けにGithub Actionsを実行

### ENV設定

Settingsタブ→Secretsに下記を設定

- AWS_ACCESS_KEY_ID
- AWS_SECRET_ACCESS_KEY
- AWS_ECR_REPO_NAME
- SLACK_WEBHOOK

### 設定ファイルをリポジトリに設置

下記設定でやってることを簡単に書くとこんなかんじ

- masterへのpush / cronで定期実行
- 本番稼働しているECRが対象
- スキャンして何かあったらIssue上げる

実行タイミングとスキャンする対象は適宜確認いただくとして、実装が多めならPR時にチェック、運用メインで安定してるならリリースされてるイメージをスキャンしていくといいかも。
後者でいいかなと思ったので、リリースされているイメージ向けにチェックすることにした。

```yaml:.github/workflows/trivy.yml
name: Scan ECR by Trivy

on:
  push:
    branches:
    - master
  pull_request:
  schedule:
    - cron: '0 0 * * 1'

jobs:
  build:
    name: Build
    runs-on: ubuntu-18.04
    steps:
      - name: Checkout code
        uses: actions/checkout@v2

      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v1
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: ap-northeast-1

      - name: Login to Amazon ECR
        id: login-ecr
        uses: aws-actions/amazon-ecr-login@v1

      - name: pull image to Amazon ECR
        id: pull-image
        env:
          ECR_REGISTRY: ${{ steps.login-ecr.outputs.registry }}
          ECR_REPOSITORY: ${{ secrets.AWS_ECR_REPO_NAME }}
          IMAGE_TAG: ${{ (github.ref  == 'refs/heads/master' && 'latest') || 'staging' }}
        run: |
          docker pull $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG
          docker tag $ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG test-ci
          echo "::set-output name=image::$ECR_REGISTRY/$ECR_REPOSITORY:$IMAGE_TAG"

      - uses: homoluctus/gitrivy@v1.0.0
        with:
          image: test-ci
          issue: 'true'
          token: ${{ secrets.GITHUB_TOKEN }}

      - uses: 8398a7/action-slack@v3
        if: failure()
        with:
          status: ${{ job.status }}
          fields: repo,message,commit,author,action,eventName,ref,workflow,job,took
        env:
          GITHUB_TOKEN: ${{ github.token }}
          SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }}
```

## Issuesサンプル
![スクリーンショット 2021-10-06 17.31.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3442/4231257f-b8ed-e434-4059-bced8262eb9c.png)