aws セキュリティ

全リージョン、複数AWSアカウントのAWS Security Hubのコントロールをコードで統制・管理する

aws セキュリティ

こんにちは。技術部技術基盤チームの@k1LoWです。

FUJI ROCK FESTIVAL '22のライブ配信で観ることができた Hiatus Kaiyote のアクトは最高でした。

また、配信はされなかったものの#fujirockのTwitter TLで知ることができた SMTK をヘビーに聴いています。最高です。

さて、本エントリーではGMOペパボにおけるAWS Security Hubのコントロールの統制・管理の取り組みについて紹介します。

AWS Security Hubのセキュリティ標準とコントロール

AWS Security Hubとは、公式ドキュメントによると次のように紹介されています。

AWS Security Hub では、AWS のセキュリティ状態を包括的に把握することが可能で、セキュリティ業界標準およびベストプラクティスに照らした環境チェックを行うのに有効です。

Security Hub は、AWS アカウント、サービス、およびサポートされているサードパーティーパートナー製品からセキュリティデータを収集するため、セキュリティの傾向を分析し、最も優先度の高いセキュリティ問題を特定するのに役立てることができます。

また「セキュリティ標準(Standard)」というベストプラクティスや業界標準に基づいた一連のセキュリティチェック項目で継続的な環境チェックとスコアリングをすることができます。

AWS Security Hubでは2022年8月9日時点で次のセキュリティ標準が利用可能です。

セキュリティ標準は、セキュリティチェック項目の集まりです。その特定のリソースに対するセキュリティチェック項目を「コントロール(Control)」と呼びます。

あるセキュリティ標準を有効にすると、そのセキュリティ標準に含まれる各コントロールに従ったセキュリティチェックが実施されるようになります。

そして、セキュリティチェックの結果が「検出結果(Finding)」として集約され、そのセキュリティ標準のスコアリングがされることになります。

全リージョン、複数AWSアカウントのコントロールの統制・管理の難しさ

GMOペパボでは複数のAWSアカウントを運用しています。その全てのAWSアカウントでAWS Security Hubを有効にしています。

各コントロールの検出結果に対して「セキュリティチェックが成功するように各リソースについて修正対応する」というのが最初に検討する対応です。

一方で修正対応以外の対応方法もあります。

  1. コントロールを無効化する
    • コントロールが要求する基準が高すぎたり、実際の運用に合致しない場合、「コントールを無効化する」ことを選択することがあります。
    • また、AWS Security Hubの料金は各コントロールのリソースへのセキュリティチェック単位で発生します。「不必要と判断したコントールを無効化する」ことは、コストを最適化という面でも有効です。
  2. リソース単位でのコントロールによるセキュリティチェックを無効化(抑制)する
    • コントロールを無効化する以外にも、「このリソースにおいてはコントロールが指摘するセキュリティチェック項目を対応する必要はない」として「リソース単位でのコントロールのセキュリティチェックを無効化(抑制)する」という手段もあります。

上記のような対応を取る場合、次のような課題があります。

一定の基準で無効化を実施する必要がある

コントロールの無効化やリソース単位での無効化といった手段は安易に実施してしまうとセキュリティレベルを下げてしまうことにもなりかねません。

会社全体でセキュリティレベルを維持するため、無効化する際には一定の基準を元に実施判断をしていく必要があります。

「一定の基準」をどのように維持していくかが課題になります。

対象となるコントロールが多い

コントロールの統制・管理が必要だということは上記で述べた通りです。

しかし、そのコントロールの数は膨大です。例えばAWS Foundational Security Best Practicesのコントロールは200近くあります。

また、AWS Security Hubはリージョン単位のサービスです。全リージョンの検出結果を1つのリージョンに集約させることは可能ですが、セキュリティ標準やコントロールの設定はリージョンごとに必要になります。

さらに、複数AWSアカウントに対して横断的に統制・管理するとなると、統制・管理対象の要素は単純計算で「リージョン数 x AWSアカウント数 x コントロール数」になります。

「リソース単位でのコントロールによるセキュリティチェックを無効化(抑制)」も考慮するとその数はさらに増えることになります。

