Gunosy Tech Blog

Gunosy Tech Blogは株式会社Gunosyのエンジニアが知見を共有する技術ブログです。

Snyk IaC + reviewdog + aquaではじめるDevSecOps

はじめに

こんにちは。技術戦略室SREチームのkoizumiです。 最近は、katoさんからオススメいただいた「スクワットの深さは人間性の深さ」という本を読み、日々スクワットに励んでいます(大嘘)。

さて、こちらの記事は Gunosy Advent Calendar 2022 の9日目になります。 昨日の記事はGunosy Tech Lab 石川さんの「リモートモブプログラミング開発の実践」でした。

本日は「Snyk IaC + reviewdog + aquaではじめるDevSecOps」と題して、CIへSnyk IaCを導入した事例についてご紹介します。

先日、私が執筆したこちらの記事でも、「Shift-Leftによるセキュリティ対策」という見出しで少しご紹介いたしました。 今回はこの部分について、より詳しくどのように実装したのかをご紹介できればと思います。

Snyk IaCとは

Snyk Infrastructure as Code (Snyk IaC)はTerraform、CloudFormation、Kubernetesなどの幅広いIaCツールに対してセキュリティスキャンを行うことができるツールです。 Snyk CLIまたはGUI(Web上)からセキュリティスキャンを実行することができ、以下のようにミスコンフィグレーションがある箇所がわかります。

弊社ではAWS Security HubとKubescapeを用いたライブ環境のセキュリティスキャン(ミスコンフィグレーションのチェックなど)を行なっております。 これに加えて、Shift-Leftを考慮して、リソースがデプロイされる前の開発工程でミスコンフィグレーションを検出し、よりセキュリティに起因する問題を事前に潰していきたいと考え、このSnyk IaCを用いたCI上でのIaC解析を導入しました。

CIでのIaC解析

弊社ではCircleCIを使っており、そのCI上からSnyk CLIによってSnyk IaCを実行することでIaC解析を行っています。 ただ、CIにSnyk IaCをそのまま組み込むのではなく、Pull Requestが作成された段階で新たに作成・変更されたTerraformファイルなどを解析し、ミスコンフィグレーションがあった場合はコメント形式で指摘事項を出力してくれるようにSnyk IaCとreviewdogを組み合わせて実装しました。 また、aquaを用いてCI上で使うSnyk CLIを楽にインストールし、かつ、楽にツールのバージョン管理をできるようにしました。

このreviewdogとaquaについての簡単な説明と、Snyk IaCとどのように組み合わせて実装したかをご紹介します。

aquaでSnyk CLIを簡単にインストール&バージョン管理

まずは、CI上でSnyk CLIを使用できるようにする必要があります。 弊社では、CIで使用するCLIツールはaquaによって管理するようにしています。

aquaとは、CLIツールをインストールするためのツールで、以下のようにインストールするCLIとそのバージョンをyamlで宣言的に定義することができます。

registries:
  - type: standard
    ref: v3.95.0 # renovate: depName=aquaproj/aqua-registry
  - name: private
    type: local
    path: registry.yaml

