はじめに
RaiseTechの課題で、CloudFormationで環境構築をしました。
自分の理解を深めるために作成した環境のアウトプットをします。
参考:AWS CloudFormation テンプレートリファレンス
前々回の記事ではVPC、EC2、RDS、ALBについてアウトプットをしました。
前回の記事ではCloudWatch AlarmとSNSについてアウトプットをしました。
今回は、WAFについてアウトプットを行います。
テンプレート(抜粋)
#WAF
WebACL:
Type: AWS::WAFv2::WebACL
Properties:
Name: aws-study-alb-waf
Scope: REGIONAL
DefaultAction:
Allow: {}
VisibilityConfig:
CloudWatchMetricsEnabled: true
MetricName: aws-study-alb-waf
SampledRequestsEnabled: true
Rules:
- Name: AWS-AWSManagedRulesCommonRuleSet
Priority: 1
Statement:
ManagedRuleGroupStatement:
VendorName: AWS
Name: AWSManagedRulesCommonRuleSet
OverrideAction:
None: {}
VisibilityConfig:
MetricName: AWS-AWSManagedRulesCommonRuleSet
SampledRequestsEnabled: true
CloudWatchMetricsEnabled: true
WebACLAssociation:
Type: AWS::WAFv2::WebACLAssociation
Properties:
ResourceArn: !Ref ApplicationLoadBalancer
WebACLArn: !GetAtt WebACL.Arn
#WAF Log
WAFLogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: aws-waf-logs-alb-alc
RetentionInDays: 1
Tags:
- Key: Name
Value: aws-waf-logs-alb-alc
WAFLogConfig:
DependsOn:
- WAFToCloudWatchLogsPolicy
Type: AWS::WAFv2::LoggingConfiguration
Properties:
ResourceArn: !GetAtt WebACL.Arn
LogDestinationConfigs:
- !Sub arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:${WAFLogGroup}
WAFToCloudWatchLogsPolicy:
Type: AWS::Logs::ResourcePolicy
Properties:
PolicyName: WAFToCloudWatchLogsPolicy
PolicyDocument: !Sub |
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowWAFToLog",
"Effect": "Allow",
"Principal": {
"Service": "delivery.logs.amazonaws.com"
},
"Action": [
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:${WAFLogGroup}:*"
}
]
}
解説
AWS WAF(Web Application Firewall)
- セキュリティを強化するためのサービスの一つで、Webアプリを守るための防御フィルター
- WebサイトやAPIに届くリクエストをチェックして、悪意のあるアクセスをブロックする
- 例えば、ボット(自動攻撃プログラム)を検知して止めたり、特定の国やIPアドレスからのアクセスを拒否したりできる
- 例えるなら、Webアプリの入り口で検問してくれる門番。今回は、前回作成したALBの目の前に設置
Resources
WAFの作成
#WAF
WebACL:
Type: AWS::WAFv2::WebACL
Properties:
Name: aws-study-alb-waf
Scope: REGIONAL
DefaultAction:
Allow: {}
VisibilityConfig:
CloudWatchMetricsEnabled: true
MetricName: aws-study-alb-waf
SampledRequestsEnabled: true
Rules:
- Name: AWS-AWSManagedRulesCommonRuleSet
Priority: 1
Statement:
ManagedRuleGroupStatement:
VendorName: AWS
Name: AWSManagedRulesCommonRuleSet
OverrideAction:
None: {}
VisibilityConfig:
MetricName: AWS-AWSManagedRulesCommonRuleSet
SampledRequestsEnabled: true
CloudWatchMetricsEnabled: true
Web ACLの作成。
Web ACLとは、Web Access Control Listの略で、Webサイトへのアクセスを「どのルール(List)」で「制御(Control)」するかをまとめたルールセットのこと。
「海外からの怪しいアクセスは止める」「ボットは止める」といった個別のルールを1つのWeb ACLというリストにまとめ、それをALBなどに適用する。
- Name:Web ACLの名前
- Scope:Amazon CloudFrontディストリビューション用かリージョンアプリケーション用かを指定する。今回はリージョンアプリケーション用なので、REGIONALを指定
- DefaultAction:Webサイトへのアクセスが、Web ACLに載っているどのルールにも当てはまらなかった時に、実行するアクションを決める。Allowは通す、Blockは止める。「Allow: {}」で、どのルールにも当てはまらなかったアクセスを、原則として通す設定になる
- VisibilityConfig:WAFが攻撃をブロックしたときに、あとで人間が確認できるように、証拠を残すための設定。具体的には、CloudWatchでグラフを表示するための設定
- CloudWatchMetricsEnabled:「何件ブロックしたか」という数を、CloudWatchのグラフに表示するかどうかを決める
- MetricName:グラフの名前
- SampledRequestsEnabled:アクセスをブロックしたときに、「具体的にどんな変なリクエストが来たのか」というデータを保存して、コンソール画面で見られるようにするかどうかの設定
- Rules:ルールセットの具体的な中身
- Name:ルールの名前
- Priority:ルールの優先順位。複数のルールがある場合、数字が小さいものから順番にチェックされる。今回は1つだけなので1を指定
- Statement:チェックする項目
- ManagedRuleGroupStatement:AWSが用意しているルールセットを呼び出すための合図。一から自分でチェック項目を書くのは大変なので、既存のものを使用。使用するには、ベンダー名とルールグループ名を指定する必要がある
- VendorName:管理対象ルールグループのベンダー名。ルールグループ名と併せて使用して、ルールグループを識別する
- Name:管理対象ルールグループの名前。ベンダー名と併せて使用してルールグループを識別する
- AWSManagedRulesCommonRuleSet:コアルールセット。Webサイトを運用する上で最低限防いでおきたい、一般的な攻撃(OWASP Top 10など)をまとめてガードしてくれる(参考:Baseline rule groups)
- OverrideAction:ルールグループ内のルールに適用するオーバーライドアクション。デフォルトアクション以外のものを適用するかどうかを決める。「None: {}」でなしの設定
- VisibilityConfig:CloudWatchでグラフを表示するための設定。ここで設定するのは、ルール単体でのブロックグラフを表示する設定。「WAF全体のグラフ」と、「そのルール単体でのグラフ」を、それぞれ別々に名前をつけて管理できるようになっているので、個々のルール内でも設定する
- MetricName:グラフの名前
- SampledRequestsEnabled:アクセスをブロックしたときに、「具体的にどんな変なリクエストが来たのか」というデータを保存して、コンソール画面で見られるようにするかどうかの設定
- CloudWatchMetricsEnabled:「何件ブロックしたか」という数を、CloudWatchのグラフに表示するかどうかを決める
WebACLAssociation:
Type: AWS::WAFv2::WebACLAssociation
Properties:
ResourceArn: !Ref ApplicationLoadBalancer
WebACLArn: !GetAtt WebACL.Arn
リソースとWeb ACLを紐付ける。
紐付けることで、WAFが機能するようになる。
- ResourceArn:Web ACLに紐付けるリソースのARN
- WebACLArn:リソースに紐付けるウェブACLのARN
WAF Logの作成
WAFのログをCloudWatch Logsに出力する設定も行いました。
#WAF Log
WAFLogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: aws-waf-logs-alb-alc
RetentionInDays: 1
Tags:
- Key: Name
Value: aws-waf-logs-alb-alc
ロググループの作成。
ロググループは、ログの保存先のこと。
- LogGroupName:ロググループの名前。必ず「aws-waf-logs-」で始まる必要がある
- RetentionInDays:指定されたロググループにログイベントを保持する日数。今回は学習用なので1日
WAFLogConfig:
DependsOn:
- WAFToCloudWatchLogsPolicy
Type: AWS::WAFv2::LoggingConfiguration
Properties:
ResourceArn: !GetAtt WebACL.Arn
LogDestinationConfigs:
- !Sub arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:${WAFLogGroup}
ログの保存先とWeb ACLを紐付ける。
- DependsOn:WAFToCloudWatchLogsPolicy(許可証)が作成された後に、WAFLogConfig(ログ設定)を作成するよう順番を指定。CloudFormationは通常、自動で作成順序を判断してくれるが、「権限(ポリシー)」と「それを利用するリソース」の間では、順番が前後してエラー(「ログを送る権限がありません」)になる恐れがあるため、安全策として
- ResourceArn:ログの保存先に紐付けるWeb ACLのARN
- LogDestinationConfigs:Web ACLに紐付けるログの保存先。ARNを指定
!GetAtt関数でARNを取得すると末尾に「: *」がつく。「: *」がついていると、「ロググループ内のすべてのログストリーム」を指してしまい、「ロググループそのもの」であることを示せずに、設定エラーになることがある。そのため!Sub関数を使用して、LogGroupのARNを渡すようにしている。
WAFToCloudWatchLogsPolicy:
Type: AWS::Logs::ResourcePolicy
Properties:
PolicyName: WAFToCloudWatchLogsPolicy
PolicyDocument: !Sub |
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowWAFToLog",
"Effect": "Allow",
"Principal": {
"Service": "delivery.logs.amazonaws.com"
},
"Action": [
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:${WAFLogGroup}:*"
}
]
}
WAFがCloudWatch Logsにログを書き込むための権限設定。
WAFというサービスが、CloudWatch Logsという別のサービスに、勝手にログを書き込むことはできない。そのため、「このサービス(delivery.logs.amazonaws.com)なら書き込んでもいい」という特別な許可証(ResourcePolicy)をあらかじめ発行しておく必要がある。
- PolicyName:リソースポリシーの名前
- PolicyDocument:ポリシーの詳細。JSON形式で記述する必要がある
組み込み関数
!GetAtt
- 指定した特定の属性値(ARN, IP, DNS等)を返してくれる関数
!Sub
- 文字列の一部を指定した変数の値に置き換えてくれる関数
終わりに
WAFの作成もコンソール画面の偉大さを思い知らされました。難しかった...でも、一度テンプレートにしてしまえば、次からはボタン一つでこの複雑な設定が再現できるので、それがCloudFormationの強みだと思いました。
作成している時は勢いで作っているところもありましたが、時間をおいて改めて見返してみると、確かになぁと思うところがありました。VisibilityConfigをなぜ2回書くのかなど。それから、公式ドキュメントの読み込みもテクニックが必要。
CloudFormationで構築した環境のアウトプットは、今回で以上です。
次回は、CloudFormationで構築した環境をTerraformで再現してみたものをアウトプットします。