
【tfsec】Terraformの静的セキュリティスキャンを行ってみよう!
この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
こんにちは!AWS事業本部コンサルティング部のたかくに(@takakuni_)です。
今回は、tfsecを使用して、Terraformのセキュリティスキャンを体験してみようと思います。
結論
- tfsecは、Terraformの静的なセキュリティスキャンを行うツール
 - ローカル環境で動作可能な認証情報などを用意しなくていい
 
tfsecとは
Aqua Security社の、オープンソースツールです。
ざっくり、ご説明すると、Terraformの静的なセキュリティスキャナーです。
ローカル、CIパイプライン環境で実行できるように設計されています。
いざ実践
インストール
今回は、Macでtfsecを使用してみようと思います。
% brew install tfsec
各OSのインストール方法は、こちらからご参照ください。
スキャン実行
今回、tfsec用に、以下のtfファイルを作成しました。
VPC、パブリックサブネット、ルートテーブル、セキュリティグループを作成します。
module "vpc" {
  source  = "terraform-aws-modules/vpc/aws"
  # source  = "../modules/vpc"
  version = "3.12.0"
  # insert the 23 required variables here
  cidr = "10.0.0.0/16"
  name = "terraform-reintroduction"
  public_subnets = ["10.0.0.0/24", "10.0.1.0/24"]
  azs = ["ap-northeast-1a", "ap-northeast-1c"]
}
resource "aws_security_group" "allow_tls" {
  name        = "allow_tls"
  description = "Allow TLS inbound traffic"
  vpc_id      = module.vpc.vpc_id
  ingress {
    description      = "TLS from VPC"
    from_port        = 443
    to_port          = 443
    protocol         = "tcp"
    cidr_blocks      = [module.vpc.vpc_cidr_block]
  }
  egress {
    from_port        = 0
    to_port          = 0
    protocol         = "-1"
    cidr_blocks      = ["0.0.0.0/0"]
    ipv6_cidr_blocks = ["::/0"]
  }
  tags = {
    Name = "allow_tls"
  }
}
では、実行してみます。
tfファイルを保管している、ディレクトリ内に移動して、tfsecコマンドを実行してみます。
% tfsec
Result #1 CRITICAL Security group rule allows egress to multiple public internet addresses. 
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
 vpc.tf Line 30
───────┬─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
   26  │   egress {
   27  │     from_port        = 0
   28  │     to_port          = 0
   29  │     protocol         = "-1"
   30  │     cidr_blocks      = ["0.0.0.0/0"]
   31  │     ipv6_cidr_blocks = ["::/0"]
   32  │   }
───────┴─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
          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.1.5/checks/aws/vpc/no-public-egress-sgr/
  - https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Result #2 CRITICAL Security group rule allows egress to multiple public internet addresses. 
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
 vpc.tf Line 31
───────┬─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
   26  │   egress {
   27  │     from_port        = 0
   28  │     to_port          = 0
   29  │     protocol         = "-1"
   30  │     cidr_blocks      = ["0.0.0.0/0"]
   31  │     ipv6_cidr_blocks = ["::/0"]
   32  │   }
───────┴─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
          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.1.5/checks/aws/vpc/no-public-egress-sgr/
  - https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
Result #3 LOW Security group rule does not have a description. 
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
 vpc.tf Lines 26-32
───────┬─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
   26  │   egress {
   27  │     from_port        = 0
   28  │     to_port          = 0
   29  │     protocol         = "-1"
   30  │     cidr_blocks      = ["0.0.0.0/0"]
   31  │     ipv6_cidr_blocks = ["::/0"]
   32  │   }
───────┴─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
          ID aws-vpc-add-description-to-security-group-rule
      Impact Descriptions provide context for the firewall rule reasons
  Resolution Add descriptions for all security groups rules
  More Information
  - https://aquasecurity.github.io/tfsec/v1.1.5/checks/aws/vpc/add-description-to-security-group-rule/
  - https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group
  - https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
  timings
  ──────────────────────────────────────────
  disk i/o             23.956709ms
  hcl parsing          74.834µs
  evaluation           21.812586ms
  adaptation           960µs
  running checks       4.643584ms
  total                109.267ms
  counts
  ──────────────────────────────────────────
  blocks               6
  modules              1
  files                9
  results
  ──────────────────────────────────────────
  ignored              0
  excluded             0
  critical             2
  high                 0
  medium               0
  low                  1
  3 potential problem(s) detected.
