こんにちは。BASE BANK 株式会社 Dev Division にて、 Software Developer をしている東口(@hgsgtk)です。
BASE BANK Dev での開発では、クラウドインフラの構成管理に、 Terraform を利用しています。
世の情報をたくさんキュレーションしている CTO の@dmnlkさんに、手軽に CI に組み込めそうなセキュリティチェックツールがあることを教えてもらったので、導入してみました。
CTO氏のキュレーションメディアで紹介された tfsec を早速試して良さそうだったhttps://t.co/bl67dlW2Ub https://t.co/vAkTOVagec
— Kazuki Higashiguchi (@hgsgtk) August 21, 2020
このブログの公開日は 2020/10/30 ですので、導入してから約 2 ヶ月強経ちました。導入・運用をつづけた経験から、いろいろ tfsec 自体の変化や、運用したことで学べた AWS セキュリティプラクティスをご紹介します。
目次
- 目次
- TL;DR
- tfsec とは
- 始め方
- 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.
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 を使用しました。
本アクションを使った設定方法は例えば次のような 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 のコメントで見れるようになります。
ちなみに、最近 GitHub に Unchanged files with check annotations という Beta 版の機能がついて、PR での変更差分外のファイルに対するコメントも反映されるようになりました。
tfsec は、Release によって新たなチェック項目が増えたりします。チェック項目が増えた際に、それに引っかかる内容が Terraform の記述に含まれていないかを継続的にチェックするにあたって、便利な機能だなと個人的に感じています。
既存の指摘は 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
- Amazon ECR のイメージスキャン機能の有効化
- Amazon S3 のロギングバケット
- AWS Key Management Service のキーローテーションの有効化
- Amazon Elasticsearch Service のデータ保護
- Redis 用 Amazon ElastiCache のデータ保護
- その他
ひとつひとつ見てみましょう。
Amazon CloudFront の推奨 SSL/TLS Policy
tfsec では aws_cloudfront_distribution' defines outdated SSL/TLS policies (not using TLSv1.2_2018)
という指摘項目があります。これは、以下の issue で追加された CloudFront のチェック観点です。
この issue 当時のベストプラクティスでは、 TLSv1.2_2018 が推奨されておりました。しかし現在は、 AWS Console に表示されていますが、 TLSv1.2_2019 が推奨されるセキュリティポリシーとなっています。
「そもそも TLSv1.2_2019 はどう違うの」という疑問を持たれた方(かつての自分ですね)は、クラスメソッドさんの次のブログの解説がとてもわかりやすいのでおすすめです。
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 >= に上げてみてください。
Amazon ECR のイメージスキャン機能の有効化
こちらは、同僚の前川さんに対応いただきました。aws_ecr_repository' defines a disabled ECR image scan
という指摘を受け対応したものです。ECR image scan は、2019 年 10 月 28 日に公開された ECR image に対するイメージスキャンの機能です。
他のツールでは、 trivy や dockle などがあげられます。
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
にします。
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 バケットのロギングバケットの場合、当該指摘をしないように修正されています。
AWS Key Management Service のキーローテーションの有効化
これは、同僚の@budougumi0617さんが新規 KMS Key を構築時に指摘され、対応いただいたものです。AWS Key Management Service(以降、AWS KMS と略します)には、カスタマーマスターキー ローテーションという機能があります。
AWS KMS は自動的に有効にした日から CMK(Customer Master Key) を 365 日後にローテーションし、その後は 365 日ごとに実行します。
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 暗号化が有効になります。
この設定をしていないと、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 を使用してインデックスやログ・アプリケーションディレクトリのデータなどを保管時に暗号化する機能が提供されています。
Terraform では encrypt_at_rest という記述で指定します。
resource "aws_elasticsearch_domain" "my_elasticsearch_domain" { domain_name = "domain-foo" encrypt_at_rest { enabled = true # 保管時のデータ暗号化を有効化 } }
しかし、こちらも既存ドメインでは有効にできません。また、特定インスタンスタイプの場合はサポートしていないこともあります。
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 には、ネットワーク転送時の暗号化オプションが用意されています。
具体的には、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 には、データの暗号化オプションが用意されています。
具体的には、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 にて追加されたチェック項目です。
WARNING レベルの指摘なので、要件上神経質になる必要がないユースケースでの CloudFront の利用であれば tfsec:ignore マーキングで対応可能です。
おわりに
tfsec の導入と、その指摘項目から AWS のセキュリティプラクティスを紹介しました。
今回は紙面の都合上紹介しておりませんが、ちょうど 2020 年 10 月に一気に開発が進んでいるのがカスタムチェックです。JSON 形式でルールを指定することで自分たちにとってのルールを tfsec のチェック内に導入できます。こちらもまた別の機会に紹介いたします。
かんたんに使用開始できるので、ちょっとセキュリティに関心・不安があるけど何も出来ていないという方がいらっしゃれば、試してみてはいかがでしょうか。