AWS マルチアカウント運用下で WafCharm を追加構築する場合の手順

記事タイトルとURLをコピーする

マネージドサービス部 佐竹です。
久しぶりに WafCharm の構築を行ったのですが、マルチアカウントの場合に少々戸惑うことがあったので、備忘録として注意点をまとめたブログを記載します。

はじめに

2020年8月に、以下の通り WafCharm の環境構成図を解説するブログを記載しました。

blog.serverworks.co.jp

ただし、当時は1つの AWS アカウントに実装しておりクロスアカウントを行っていませんでした。

現在、AWS の運用はマルチアカウントが前提になっていることが多い状況です。そしてマルチアカウント構成においては、S3 に出力するログを「ログアーカイブアカウント」に集約する構成を取ることがあります。

今回は、ログアーカイブアカウントがある状況での WafCharm 構築について記載していきます。

補足ですが、ログアーカイブアカウントについては以下に記載しております。ご参考まで。

blog.serverworks.co.jp

AWS 環境構成図

先に全体像を示します。

WafCharm マルチアカウント 構成図

本構成の前提条件は以下の通りです。

  • WafCharm の契約は組織で共通して1つのみ
  • WafCharm を実装する AWS アカウント は「A」と「B」の2つがある
  • WafCharm の実装先は各アカウントの CloudFront のみ
  • ログは「ログアーカイブアカウント(中央)」の S3 バケットに全て集約する
  • 既に AWS アカウント A では WafCharm が実装済

この状況で、AWS アカウント B にWafCharm を追加実装して行く手順を記載します。

手順

前提として、正式な手順は WafCharm が提供しているものをまずはご確認ください。

www.wafcharm.com

ただ、WafCharm が提示している手順に、マルチアカウントに対応したものがなさそうだったため、本ブログはその補足のような立ち位置となっています。

AWS WAF の作成

まずは AWS アカウント B で AWS WAF を作成して、CloudFront と紐付けを行っていきます。

構成図では画像左下の黄色い枠にあたります。

AWS マネジメントコンソールにおいて、「AWS WAF>Web ACLs>Create web ACL」から作業を行います。

Describe web ACL and associate it to AWS resources

AWS WAF の Web ACL には一意となる名称が必要です。命名規則がある場合はそれに従って入力してください。

Web ACL とリソースの紐付けは後からでも問題ありません。既に紐付け先のリソースが作成済の場合はこのタイミングで紐付けを行います。

後でこの作業を行う場合は、忘れずに紐付けを実行してください。

Add rules and rule groups

このあたりは WafCharm が後で自動的に設定してくれるため、特に設定は不要ですのでこのまま次に行きます。

続きの「Set rule priority」と「Configure metrics」でも同様です。

Review and create web ACL

問題が無ければ「Create web ACL」を押下して作成します。

確認

作成されたばかりの WAF の Web ACL はルールが空の状態ですが、この後 WafCharm によって追加されるため、まずは空であることを確認しておきます。

AWS WAF のログ出力設定

次に WafCharm のレポートで必要な AWS WAF のログ出力設定を行います。

AWS WAF のログは現在直接 S3 バケットに出力ができるのですが、バケットの命名規則が存在します。

AWS WAF ログ記録用のバケット名は aws-waf-logs- で始まる必要があり、末尾は任意のサフィックスにすることができます。

https://docs.aws.amazon.com/ja_jp/waf/latest/developerguide/logging-s3.html

この命名規則があるおかげで、事前に組織で取り決めていた S3 バケットの命名規則を守れない場合があります。

今回はログアーカイブアカウントのバケット命名規則を優先し、AWS WAF からバケットに直接出力せず Kinesis Data Firehose を利用する設計としています。

構成図では画像下部の黄色い枠にあたります。

Amazon Kinesis Data Firehose を経由して AWS WAF のログを S3 バケットへと出力する手順は以下の AWS 公式ドキュメント、そして WafCharm 提供のドキュメントも合わせて参考にしてください。

docs.aws.amazon.com

仮の S3 バケットの作成

Web ACL を作成した AWS アカウント(AWS アカウント B)で、まずは「作業用の S3 バケット」を一時的に作成します。

これは、可能な限りマネジメントコンソールからの作業で対応したいために行っている回避策です。まずは仮作成した S3 バケットへの出力設定を AWS アカウント B で完結させた後に、その S3 バケットをログアーカイブアカウントの S3 バケットへと変更するようにしています。

今回 waf-logging-kinesis-firehose-test-bucket-stg という名称で仮のバケットを作成しています。

Kinesis Data Firehose の作成

AWS アカウント B で引き続き作業を行います。

