継続は力なり

タイトル通り定期的な更新を心掛けるブログです。

カスタムルールを設定して Terraform のコードを tfsec で解析する

タダです.

業務の中で tfsec を使う機会があり,tfsecを使って,デフォルトのルールにない条件で解析を行うような仕組み化をやったのでこの記事でどういうことをやったのかをまとめていきます.

github.com

tfsec とは

tfsec は Aqua Security 社が開発している Terraform の静的セキュリティチェックを行い,潜在的なセキュリティ脅威を分析するのに寄与するツールです.

tfsec uses static analysis of your terraform templates to spot potential security issues. Now with terraform CDK support.

tfsec の導入

tfsecbrew で導入できます.その他の方法についてはこちらを参照ください.また,コンテナイメージも提供されています.

❯❯❯ brew install tfsec

tfsec のオプションとして次のものがあります.基本的なコマンドは tfsec . で実行できます.

❯❯❯ tfsec --help                                                                              
tfsec is a simple tool to detect potential security vulnerabilities in your terraformed infrastructure.

Usage:
  tfsec [directory] [flags]

Flags:
      --concise-output               Reduce the amount of output and no statistics
      --config-file string           Config file to use during run
      --custom-check-dir string      Explicitly the custom checks dir location
      --debug                        Enable debug logging (same as verbose)
  -G, --disable-grouping             Disable grouping of similar results
  -e, --exclude string               Provide comma-separated list of rule IDs to exclude from run.
      --exclude-downloaded-modules   Remove results for downloaded modules in .terraform folder
      --exclude-path strings         Folder path to exclude, can be used multiple times and evaluated in order of specification
      --filter-results string        Filter results to return specific checks only (supports comma-delimited input).
      --force-all-dirs               Don't search for tf files, include everything below provided directory.
  -f, --format string                Select output format: default, json, csv, checkstyle, junit, sarif. To use multiple formats, separate with a comma and specify a base output filename with --out. A file will be written for each type. The first format will additionally be written stdout.
  -h, --help                         help for tfsec
      --ignore-hcl-errors            Stop and report an error if an HCL parse error is encountered
      --include-ignored              Include ignored checks in the result output
      --include-passed               Include passed checks in the result output
      --migrate-ignores              Migrate ignore codes to the new ID structure
      --no-color                     Disable colored output (American style!)
      --no-colour                    Disable coloured output
  -O, --out string                   Set output file. This filename will have a format descriptor appended if multiple formats are specified with --format
      --run-statistics               View statistics table of current findings.
      --single-thread                Run checks using a single thread
  -s, --soft-fail                    Runs checks but suppresses error code
      --tfvars-file strings          Path to .tfvars file, can be used multiple times and evaluated in order of specification
      --update                       Update to latest version
      --verbose                      Enable verbose logging (same as debug)
  -v, --version                      Show version information and exit
  -w, --workspace string             Specify a workspace for ignore limits (default "default")

tfsec で提供されているチェックのルールセットには次のものがあり,どのようなチェックを行っているかはこのページから確認できます.今回は AWS Checks を使います.

tfsec 実行

tfsec 導入後に,試しに AWS の Terraform コードのディレクトリで tfsec . で実行してみると,tfsecのルールセットから違反したコードの箇所が指摘されて出力されます.出力結果から組織的に無視していいものや要対応のものを整理していくことになると思います.無視するときは個別のコードの中で無視するものを設定します.

tfsec .                                                              

Results #1-2 CRITICAL Security group rule allows egress to multiple public internet addresses. (2 similar results)
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
 hoge/xx.tf Line 41
───────┬────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
   37  │   egress {
   38  │     from_port   = 0
   39  │     to_port     = 0
   40  │     protocol    = "-1"
   41  │     cidr_blocks = ["0.0.0.0/0"]
   42}
───────┴────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
  Individual Causes
  - /Users/tady/hoge/xx.tf:25-47 (xxx.xx)
  - /Users/tady/hoge/xx.tf:1-6 (xxx.xx)
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
          ID aws-vpc-no-public-egress-sgr
      Impact Your port is egressing data to the internet
  Resolution Set a more restrictive cidr range

  More Information
  - https://aquasecurity.github.io/tfsec/v1.6.2/checks/aws/vpc/no-public-egress-sgr/
  - https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group
────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────

~中略~

  timings
  ──────────────────────────────────────────
  disk i/o             6.723876ms
  parsing              15.561457ms
  adaptation           2.028416ms
  checks               4.20521ms
  total                28.518959ms

  counts
  ──────────────────────────────────────────
  blocks               108
  modules              5
  files                46

  results
  ──────────────────────────────────────────
  ignored              0
  excluded             0
  critical             6
  high                 15
  medium               2
  low                  14

  37 potential problem(s) detected.

カスタムルールを作って GitHub Actions でチェックする

組織的にルールセットにないけどチェックしたい定義があったらカスタムルールを作って解析します..tfsecディレクトリを作り,_tfchecks.yaml_tfchecks.json を置いてくとチェックしてくれます.今回は,Terraform で管理されているリソースに必ず terraform タグを付けるようにチェックするルールにしました.

---
checks:
- code: CUS001
  description: Check if the terraform tag set for all supported resources.
  errorMessage: The required terraform tag was missing
  matchSpec:
    action: contains
    name: tags
    value: terraform
  requiredTypes:
  - resource
  requiredLabels:
  - aws_*
  severity: ERROR 

加えて GitHub Actions でプルリクエストが上がってきたときに編集したリソースが違反しているかチェックするよう reviewdog/action-tfsec で仕組み化してみます.

name: tfsec
on:
  pull_request:

jobs:
  tfsec:
    runs-on: ubuntu-latest

    steps:
      - name: checkout
        uses: actions/checkout@v3

      - name: Run tfsec with reviewdog 
        uses: reviewdog/action-tfsec@master
        with:
          github_token: ${{ secrets.github_token }}
          level: info
          working_directory: my_directory
          reporter: github-pr-review 
          fail_on_error: true
          filter_mode: nofilter

関連情報

aquasecurity.github.io

テスト実行

テスト実行をしたいので試しに セキュリティグループを追加するようなコードを書いてプルリクエストを出したとします.この状態だと terraform タグがないのでチェックに上がってきます.これでプルリクエストの段階で組織的にチェックしたいルールを仕組み化していけそうです.

resource "aws_security_group" "ecr_vpcendpoint_sg" {
  name   = "ecr-vpc-endpoint-sg"
  vpc_id = aws_vpc.tf_vpc.id

  ingress {
    from_port   = 443
    to_port     = 443
    protocol    = "tcp"
    cidr_blocks = [aws_vpc.tf_vpc.cidr_block]
  }

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = {
      Name = "ecr-vpc-endpoint-sg"
  }
}

プルリクエストでチェックされたときの例

f:id:sadayoshi_tada:20220306152235p:plain

まとめ

tfsec のカスタムチェックで組織的にルール化したいことを定義してみました.こういったガバナンスを効かせて統一的なチェックを行うのは人力では難しいと思うので,こういった仕組み化をしていけると長期的に見て良さそうだと感じました.