実行結果から、セキュリティグループ周りで、3件検知されていることが確認できます。
重要度について
tfsecでは、検知結果を4つの重要度でカテゴライズしています。
- critical
 - high
 - medium
 - low
 
重要度の具体的な、選別方法は明記されていないですが、検知されたルールに、ひととおり目を通しておきましょう。
aws-vpc-no-public-egress-sgr
An egress security group rule allows traffic to /0.
Result #1, #2で、アウトバウンドルールが、フルオープンであることを検知していました。

リファレンスに、解決策や影響範囲が記載されているので、「何がどのように悪い」のか、とてもわかりやすいです。
aws-vpc-add-description-to-security-group-rule
Missing description for security group rule.
Result #3では、アウトバウンドルールに、説明書きがないことを検知していました。
たしかに、説明書きがないと、使用用途がわかりづらいため、追加した方がいいですね。
ルール検知を無視する
スキャン実行で検知されたアウトバウンドルールのフルオープンを、ignore(無視)に変更してみようと思います。
変更方法は、コード内にコメントとして、検知を無視するコードを追記します。
無視を行うコードの有効範囲は、同一行と一つ下の行までです。
Result #1のみを無視する
resource "aws_security_group" "allow_tls" {
  name        = "allow_tls"
  description = "Allow TLS inbound traffic"
  vpc_id      = module.vpc.vpc_id
  ingress {
    description      = "TLS from VPC"
    from_port        = 443
    to_port          = 443
    protocol         = "tcp"
    cidr_blocks      = [module.vpc.vpc_cidr_block]
  }
  egress {
    from_port        = 0
    to_port          = 0
    protocol         = "-1"
    # tfsec:ignore:aws-vpc-no-public-egress-sgr
    cidr_blocks      = ["0.0.0.0/0"] # ignored
    ipv6_cidr_blocks = ["::/0"] # critical
  }
  tags = {
    Name = "allow_tls"
  }
}
/* or
resource "aws_security_group" "allow_tls" {
  name        = "allow_tls"
  description = "Allow TLS inbound traffic"
  vpc_id      = module.vpc.vpc_id
  ingress {
    description      = "TLS from VPC"
    from_port        = 443
    to_port          = 443
    protocol         = "tcp"
    cidr_blocks      = [module.vpc.vpc_cidr_block]
  }
  egress {
    from_port        = 0
    to_port          = 0
    protocol         = "-1"
    cidr_blocks      = ["0.0.0.0/0"] # tfsec:ignore:aws-vpc-no-public-egress-sgr
    # 一行開ける
    ipv6_cidr_blocks = ["::/0"]
  }
  tags = {
    Name = "allow_tls"
  }
}
*/
Result #1,2を無視する
resource "aws_security_group" "allow_tls" {
  name        = "allow_tls"
  description = "Allow TLS inbound traffic"
  vpc_id      = module.vpc.vpc_id
  ingress {
    description      = "TLS from VPC"
    from_port        = 443
    to_port          = 443
    protocol         = "tcp"
    cidr_blocks      = [module.vpc.vpc_cidr_block]
  }
  egress {
    from_port        = 0
    to_port          = 0
    protocol         = "-1"
    cidr_blocks      = ["0.0.0.0/0"] # tfsec:ignore:aws-vpc-no-public-egress-sgr
    ipv6_cidr_blocks = ["::/0"] # ignored →コードの影響範囲は1行下まで及ぶため
  }
  tags = {
    Name = "allow_tls"
  }
}
/* or
resource "aws_security_group" "allow_tls" {
  name        = "allow_tls"
  description = "Allow TLS inbound traffic"
  vpc_id      = module.vpc.vpc_id
  ingress {
    description      = "TLS from VPC"
    from_port        = 443
    to_port          = 443
    protocol         = "tcp"
    cidr_blocks      = [module.vpc.vpc_cidr_block]
  }
  egress {
    from_port        = 0
    to_port          = 0
    protocol         = "-1"
    cidr_blocks      = ["0.0.0.0/0"] # tfsec:ignore:aws-vpc-no-public-egress-sgr
    ipv6_cidr_blocks = ["::/0"] # tfsec:ignore:aws-vpc-no-public-egress-sgr
  }
  tags = {
    Name = "allow_tls"
  }
}
*/
最後に
今回は、かなり簡単ではありますが、tfsecの使い方をご紹介しました。
より応用的な使い方は、別途ブログにできたらと思います。
以上、AWS事業本部コンサルティング部のたかくに(@takakuni_)でした!