今回 CloudFront 用の出力のため、先にバージニアリージョンを選択しておきます。

そして Amazon Kinesis Data Firehose>Data Firehose>Create delivery stream から作業を開始します。

その後、Direct Put を選択し、Destination に Amazon S3 を選択します。

Delivery stream name は適切に設定してください。加えて、AWS WAF で利用する場合にもこの名前を aws-waf-logs- の prefix から開始する必要がある点に注意してください。

Destination settings では、先ほど仮作成したバケットを選択します。

Buffer hints, compression and encryption

なお、WafCahrm レポートのためには Buffer hints, compression and encryption の設定を開き「Compression for data records」で「GZIP」を選択する必要があります。

また、Buffer interval は 60 秒が推奨とのことです(デフォルト 300 秒)。

Advanced settings を確認します。ここで Kinesis Data Firehose 用の IAM Role を合わせて作成してくれるため、これを有効活用します。

この後 ログアーカイブアカウントにおいて S3 のバケットポリシーを設定するタイミングがありますが、この時に「既に存在する Arn」を Principal で指定する必要があり、先に Kinesis 側の IAM Role の作成が必要となります。よって、ここで自動生成される IAM Role の Arn を後でバケットポリシーに利用することになります。

問題がなければ、Create delivery stream を押下して作成します。

IAM Role の Arn を取得する

Data Firehose と同時に作成された IAM Role の Arn を取得します。

今回、例として arn:aws:iam::123456789012:role/service-role/KinesisFirehoseServiceRole-aws-waf-logs--us-east-1-0123456789012 を取得しました。

「AWS アカウント B」の S3 バケットに AWS WAF のログが出力されるところまでは作業が完了したため、続けてこれをログアーカイブアカウントへの出力に変更していきます。

S3 バケットの作成とポリシーの設定 (ログアーカイブアカウント)

作業アカウントを変更するため、ログアーカイブ(保管)アカウントにスイッチロールします。

ログアーカイブアカウントに作成した(もしくは既に作成済の) S3 バケットへ、以下に後述する JSON のポリシーを記載し、Kinesis からの Put を受け入れられるようにします。

バケットポリシーは以下の AWS 公式ドキュメント内「Cross-Account Delivery to an Amazon S3 Destination」を参考にしています*1

docs.aws.amazon.com

先程主取得した「AWS アカウント B」の IAM Role を追加する場合は、以下の通り Pricipal に追記します。

{
    "Version": "2012-10-17",
    "Id": "Kinesis-aws-waf-logs-for-waf-charm",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": [
                    "arn:aws:iam::123456789011:role/service-role/KinesisFirehoseServiceRole-aws-waf-logs--us-east-1-0123456789011",
                    "arn:aws:iam::123456789012:role/service-role/KinesisFirehoseServiceRole-aws-waf-logs--us-east-1-0123456789012"
                ]
            },
            "Action": [
                "s3:AbortMultipartUpload",
                "s3:GetBucketLocation",
                "s3:GetObject",
                "s3:ListBucket",
                "s3:ListBucketMultipartUploads",
                "s3:PutObject",
                "s3:PutObjectAcl"
            ],
            "Resource": [
                "arn:aws:s3:::bucketName",
                "arn:aws:s3:::bucketName/*"
            ]
        }
    ]
}

上記は一例です。"Principal" に記載された IAM Role の Arn と "Resource" に記載されたバケット名 (bucketName) は適宜修正してご利用ください。

Kinesis 用 IAM Role の権限を修正する

まず作業アカウントを変更するため、AWS アカウント B にスイッチロールしなおします。

Kinesis Data Firehose の設定で、出力先のバケットを「仮作成したバケットからログアーカイブアカウントが持つ集約用バケットに差し替える」にあたり、先に自動作成された「AWS アカウント B」の IAM Role arn:aws:iam::123456789012:role/service-role/KinesisFirehoseServiceRole-aws-waf-logs--us-east-1-0123456789012 にアタッチされている IAM ポリシーで修正が必要になります。

現在は出力先が仮作成した S3 バケット waf-logging-kinesis-firehose-test-bucket-stg になっているため、これを先のバケットポリシーを記載した S3 バケット名に合わせるよう修正します。

IAM ポリシーの編集画面から、"arn:aws:s3:::waf-logging-kinesis-firehose-test-bucket-stg" を適切なバケット名に修正します。修正箇所は上画像にある通り、JSON の中ほどにある「2か所」だけとなります。

Kinesis Data Firehose の出力先バケットを修正する

Kinesis Data Firehose の出力先 S3 バケットをログアーカイブアカウントの持つ集約用バケットに設定変更するには、クロスアカウントアクセスの設定が必要です。

