はじめに
AWS WAF はフルマネージドで便利なファイアウォールであり、インターネットに面したゲートウェイ機能を有するシステムをお手軽に構築するなら、ほぼ必須で使うことになるサービスだろう(自前で手塩にかけて育てたWAFを持っているのであれば話は別だろうけど)。
ということで、お手軽に使える AWS WAF をお手軽に Terraform で構築しつつ基礎を理解していく。
インテグレーションは API Gateway を使う。
今回作る「IPアドレス制限」だけであれば、API Gateway のリソースポリシーを使った方が手っ取り早い。あくまでも練習のためにやっていると考えていただきたい。
IPアドレス制限する AWS WAF の基本セット
今回の構成では、ブラックリスト形式で実施する。
ルール設定に必要になる Terraform のリソースは以下の2種類。
- aws_wafv2_web_acl
- aws_wafv2_ip_set
今回の設定は練習であり、マネージメントコンソールにも注意書きがあるように、ブラックリストとしては実質的に意味がないということは留意しておくこと。
When a request comes through a CDN or other proxy network, the source IP address identifies the proxy and the original IP address is sent in a header. Use caution with the option, IP address in header, because headers can be handled inconsistently by proxies and they can be modified to bypass inspection.
Web ACL 本体とルールの設定
Web ACL は以下のように定義する。
resource "aws_wafv2_web_acl" "iprestriction" {
name = local.webacl_name
description = "TEST IP Adress Restriction"
scope = "REGIONAL"
default_action {
allow {}
}
rule {
name = "iprestriction"
priority = 1
action {
block {}
}
statement {
ip_set_reference_statement {
arn = aws_wafv2_ip_set.test.arn
}
}
visibility_config {
cloudwatch_metrics_enabled = false
metric_name = local.webacl_iprestriction_metric_name
sampled_requests_enabled = false
}
}
visibility_config {
cloudwatch_metrics_enabled = false
metric_name = local.webacl_metric_name
sampled_requests_enabled = false
}
}
visibility_config
は今の段階では使わないものの、必須パラメータなので設定しておく。
default_action
も必須パラメータで、ここでブラックリストにするかホワイトリストにするかを指定するようなイメージだ。デフォルトが allow
であればブラックリストといった感じだ。
IPアドレスリストの設定
aws_wafv2_web_acl
側でIPアドレス制限を直接書くのではなく、IPアドレスセットのリソースを準備し、それと比較するようなかたちになっている。おそらく、複数のルール間でお手軽に共通化ができるように、という思想なのだろうと推測。
resource "aws_wafv2_ip_set" "test" {
name = "test"
description = "TEST IP set"
scope = "REGIONAL"
ip_address_version = "IPV4"
addresses = [
"xxx.xxx.xxx.xxx/32",
]
}
アドレスはCIDRで指定する。今回はIPアドレスを1つだけ block したいので、/32
を指定する。
API Gateway とインテグレーションする
さて、せっかくルールを作ってもインテグレーションしなければ意味がない。
インテグレーションには以下の Terraform リソースを使う。
- aws_wafv2_web_acl_association
使い方は簡単で、API Gateway と AWS WAF の ARN を繋ぐだけで良い。
API Gateway は REST API そのものではなくてステージと連動するという点だけ注意だ。
resource "aws_wafv2_web_acl_association" "iprestriction" {
resource_arn = aws_api_gateway_stage.prod.arn
web_acl_arn = aws_wafv2_web_acl.iprestriction.arn
}
動作確認する
さて、本当にこれでIPアドレス制限されるのかを試してみよう。
IPアドレスリストに設定していないIPアドレスでアクセスした場合、
{
"data": {
"hoge": "hige"
},
"errorMessage": ""
}
と正しく取得され、リストに設定したIPアドレスでアクセスすると
{"message":"Forbidden"}
と表示される。その他、curl -i
で取得されるヘッダ情報としては以下。
HTTPステータスコードは 403 として返却される。
HTTP/2 403
content-type: application/json
content-length: 23
date: Sun, 06 Dec 2020 02:57:37 GMT
x-amzn-requestid: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
x-amzn-errortype: ForbiddenException
x-amz-apigw-id: xxxxxxxxxxxxxxxx
x-cache: Error from cloudfront
via: 1.1 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.cloudfront.net (CloudFront)
x-amz-cf-pop: NRT12-C4
x-amz-cf-id: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
API Gateway の HTTPステータスコードやワーディングの変更
API Gateway とインテグレーションする場合は、HTTP ステータスコードや応答の JSON はゲートウェイのレスポンスで変更可能だ。api_gateway_gateway_response
リソースの response_type = "WAF_FILTERED"
を使えば Terraform でもできる(詳細は記事を参照)。
API Gateway のログ出力
API Gateway とインテグレーションする場合は、AWS WAF とのやり取りをアクセスログに出力することができる。アクセスログの設定に関する詳細は、手前味噌だがこの記事が分かりやすいと思う。
AWS WAF に関連する項目の出力例は以下の通り。
"waf_response_code": "$context.wafResponseCode",
"webacl_arn": "$context.webaclArn",
"waf_error": "$context.waf.error",
"waf_latency": "$context.waf.latency",
"waf_status": "$context.waf.status",
これで実際に出力されたアクセスログを確認すると、以下のように出力される。
"waf_response_code": "WAF_ALLOW",
"webacl_arn": "arn:aws:wafv2:ap-northeast-1:xxxxxxxxxxxx:regional/webacl/waf-iprestrict-test-webacl/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"waf_error": "-",
"waf_latency": "7",
"waf_status": "200"
"waf_response_code": "WAF_BLOCK",
"webacl_arn": "arn:aws:wafv2:ap-northeast-1:xxxxxxxxxxxx:regional/webacl/waf-iprestrict-test-webacl/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"waf_error": "-",
"waf_latency": "7",
"waf_status": "403"
AWS マネージメントコンソールでの確認
上記で作ったリソースをマネージメントコンソールで確認すると以下のようになる。
iprestriction
のルールを選択して、右上の Edit
ボタンを押すと、以下のようにルール編集画面で設定内容を確認できる。
API Gateway とのインテグレーションに関する設定は以下。
IPアドレスリストに関する設定は以下。
基本のルール設定編はここまで。