BASEプロダクトチームブログ

ネットショップ作成サービス「BASE ( https://thebase.in )」、ショッピングアプリ「BASE ( https://thebase.in/sp )」のプロダクトチームによるブログです。

Terraformのセキュリティ静的解析 tfsec の導入から始めるAWSセキュリティプラクティス

こんにちは。BASE BANK 株式会社 Dev Division にて、 Software Developer をしている東口(@hgsgtk)です。

BASE BANK Dev での開発では、クラウドインフラの構成管理に、 Terraform を利用しています。

世の情報をたくさんキュレーションしている CTO の@dmnlkさんに、手軽に CI に組み込めそうなセキュリティチェックツールがあることを教えてもらったので、導入してみました。

このブログの公開日は 2020/10/30 ですので、導入してから約 2 ヶ月強経ちました。導入・運用をつづけた経験から、いろいろ tfsec 自体の変化や、運用したことで学べた AWS セキュリティプラクティスをご紹介します。

目次

TL;DR

  • Terraform のセキュリティ静的解析 tfsec はクラウドの認証キー・権限付与が必要ないためすぐに試すことが出来る
  • tfsec 自体の開発も頻繁にコミットされており日々進化を遂げている
  • tfsec を使い続けることで学んだ AWS セキュリティプラクティスをいくつか紹介する

tfsec とは

tfsec は、Terraform ファイルを静的解析しセキュリティイシューとなるような点を指摘してくれるツールです。

A static analysis security scanner for your Terraform code. Discover problems with your infrastructure before hackers do.

www.tfsec.dev

AWS・Azure・GCP といったクラウドベンダーをサポートしています。また、秘匿情報の混入がないかといった特定ベンダーに関わらない一般的なセキュリティチェック事項も備えています。

開発はメンテナー・コアコミッターの方々によって頻繁に行われています。チェック項目の新規追加はもちろんのこと、先ほど紹介したhttps://www.tfsec.devというウェブサイトを公開したり、tfsec 自体のパフォーマンスチューニングやカスタムチェック作成のサポートなど、日々新機能が追加されています。また、筆者自身いくつか PR を提出していますがそれに対してもすぐに反応いただきメンテナー・コアコミッターの熱量の高さを感じます。

始め方

クラウドの認証キー・権限付与が必要ないため導入しやすい

tfsec が始めやすい特徴として、当該クラウドの認証キー・権限などが不要な点です。たとえば、 terraform plan をするようなツールだと、AWS の場合 IAM を発行する必要があります。しかし、本ツールは *.tf ファイルの内容の静的解析を行うだけなので、これらがいりません。

AWS でのインフラ構成管理を Terraform でやる場合、 Terraform に対してそれなりに強い権限を付与するため、その権限管理をどこでやるかは論点になりがちです。それを考えなくていいのは、とても始めやすい利点だなと感じます。

GitHub Actions で始める

私の所属するチームでは、 GitHub Actions で導入をはじめました。

公式の GitHub では、 triat/terraform-security-scan が紹介されています。しかし今回は、GitHub の Pull request(PR) へのコメントがすぐに実現できる点で、 reviewdog が公開している reviewdog/action-tfsec を使用しました。

github.com

本アクションを使った設定方法は例えば次のような yml ファイルです。

name: tfsec
on: [pull_request]
jobs:
  tfsec:
    name: tfsec
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v2

      - name: Terraform security scan
        uses: reviewdog/action-tfsec@master
        with:
          github_token: ${{ secrets.github_token }}
          reporter: github-pr-review # Change reporter
          fail_on_error: "true" # Fail action if errors are found
          filter_mode: "nofilter" # Check all files, not just the diff
          flags: "" # Optional

これにより、次のように指摘内容が GitHub の PR のコメントで見れるようになります。

f:id:khigashigashi:20201029190049p:plain
ReviewDogによるPRへのコメント

ちなみに、最近 GitHub に Unchanged files with check annotations という Beta 版の機能がついて、PR での変更差分外のファイルに対するコメントも反映されるようになりました。

f:id:khigashigashi:20201029190123p:plain
"Unchanged files with check annotations" によるPR差分外のコメント

tfsec は、Release によって新たなチェック項目が増えたりします。チェック項目が増えた際に、それに引っかかる内容が Terraform の記述に含まれていないかを継続的にチェックするにあたって、便利な機能だなと個人的に感じています。

github.com

既存の指摘は tfsec:ignore でいったん Fixme issue にする

GitHub Actions に入れると、多かれ少なかれ、 Error / Warning レベルの内容が指摘されるかもしれません。導入にあたりすべてを直してからというのも新規に生まれるセキュリティの穴を塞げなくてもったいないので、弊社の例では、最初に tfsec:ignore というマーキングで既存の指摘を無視する設定をしていきました。

resource "aws_ecr_repository" "hoge" {
  #tfsec:ignore:AWS023
  #Fixme above it

Fixme で残しつつ、随時解消していく方法をとっていきました。

tfsec の指摘から AWS におけるセキュリティプラクティスを学ぶ

実際に tfsec を使い続けてさまざまな指摘によって、 AWS におけるセキュリティプラクティスを学びました。それらの学びをおすそ分けします。具体的には次の内容を紹介します。

ひとつひとつ見てみましょう。

Amazon CloudFront の推奨 SSL/TLS Policy

tfsec では aws_cloudfront_distribution' defines outdated SSL/TLS policies (not using TLSv1.2_2018) という指摘項目があります。これは、以下の issue で追加された CloudFront のチェック観点です。

github.com

この issue 当時のベストプラクティスでは、 TLSv1.2_2018 が推奨されておりました。しかし現在は、 AWS Console に表示されていますが、 TLSv1.2_2019 が推奨されるセキュリティポリシーとなっています。

「そもそも TLSv1.2_2019 はどう違うの」という疑問を持たれた方(かつての自分ですね)は、クラスメソッドさんの次のブログの解説がとてもわかりやすいのでおすすめです。

dev.classmethod.jp

resource "aws_cloudfront_distribution" "example.com" {
   # (省略)
  viewer_certificate {
    acm_certificate_arn            = "certificateのarn"
    cloudfront_default_certificate = false
    minimum_protocol_version = "TLSv1.2_2019"
    ssl_support_method       = "sni-only"
  }
)

もともと、TLSv1.2_2018 ではない場合 Error と指摘されていましたが、PR を提出しリリースいただきました。もし TLSv1.2_2019 にあげても Error になる場合は、tfsec のバージョンを 0.27.0 >= に上げてみてください。

github.com

Amazon ECR のイメージスキャン機能の有効化

こちらは、同僚の前川さんに対応いただきました。aws_ecr_repository' defines a disabled ECR image scanという指摘を受け対応したものです。ECR image scan は、2019 年 10 月 28 日に公開された ECR image に対するイメージスキャンの機能です。

aws.amazon.com

他のツールでは、 trivydockle などがあげられます。

ECR Image scan を有効にするには、 aws_ecr_repository.image_scanning_configuration を設定します。

image_scanning_configuration は、Terraform 2 系の場合は 2.34 から、 3 系の場合は 3.10 から使用可能です。

resource "aws_ecr_repository" "hoge" {
  # (省略)
  image_scanning_configuration {
    scan_on_push = true
  }
}

Amazon S3 のバケットロギング

aws_s3_bucket does not have logging enabled と指摘された場合、S3 のバケットロギングの検討が必要です。

S3 ではAWS開発者ガイド:Amazon S3 サーバーアクセスのログ記録で解説がある通り、サーバーアクセスに対するログ記録機能が提供されています。このロギングを有効にしておくとセキュリティやアクセス監査の観点で役に立ちそうです。

resource "aws_s3_bucket" "public-usecase-bucket" {
  # (省略)
  logging {
    target_bucket = aws_s3_bucket.access-logs.id # logging bucketを指定
    target_prefix = "logs/"
  }
}

resource "aws_s3_bucket" "access-logs" {
  # (省略)
  acl    = "log-delivery-write"
}

S3 のアクセスログバケットを作成する際には、acl をlog-delivery-writeにします。

discuss.hashicorp.com

log-delivery-writeは、AWS があらかじめ定義した既定 ACL と呼ばれるものの 1 つです(既定 ACL については、AWS開発者ガイド:アクセスコントロールリスト (ACL) の概要をご参照ください)。

LogDelivery グループはバケットに対する WRITE および READ_ACP アクセス許可を取得します。

ロギングバケット自体の ACL を考える際にはこの既定 ACL を使用するのが便利です。

以前は、ロギングバケット自体にもaws_s3_bucket does not have logging enabledという指摘が入り tfsec:ignore マーキングで回避する必要がありました。しかし、tfsec に対して PR を提出し解消いたしました。S3 バケットのロギングバケットの場合、当該指摘をしないように修正されています。

github.com

AWS Key Management Service のキーローテーションの有効化

これは、同僚の@budougumi0617さんが新規 KMS Key を構築時に指摘され、対応いただいたものです。AWS Key Management Service(以降、AWS KMS と略します)には、カスタマーマスターキー ローテーションという機能があります。

AWS KMS は自動的に有効にした日から CMK(Customer Master Key) を 365 日後にローテーションし、その後は 365 日ごとに実行します。

docs.aws.amazon.com

resource "aws_kms_key" "sample_key" {
  description         = "機密情報の暗号化に利用"
  enable_key_rotation = true # 自動キーローテーションを有効にする
}

作業としては、enable_key_rotation = true の設定だけです。その設定をしてから 365 日後に自動でローテーションされます。

Amazon Elasticsearch Service のデータ保護

こちらは、同僚の前川さんが新規 Amazon Elasticsearch Service (以降、Amazon ES と略します)構築時に指摘され対応いただいたものです。Amazon ES は、データ保護におけるセキュリティ上の機能として「ノード間通信の暗号化」・「保管時の暗号化」という2つのオプションを備えています。

ノード間通信の暗号化

Amazon ES のドメインは、デフォルトでは VPC 内のノード間トラフィックは暗号化されませんが、ノード間通信の暗号化を有効にすることで VPC 内のすべての通信で TLS 1.2 暗号化が有効になります。

docs.aws.amazon.com

この設定をしていないと、Resource 'aws_elasticsearch_domain.es' defines an Elasticsearch domain with plaintext traffic (missing node_to_node_encryption block).という指摘を受けます。

具体的には次のようなコードによってノード間通信の暗号化の設定が可能です。

resource "aws_elasticsearch_domain" "es" {
  elasticsearch_version = "6.3"
  # (省略)
  node_to_node_encryption {
    enabled = true # true にすることで有効化する
  }
}

しかし、AWS開発者ガイド: Amazon Elasticsearch Service のノード間の暗号化にある通り、これは既存ドメインに対しての設定のつけ外しはできないため、既存の Amazon ES ドメインに対しては別のドメインを作成する必要があります。

また、elasticsearch_version も 6.0 以降が求められます。既存リソースに対して作り直しのコストを書けるのはしんどいという判断したら、tfsec:ignore マーキングするとよいでしょう。

保管時の暗号化

Amazon ES ドメインでは、AWS KMS を使用してインデックスやログ・アプリケーションディレクトリのデータなどを保管時に暗号化する機能が提供されています。

docs.aws.amazon.com

Terraform では encrypt_at_rest という記述で指定します。

resource "aws_elasticsearch_domain" "my_elasticsearch_domain" {
  domain_name = "domain-foo"

  encrypt_at_rest {
    enabled = true # 保管時のデータ暗号化を有効化
  }
}

しかし、こちらも既存ドメインでは有効にできません。また、特定インスタンスタイプの場合はサポートしていないこともあります。

docs.aws.amazon.com

R3 インスタンスタイプは、保管時のデータの暗号化またはきめ細かなアクセスコントロールをサポートしていません。

サポート対象外の場合 tfsec:ignore マーキングすることになりますが、このような暗号化の検討を指摘によって考えられるのは tfsec の良い点ですね。

Redis 用 Amazon ElastiCache のデータ保護

こちらも Amazon ES における「ノード間通信の暗号化」・「保管時の暗号化」と類似したセキュリティプラクティスが存在します。前者を「In-Transit Encryption (TLS)」、後者を「At-Rest Encryption」にて設定します。

In-Transit Encryption (TLS)

tfsec からは Resource 'aws_elasticache_replication_group' defines an unencrypted Elasticache Replication Group (missing transit_encryption_enabled attribute というメッセージで指摘されます。

Amazon ElastiCache には、ネットワーク転送時の暗号化オプションが用意されています。

docs.aws.amazon.com

具体的には、transit_encryption_enabledというオプションを true にしておくことで設定可能です。

resource "aws_elasticache_replication_group" "my-resource" {
        # (省略)       
        transit_encryption_enabled = true
}

こちらの設定は、Redis の対応バージョン(3.2.6, 4.0.10 or later)や対応可能なノードタイプが限られるといった制約条件を事前に確認する必要があります。

また、暗号化の実装によるバックアップオペレーション・ノード同期オペレーションの実行パフォーマンスが低下する場合があることを開発者ガイドにて示しています。

なお、既存のレプリケーショングループの場合は新しいレプリケーショングループを作成する必要があります。こちらの方法についても、開発者ガイドにて具体的な手順が説明されています。実際に読者の中で気がついて検討をしたい方がいらっしゃれば、是非ご覧になってください。

At-Rest Encryption

tfsec からは Resource 'aws_elasticache_replication_group.bb-prd-auth' defines an unencrypted Elasticache Replication Group (missing at_rest_encryption_enabled attribute) というメッセージで指摘されます。

Amazon ElastiCache には、データの暗号化オプションが用意されています。

docs.aws.amazon.com

具体的には、at_rest_encryption_enabledというオプションを true にしておくことで設定可能です。

resource "aws_elasticache_replication_group" "my-resource" {
        # (省略)       
        at_rest_encryption_enabled = true
}

こちらも、「In-Transit Encryption (TLS)」と同様の制約事項・考慮事項があります。

セキュリティ観点とパフォーマンス観点のバランシングは自身のアプリケーション要件に沿って検討が必要ですが、tfsec によってセキュリティ観点での指摘を純粋に受けられるのは設計上の利点でしょう。

その他

その他、少し細かいですが管理上大事な内容を紹介します。

aws_security_group_rule' should include a description for auditing purposes

Security group の INBOUND / OUTBOUND ルールには、説明(description)を設定できますが、監査上は設定することが推奨されます。

resource "aws_security_group_rule" "huga" {
  # (省略)
  description       = "BASE Office"
}

aws_cloudfront_distribution' does not have a WAF in front of it

tfsec の v0.30.0 にて追加されたチェック項目です。

docs.aws.amazon.com

WARNING レベルの指摘なので、要件上神経質になる必要がないユースケースでの CloudFront の利用であれば tfsec:ignore マーキングで対応可能です。

おわりに

tfsec の導入と、その指摘項目から AWS のセキュリティプラクティスを紹介しました。

今回は紙面の都合上紹介しておりませんが、ちょうど 2020 年 10 月に一気に開発が進んでいるのがカスタムチェックです。JSON 形式でルールを指定することで自分たちにとってのルールを tfsec のチェック内に導入できます。こちらもまた別の機会に紹介いたします。

かんたんに使用開始できるので、ちょっとセキュリティに関心・不安があるけど何も出来ていないという方がいらっしゃれば、試してみてはいかがでしょうか。