🌊

Trivy conifigで特定Terraformリソースの特定アラートを抑制する

2022/02/13に公開

やりたいこと

TrivyのconfigサブコマンドでTerraformのコードを静的解析したい。最初からtfsecを利用してもよいが、他にもDockerfileなども静的解析したいのでTrivyで十分であればTrivyだけで対処したい。

一方で、すべての警告に対応できるわけではないので、特定リソースにおいて特定ルールによる警告は抑制したい。同じルールでもあるリソースでは許可しても別のリソースでは許可したくないケースがあるので、指定ルールを一律で許可したくはない。また、同じリソースであってもあるルールは許可しても別のルールは許可したくないケースがあるので、指定リソースを一律で解析除外はしたくない。

Trivy v0.23.0 および tfsec v1.1.4 にて検証。

具体例

AWSのセキュリティグループで、すべての外部接続先を許可する。

network.tf
resource "aws_security_group" "sample" {
  name = "sample-sg"
  description = "sample security group"
  vpc_id = var.vpc_id

  ingress {
    description = "allow access HTTP"
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    self        = true
  }

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

このコードをtrivyで静的解析に掛けると警告を出してくれる。

$ trivy config .
2022-02-12T01:22:44.026Z	INFO	Detected config files: 1

network.tf (terraform)
=======================================
Tests: 5 (SUCCESSES: 4, FAILURES: 1, EXCEPTIONS: 0)
Failures: 1 (UNKNOWN: 0, LOW: 0, MEDIUM: 0, HIGH: 0, CRITICAL: 1)

+------------------------------------------+--------------+------------------------------------------+----------+------------------------------------------+
|                   TYPE                   |  MISCONF ID  |                  CHECK                   | SEVERITY |                 MESSAGE                  |
+------------------------------------------+--------------+------------------------------------------+----------+------------------------------------------+
|   Terraform Security Check powered by    | AVD-AWS-0103 | An inline egress security group rule     | CRITICAL | Resource 'aws_security_group.sample'     |
|                  tfsec                   |              | allows traffic to /0.                    |          | defines a fully open egress security     |
|                                          |              |                                          |          | group.                                   |
+------------------------------------------+--------------+------------------------------------------+----------+------------------------------------------+

解決策

tfsecのIgnoring specific issueを利用する。コードの対象箇所にコメントとして tfsec:ignore:RULE を記載すればその箇所での警告を抑制してくれる。

network.tf
resource "aws_security_group" "sample" {
  ...

  egress {
    description = "allow all egress connection"
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"] #tfsec:ignore:AWS009
  }
}

実行結果

$ trivy config .
2022-02-12T01:26:24.832Z	INFO	Detected config files: 1

network.tf (terraform)
=======================================
Tests: 4 (SUCCESSES: 4, FAILURES: 0, EXCEPTIONS: 0)
Failures: 0 (UNKNOWN: 0, LOW: 0, MEDIUM: 0, HIGH: 0, CRITICAL: 0)

指定するルールID

指定するルールIDとして、 trivy 実行時に警告一覧として出力される MISCONF IDを指定したくなるが、これを指定しても警告を抑制してくれない。

network.tf(警告抑止してくれない例1)
resource "aws_security_group" "sample" {
  ...

  egress {
    description = "allow all egress connection"
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"] #tfsec:ignore:AVD-AWS-0103
  }
}

また、tfsecは v1.0.0 からルールID体系が変更になった。これに伴い AWS009 といったルールID (leagcy ID)から rules.md に記載されている aws-vpc-no-public-egress-sgr というルールID(new ID)を指定する必要がある。しかし、trivyでは legacy IDにのみ対応しており、new IDを指定しても警告を抑制してくれない。

network.tf(警告抑止してくれない例2)
resource "aws_security_group" "sample" {
  ...

  egress {
    description = "allow all egress connection"
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"] #tfsec:ignore:aws-vpc-no-public-egress-sgr
  }
}

以上から、trivyを利用する以上はlegacy IDを指定する必要がある。

legacy IDの取得

では、どうやってlegacy IDを取得するかというと、これが難しい。

trivyにMISCONF IDの替わりにlegacy IDを出力するオプションはなさそう。MISCONF IDからlegacy IDに変換する方法もなさそう。現状ではtfsecを実行して対応するルールIDを取得するしかない。

しかし、tfsecも最新のv1.1.4ではnew IDに移行しており、legacy IDを出力してくれない。このため、古いバージョンのtfsecを実行するか、tfsecが内部で持つ対応マップ を参照してlegacy IDを取得する必要がある。

以上から、legacy IDを取得するためには tfsecを実行する→対応マップでlegacy IDを参照するというステップを経る必要がある。しかし、tfsecで実行する以上はtfsecによる警告も同時に抑制する必要があるが、最新のtfsecではlegacy IDで指定しても警告を抑制してくれない。このため、コードには新旧のルールIDで警告を抑制する必要がある。

network.tf(抜粋)
resource "aws_security_group" "sample" {
  ...

  egress {
    description = "allow all egress connection"
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"] #tfsec:ignore:aws-vpc-no-public-egress-sgr tfsec:ignore:AWS009
  }
}

できればMISCONF IDを指定しても trivy が除外してくれるか、trivyが警告出力でlegacy IDを出力する、またはtrivyが警告除外のルールIDとしてnew IDに対応した上で結果出力時にnew IDを出力して欲しいところ。

その他の解決策

trivyignore

検出対象から除外したい脆弱性や設定不備については tirvyignoreを指定することで回避できる。ここでは trivyのMISCONF IDが指定できる。tfsecのlegacy IDやnew IDは指定できない。

$ cat .trivyignore
AVD-AWS-0103

この方法であればtrivyで設定不備が検出された後に tfsecを実行してlegacy IDのマップを参照して、といった作業が不要になる。一方で、ここで指定したIDは他のリソースからも検出が除外される。特定リソースでのみ除外したいという今回の要件には合わない。

--ski-files / --skip-dirs

trivy config --skip-files network.tf . のような方法で対象ファイル/ディレクトリを解析対象から除外できる。

ただし、この方法では ingress に関する警告も出力されなくなるし、解析対象に含めたいか考慮してファイル分割する必要が出てくる。今回のようにルール適用を制御する用途としては不向き。

Rego policy

Regoのポリシーで今回の要件を実現できるかは不明。実現できたとしても手間が掛かり過ぎるので不適切な気がする。

まとめ

  • trivyでterraformの警告を抑制するにはコメントでtfsecのlegacy IDを指定する
  • legacy IDを取得するにはtfsecを実行した上で対応表からnew IDとの対応を確認する必要がある
  • ここまでしてtrivyを使いたいかは要検討、直接tfsecを使った方が簡単

Discussion