数に対して、いかに効率的に統制・管理していくかが課題になります。

コードで統制・管理する

コントロールの統制・管理の課題は

  1. 無効化の手段を取る場合は一定の基準を元に実施判断をしていく必要がある
  2. 単純に対象となるコントロールの数が多い

の2つであると述べました。

この2つの課題を軽減するために、AWS Security Hubのコントロールの設定をコードで記述しそれをGitHubのリポジトリで管理する方法を選択しました。

課題「1. 無効化の手段を取る場合は一定の基準を元に実施判断をしていく必要がある」に対応する

1つ目の課題の「無効化の手段を取る場合は一定の基準を元に実施判断をしていく必要がある」については、

  • 無効化の申請はGitHubのPull Requestベースで行い、Pull Requestのレビューを「一定の基準に沿っているか」を判断するチェックポイントとして活用する
  • 無効化の判断理由をコード上に記述することを強制することで、過去の判断基準を確認できるようにする

とすることで対応することにしました。

Pull Requestをマージしたタイミングで記述されたコードの通りにAWS Security Hubのコントロールの状態が更新されればさらに良いでしょう。

なお、GitHubのPull Requestを使ったチェックフローは、GMOペパボにおいてはエンジニアに限らず全パートナーが慣れているフローなのでこの形に落とし込めることは大きなメリットになります。

課題「2. 単純に対象となるコントロールの数が多い」に対応する

数の多さに対応するためには、「どのようなコード(構造)でコントロールを管理するか」が重要になってくると考えました。

前述したように、AWS Security Hubはリージョン単位のサービスです。

単純な方法だと全リージョン分のコントロールについて同じようなコードを書く必要がでてきます。

また、GMOペパボでは複数AWSアカウントを運用しているため、統制・管理のために「複数AWSアカウント横断で共通の設定」という方法も取れることが望ましいです。

コード化する手段の検討

AWS Security Hubのコントロール設定をコード化するの手段として、まずAWS CloudFormation(AWS CloudFormation StackSets)とTerraformを検討しました。

課題1については検討した2ツールとも問題なく対応できると判断しました。

しかし、課題2についてはAWS CloudFormationやTerraformの上に全リージョンや複数AWSアカウントをまたいだ効率的なコントロール管理の仕組みを構築するのは難しいと判断しました。

そこで、最終手段として「専用のツールを作る」という選択をしました。

control-controls

今回、control-controlsというツールを作成しました。

https://github.com/pepabo/control-controls

control-controlsはAWS Security Hubのコントロールの設定を管理するためのツールです。