packages:
  - import: aqua/*.yaml

  # common
  - name: open-policy-agent/conftest@v0.35.0
  - name: suzuki-shunsuke/github-comment@v5.0.0

  # terraform
  - name: hashicorp/terraform@v1.3.4
  - name: suzuki-shunsuke/tfcmt@v4.0.0

  # helmfile
  - name: gunosy/helmfile-notify@v0.1.3
    registry: private

これにより、主に以下のようなメリットがあります。

  • CLIツールのバージョンをリポジトリで揃えられる
  • プロジェクトに必要なツールとそのバージョンをコードで宣言的に管理し、aqua iでインストールすることができる
  • Renovate で簡単にツールのバージョンアップを行える

aquaでインストールできるツールおよびそのインストール方法はRegistryで管理されています。 Standard Registryという公式のRegistryを使用すれば、そこに登録されているツールであれば自分でRegistryを書かなくても、上記のようにツール名とバージョンを指定すれば簡単にツールをインストールできます。

github.com

そこで、Snyk CLIもaquaで管理しようと思い、Standard RegistryでSnyk CLIを探してみましたが... 無い!!

ということで、Standard RegistryにSnyk CLIを追加するPRを投げました。

これにより先のyamlファイルに以下のようにsnyk/cli@v1.x.xを追加するだけで、Snyk CLIを簡単にインストールかつ管理することができました。

registries:
  - type: standard
    ref: v3.95.0 # renovate: depName=aquaproj/aqua-registry
  - name: private
    type: local
    path: registry.yaml

packages:
  - import: aqua/*.yaml

  # common
  - name: open-policy-agent/conftest@v0.35.0
  - name: suzuki-shunsuke/github-comment@v5.0.0

  # terraform
  - name: hashicorp/terraform@v1.3.4
  - name: suzuki-shunsuke/tfcmt@v4.0.0

  # snyk
  - name: snyk/cli@v1.1061.0

  # helmfile
  - name: gunosy/helmfile-notify@v0.1.3
    registry: private

ツールごとにインストール方法を考えたりする必要もなく、Renovateによりツールのバージョンアップも簡単になるので、皆様も是非導入の際は使ってみてください。

reviewdogでコメント形式の指摘を実現

このままでもCI上でSnyk CLIを実行できますが、既存のリポジトリには既に多くのTerraformファイルなどがあり、Snyk IaCの導入初期段階においてはPull Requestを作成した際に自分が作成・変更した部分とは関係のない部分で指摘がされてしまうと、その大量の指摘を解決するまでそのPull Requestをmergeすることができません。(CIが失敗したまま無理矢理mergeすることはできますが、好ましくは無いですよね)

また、Snyk CLIをCI上で実行し、何か指摘事項があってエラーとなった場合には、CircleCIのGUIにアクセスしてそのエラー内容を確認する必要がありました。

そこで、新たに作成・変更した部分でミスコンフィグレーションがあるかどうかをチェックし、コメント形式で指摘されるようにreviewdogを活用して実装しました。

reviewdogとは、linterなどのチェックツールの結果を自動でGitHubのPull Requestにコメントの形で指摘するようにできるツールです。 詳しくは、reviewdog開発者の haya14busaさんこちらの記事をご覧ください。

reviewdogを使うと、コメント形式でSnykの指摘事項を確認することができるので開発者にとって非常にわかりやすく、Developper Experience面においてとても有効だと思います。

ただ、Snyk CLIの出力フォーマットはjsonsarifが用意されていますが、reviewdogでは先の2つは受け取り可能なフォーマットとして用意されていません。

そこで、Snyk CLIの検出結果をjsonで出力し、それをjqファイルでreviewdogで受け取り可能なデータフォーマットに変換します。 今回はRDFormatというreviewdog独自のデータフォーマットに変換します。 jqファイルは以下のように作成しました。

{
  source: {
    name: "snyk",
    url: "https://github.com/snyk/cli"
  },
  diagnostics: (if type=="array" then . else [.] end | [ .[] |{issue: {file: .targetFile}, infrastructureAsCodeIssues: .infrastructureAsCodeIssues[]}| {
    message: [.infrastructureAsCodeIssues.issue + " \n " + .issue.file + (if .infrastructureAsCodeIssues.path == "" then "" else " > " + (.infrastructureAsCodeIssues.path | join(" > ")) end )] | .[],
    code: {
      value: .infrastructureAsCodeIssues.id,
      url: .infrastructureAsCodeIssues.documentation,
    },
    location: {
      path: .issue.file,
      range: {
        start: {
          line: .infrastructureAsCodeIssues.lineNumber,
        },
      }
    },
    severity: (if .infrastructureAsCodeIssues.severity == "critical" then
              "ERROR"
            elif .infrastructureAsCodeIssues.severity == "high" then
              "WARNING"
            elif .infrastructureAsCodeIssues.severity == "medium" then
              "INFO"
            elif .infrastructureAsCodeIssues.severity == "low" then
              "INFO"
            else
              null
            end),
  } ] )
}

reviewdogの設定ファイル(.reviewdog.yml)は以下のようにし、snyk iac testのJSON出力をjqファイルでRDFormatに変換します。

runner:
  snyk-iac:
    name: snyk-iac
    cmd: snyk iac test . --json | jq -f -r ./snykiac-to-rdjson.jq
    format: rdjson

あとはCIでreviewdogを実行します。 下記のようにreviewdogに関するcommand、job、workflowを追加します。 snyk iac testを行うためには、snyk authを行う必要がある点に注意してください。 CircleCIの場合は、予め使用するcontextにSNYK_TOKENを設定しておきましょう。

commands:
  snyk_auth:
    steps:
      - run: snyk auth $SNYK_TOKEN
  reviewdog:
    parameters:
      runners:
        type: string
    steps:
      - run: reviewdog -reporter="github-check" -diff="git diff FETCH_HEAD" -runners="<< parameters.runners >>"
jobs:
  reviewdog:
    executor: base
    parameters:
      runners:
        type: string
    steps:
      - checkout
      - setup:
          executor: base
      - snyk_auth
      - reviewdog:
          runners: << parameters.runners >>
workflows:
  lint:
    jobs:
      - reviewdog:
          name: trivy
          runners: trivy
          <<: *lint-context
      - reviewdog:
          name: snyk-iac
          runners: snyk-iac
          <<: *lint-context

これにより、Pull RequestをOpenにしたときに新たに作成・変更したTerraformファイル等を解析し、 Checksタブに以下の様に検出結果が表示されます。

Snyk IaCにて検出された項目をignoreしたい場合は、上記イメージの赤矢印部分の$ファイル名 > resource > hogehoge の箇所をそのままコピーして、以下のように.snykファイルにペーストするだけで簡単に指摘事項をignoreできるようになっています。

version: v1.25.0
ignore:
  SNYK-CC-TF-**:
    - '$ファイル名 > resource > hogehoge':
       reason: hogehoge

まとめ

今回はSnyk IaCをCIに導入した事例について紹介しました。

以上のように、aquaによってSnyk CLIを楽にインストール/バージョン管理できるようにし、reviewdogによって指摘事項の確認をPull Request内で完結したことにより、Developper Experienceを良い状態に保ったまま、気軽にDevSecOpsを実践することができました。

また、Snyk IaCを活用したShift-Leftによるセキュリティ対策に加えて、プロダクション環境のリソースに対するセキュリティスキャン(AWS Security Hub, Kubescapeなど)やSnyk Containerを活用したコンテナスキャンを行なっていくことも非常に重要です。 こちらについても気になる方は、先日のブログも是非読んでみてください。

Snyk Containerについては絶賛導入中であるため、運用を進めていった段階でブログにしてみようかなと思います。

次回はUTさんです!とても楽しみです!

それでは皆さん、よいお年を! :happy_new_year: (気が早い)