しかし、この設定変更作業がマネジメントコンソールから実装できないため、AWS CLI (AWS CloudShell) を利用します。

describe-delivery-stream (実施前の確認)

まずは describe-delivery-stream コマンドで、現在の設定を確認します。delivery-stream-name は適切に修正してください。

aws firehose describe-delivery-stream --delivery-stream-name aws-waf-logs-aws-waf-logging-firehose

返り値を確認し、「version-id」と「destination-id」を取得します。

また、S3 バケットの出力先の変更前の値も見ておくとよいでしょう。

update-destination

次に update-destination コマンドを実行します。

「version-id」と「destination-id」は先ほど取得した値を利用します。

以下は一例であるため、必要に応じて引数は修正してください。

aws firehose update-destination \  
--delivery-stream-name aws-waf-logs-aws-waf-logging-firehose \  
--current-delivery-stream-version-id 1 \  
--destination-id destinationId-000000000001 \  
--s3-destination-update BucketARN=arn:aws:s3:::bucketName,Prefix=o-prefix/accountID/aws-waf-logs-aws-waf-logging-firehose/

正しく実行された場合、返り値はありません。

describe-delivery-stream (実施後の確認)

再度同コマンドを実行し、設定変更前後の JSON で Diff を取って変更された値を確認しておきます。

aws firehose describe-delivery-stream --delivery-stream-name aws-waf-logs-aws-waf-logging-firehose

もしくは上画像の通りマネジメントコンソールから Kinesis Data Firehose の Configuration を確認して S3 バケットが変更されていることを確認します。

不要な S3 バケットの削除

仮で作成した「waf-logging-kinesis-firehose-test-bucket-stg」は不要になったためバケットごと削除します。

AWS WAF のログ設定(Kinesis と WAF の紐付け)

Kinesis Data Firehose が完成したため、これを AWS WAF の WAF ACL に紐付けます。

「Logging and metrics」タブを開き、Logging 欄の「Enable」を押下し AWS WAF > Web ACLs > waf-acl-cloudfront > Enable logging から作業を行います。

Logging destination で、「Kinesis Data Firehose stream」を選択し、先ほど作成した Data Firehose を一覧から選択します。なお、ここに作成した Data Firehose が表示されない場合、Data Firehose のリージョンを誤っている可能性が高いでしょう。

設定はこれ以外特に不要なため「Save」を押下して設定を反映します。

正しく設定が完了したかどうか、念のため確認しておきます。

WafCharm の Web ACL Config の設定

WafCharm には「AWS アカウント A」の IAM Role が既に作成済という状況ですが、この WafCharm Credential Store 設定は(もちろんながら)使いまわせないため、「AWS アカウント B」で新規に WafCharm Web ACL Config 用の IAM Role を作成します。

構成図では、画像左下にある「IAM Role B」の作成を行うこととなります。

改めて説明となりますが、今回 AWS WAF の Web ACL と CloudFront は同じ AWS アカウント(アカウント B)に実装してあります。

しかし、そのログを保存する AWS アカウントはログアーカイブアカウントとしてそれ専用となっており、AWS アカウントを跨いだ実装となっています。

このため、WafCharm を1つの AWS アカウントで実装する場合には共有(使いまわし)が可能な「①Web ACL Config 用の Credential Store」と「②Web Site Config 用 の Credential Store」が別々に必要となります。つまり AWS アカウントごとに IAM Role を作成する手順となります。

なお、既に WafCharm が1つでも設定がされている場合には「②Web Site Config 用 の Credential Store」では既存の Credential Store が引き続き使えるため「①Web ACL Config 用の Credential Store」を新規に追加するだけで問題ありません。

ということで「①Web ACL Config 用の Credential Store」を設定する手順に戻ります。

今回設定で注意すべき点は「Choose AWS Service Type」で「CloudFront」を選択する点と、「Credential Store」で「+ Add」を押下して設定を追加する点です。

また、設定には AWS WAF の Web ACL ID が必要なため、事前に手元に保存してから作業を行うと良いでしょう。

Web ACL Config 用の IAM Role の作成

新規に Web ACL Config を作成する場合、紐づける IAM Role の作成が必要です。

この時、WafCharm の Web ACL Config 用の IAM Role には以下の権限を付与します。

  1. AWSWAFFullAccess
  2. CloudWatchReadOnlyAccess

ここで S3 バケットの閲覧権限は不要です。

これ以外の作業については、WafCharm の手順通りに実装してください。

WAF ACL に追加されたルールの確認

WafCharm の Web ACL Config の設定が正しく完了すると、WafCharm がすぐに基本的なルールを AWS WAF に追加します。