control-controlsの特徴は次の通りです。

  1. TerraformやCodenize.toolsと同じように、対象となるリソースの状態の冪等性を担保する動きをする( control-controls apply
  2. Dry-run( control-controls plan )の仕組みを提供している
  3. あらかじめ全リージョンを対象を前提としている
  4. ベースとなるコントロールの設定に対してリージョンごとの設定の差分を書ける
  5. kustomizeと同じように、設定ファイル自体の差分パッチの機能を持つ( --overlay

使い方

使い方はTerraformと同じように control-controls plan で差分を確認し、

$ control-controls plan controls.yml
2022-04-14T15:16:54+09:00 INF Checking eu-north-1
2022-04-14T15:17:02+09:00 INF Checking ap-south-1
2022-04-14T15:17:08+09:00 INF Checking eu-west-3
[...]
2022-04-14T15:18:19+09:00 INF Checking us-east-2
2022-04-14T15:18:25+09:00 INF Checking us-west-1
2022-04-14T15:18:31+09:00 INF Checking us-west-2
- eu-north-1::standards::aws-foundational-security-best-practices/v/1.0.0::controls::Redshift.4 (disabled reason: Redshift is not running.)
- eu-north-1::standards::aws-foundational-security-best-practices/v/1.0.0::controls::Redshift.6 (disabled reason: Redshift is not running.)
- eu-north-1::standards::aws-foundational-security-best-practices/v/1.0.0::controls::Redshift.8 (disabled reason: Redshift is not running.)
- ap-south-1::standards::aws-foundational-security-best-practices/v/1.0.0::controls::Redshift.4 (disabled reason: Redshift is not running.)
- ap-south-1::standards::aws-foundational-security-best-practices/v/1.0.0::controls::Redshift.6 (disabled reason: Redshift is not running.)
[...]
- us-west-1::standards::aws-foundational-security-best-practices/v/1.0.0::controls::Redshift.6 (disabled reason: Redshift is not running.)
- us-west-1::standards::aws-foundational-security-best-practices/v/1.0.0::controls::Redshift.8 (disabled reason: Redshift is not running.)
- us-west-2::standards::aws-foundational-security-best-practices/v/1.0.0::controls::Redshift.4 (disabled reason: Redshift is not running.)
- us-west-2::standards::aws-foundational-security-best-practices/v/1.0.0::controls::Redshift.6 (disabled reason: Redshift is not running.)
- us-west-2::standards::aws-foundational-security-best-practices/v/1.0.0::controls::Redshift.8 (disabled reason: Redshift is not running.)

Plan: 0 to enable, 51 to disable

control-controls apply で適用します。

$ control-controls apply controls.yml
2022-04-14T15:43:37+09:00 INF Applying to eu-north-1
2022-04-14T15:43:46+09:00 INF Disable control Control=Redshift.4 Reason="Redshift is not running." Region=eu-north-1 Standard=aws-foundational-security-best-practice
s/v/1.0.0
2022-04-14T15:43:47+09:00 INF Disable control Control=Redshift.6 Reason="Redshift is not running." Region=eu-north-1 Standard=aws-foundational-security-best-practice
s/v/1.0.0
2022-04-14T15:43:49+09:00 INF Disable control Control=Redshift.8 Reason="Redshift is not running." Region=eu-north-1 Standard=aws-foundational-security-best-practice
s/v/1.0.0
2022-04-14T15:43:51+09:00 INF Applying to ap-south-1
2022-04-14T15:43:56+09:00 INF Disable control Control=Redshift.4 Reason="Redshift is not running." Region=ap-south-1 Standard=aws-foundational-security-best-practice
s/v/1.0.0
2022-04-14T15:43:57+09:00 INF Disable control Control=Redshift.6 Reason="Redshift is not running." Region=ap-south-1 Standard=aws-foundational-security-best-practice
s/v/1.0.0
[...]
2022-04-14T15:46:18+09:00 INF Disable control Control=Redshift.6 Reason="Redshift is not running." Region=us-west-1 Standard=aws-foundational-security-best-practices
/v/1.0.0
2022-04-14T15:46:19+09:00 INF Disable control Control=Redshift.8 Reason="Redshift is not running." Region=us-west-1 Standard=aws-foundational-security-best-practices
/v/1.0.0
2022-04-14T15:46:20+09:00 INF Applying to us-west-2
2022-04-14T15:46:26+09:00 INF Disable control Control=Redshift.4 Reason="Redshift is not running." Region=us-west-2 Standard=aws-foundational-security-best-practices
/v/1.0.0
2022-04-14T15:46:27+09:00 INF Disable control Control=Redshift.6 Reason="Redshift is not running." Region=us-west-2 Standard=aws-foundational-security-best-practices
/v/1.0.0
2022-04-14T15:46:29+09:00 INF Disable control Control=Redshift.8 Reason="Redshift is not running." Region=us-west-2 Standard=aws-foundational-security-best-practices
/v/1.0.0

Apply complete

GMOペパボでは全AWSアカウントのcontrol-controlsの設定ファイルを1つのGitHubリポジトリで管理するようにし、GitHub Actionsを使って

  • Pull Requestを作成すると control-controls plan を実行し、Dry-runの結果をコメント
  • mainブランチにマージすると control-controls apply を実行し、結果をPull Requestにコメント

と自動化しています。

設定ファイルを使った統制・管理

設定ファイルは次のような構成になっています。

autoEnable: true
standards:
  aws-foundational-security-best-practices/v/1.0.0:
    enable: true
    controls:
      disable:
        CodeBuild.1: CodeBuildは使用ないため無効化する
        CodeBuild.2: CodeBuildは使用ないため無効化する
        CodeBuild.4: CodeBuildは使用ないため無効化する
        CodeBuild.5: CodeBuildは使用ないため無効化する
        ElasticBeanstalk.1: ElasticBeanstalkは使用ないため無効化する
        ElasticBeanstalk.2: ElasticBeanstalkは使用ないため無効化する
  cis-aws-foundations-benchmark/v/1.2.0:
    enable: true
  pci-dss/v/3.2.1:
    enable: false
regions:
  eu-north-1:
    standards:
      aws-foundational-security-best-practices/v/1.0.0:
        enable: false
      cis-aws-foundations-benchmark/v/1.2.0:
        enable: false
  ap-south-1:
    standards:
      aws-foundational-security-best-practices/v/1.0.0:
        enable: false
      cis-aws-foundations-benchmark/v/1.2.0:
        enable: false
[...]
  eu-central-1:
    standards:
      aws-foundational-security-best-practices/v/1.0.0:
        enable: false
      cis-aws-foundations-benchmark/v/1.2.0:
        enable: false

standards.<standard>.* にベースとなる設定を記述します。これは全リージョンに適用されます。

もしリージョンごとに差分がある場合は regions.<region>.standards.<standard>.* に差分を記述することで、ベースの設定を上書き可能です。

上記の例では、使用しないリージョンについてセキュリティ標準自体を無効化しています。

コントロールの有効・無効の設定は standards.<standard>.controls.enablestandards.<standard>.controls.disable に記述しますが、無効設定のみ「無効理由」を強制するようになっています。

上記の例では、CodeBuildやElasticBeanstalkの関連コントロールを無効化しています。

また、リソース単位でのコントロールによるセキュリティチェックの無効化(抑制)も可能です。

例えばS3バケット arn:aws:s3:::static.example.com について、AWS Foundational Security Best Practices のコントロール S3.2のチェックを抑制する(SUPPRESSED)には次のように書くことができます。

standards:
  aws-foundational-security-best-practices/v/1.0.0:
    enable: true
    findings:
      S3.2:
        arn:aws:s3:::static.example.com:
          status: SUPPRESSED
          note: 秘匿すべき情報はない。また用途上Publicアクセスを無効にするのは難しい

--overlay オプションを使った統制・管理

設定ファイルを使った統制・管理は1AWSアカウントを想定しています。

--overlay オプションを活用することで、複数AWSアカウントをまたいだ統制・管理ができるようになります。

GMOペパボはインターネットサービスを多数展開しています

例えば、それぞれのサービスごとにAWSアカウントを分けているとします。

共通の設定を base.yml として作成し、それぞれのサービスごとのAWSアカウントごとの差分を [サービス].yml として記述します。

それらを次のように --overlay オプションを使用して実行することで、base.yml[サービス].yml の差分パッチを当てた状態で planapply を実行できます。

$ AWS_PROFILE=colorme control-controls apply base.yml --overlay colorme.yml
$ AWS_PROFILE=minne control-controls apply base.yml --overlay minne.yml
[...]

(実際には、AWSアカウントをまたいだAssumeRoleを活用して適用していますが、簡単のために AWS_PROFILE 環境変数で表現しています。)

まとめ

本エントリーでは、GMOペパボにおけるAWS Security Hubのコントロールの統制・管理の取り組みについて紹介しました。

今回は最終手段として「専用のツールを作る」ことを選択しました。

ユースケースを「AWS Security Hubのコントロールの統制・管理」に絞ったことで、記述量の少ない、GitHub Actionsで自動化された統制・管理構成を構築できたと思います。

もし同じような課題で困っている方がいらっしゃいましたら、 control-controls も検討してもらえると嬉しいです。

また、今回私たちが選択できなかった(AWS CDKを含む)AWS CloudFormationやTerraformといった、一般的によく使用されているIaCツールでの統制・管理方法についても聞いてみたいです。

知見をお持ちの方はぜひ広くインターネットに共有していただけると嬉しいです。

それでは良い夏休みを!