よって、ルールが追加されているかをすぐに確認します。

もし WafCharm のルールが追加されていない場合、設定に不備がある可能性が高いため、見直しを行ってください。

WafCharm の Web Site Config の設定

WafCharm の Web Site Config の設定は、マルチアカウントにおいてはログアーカイブアカウントの CloudFront 用(もしくはその他のサービス用)の S3 バケットを閲覧する権限のみ必要になります。

このため、先に記載した通り WafCharm 用の IAM Role を予めログアーカイブアカウントに作っておく場合は Credential Store としてそれを常に利用可能です*2

今回は既に存在している IAM Role「iam-role-wafcharm-web-site-config」を使って設定を行います。

IAM Policy の厳格化(オプション)

なお、デフォルトの手順では、Web Site Config の設定に必要な IAM ポリシーは、AWS Managed Policy の「AmazonS3FullAccess」となっています。ただこの権限は全 S3 バケットが対象となり強力であるため、我々の場合は以下のようにポリシーを個別に記載してアタッチしています。

名前は「iam-policy-wafcharm-web-site-config」などとして作成します。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:Get*",
                "s3:List*",
                "s3:Describe*",
                "s3-object-lambda:Get*",
                "s3-object-lambda:List*"
            ],
            "Resource": [
                "arn:aws:s3:::bucketName-cloudfront-log",
                "arn:aws:s3:::bucketName-cloudfront-log/*"
            ]
        }
    ]
}

このように修正することで、Web Site Config の IAM Role の権限をほぼ必要最低限まで狭めることができます。

Web Site Config の追加

WafCharm の設定画面から追加を行います。

最初に Web ACL Config は正しいものを選択します。これを間違えると意図しない WAF ACL に紐づいてしまうため注意してください。

FQDN と、S3 Path は適切な値を入力します。今回であれば「AWS アカウント A」の設定を参考にすると良いでしょう。

Credential Store Option は AWS WAF と CloudFront のログ用バケットが別アカウントの場合「Reuse Web ACL Credential Store」を利用できないため、本チェックを外します

構成図で説明すると、上画像の通りです。

引き続き設定ですが、Credential Store は既存の IAM Role「iam-role-wafcharm-web-site-config」を選択します。

新規作成が必要な場合には「+ Add」から作成してください。「+ Add」での Credential Store 作成後は、WafCharm 画面内の Credential Store に意図した Credential が設定されているか確認を怠らず行ってください*3

設定完了後「Save」を押下し保存します。

画面遷移後 Resource State が「検証済み」になることを確認してください。

WAF でブロックが行われるかの動作確認

ここまで設定すれば正しく設定が完了しています*4

AWS WAF で正しくブロックが行われるかどうかは、XSS や SQL injection のような攻撃を疑似的に行うと良いでしょう。

403 ERROR
The request could not be satisfied.

上記のエラーがブラウザで表示されることを確認したら、AWS WAF のコンソールか、CloudFront Security Dashboard を利用して実際にブロックカウントが増加しているか確認します。

ログを見ると、AWS WAF で無事にブロックがされていることがわかりました。

403 Forbidden error について

AWS WAF でブロックが行われた場合、以下の re:Post に記載があるように「403 Forbidden error」が発生します。

If a request matches an AWS WAF rule that is set to Block, then by default AWS WAF returns a 403 Forbidden error.

repost.aws

まとめ

本ブログでは、AWS マルチアカウント運用下で WafCharm を追加構築する場合の手順を記載しました。

ご紹介したようにマルチアカウントでログアーカイブアカウントを分離している場合には、少々手間がかかる設定追加を毎回行わなければなりません。

本ブログの内容が WafCharm の設定ミスの回避に少しでも役立てば幸いです。

では、またお会いしましょう。

*1:S3 バケットポリシーには "s3:PutObjectAcl" が必要と AWS ドキュメントに記載がありますが、自動作成される Kinesis Data Firehose 用の IAM Role にはこの権限がないため、"s3:PutObjectAcl" は記載が不要かもしれません

*2:ただし、必要最低限のポリシーを付与している場合は分離する必要があります

*3:新規に Credential を作成した場合、正しく割り当てされない可能性があります

*4:Lambda を利用した WafCharm 月次レポートの出力設定もログアーカイブアカウントに既に設定済の場合は追加の実装は不要です

佐竹 陽一 (Yoichi Satake) エンジニアブログの記事一覧はコチラ

マネージドサービス部所属。AWS資格全冠。2010年1月からAWSを利用してきています。2021-2022 AWS Ambassadors/2023 Japan AWS Top Engineers/2020-2023 All Certifications Engineers。AWSのコスト削減、最適化を得意としています。