この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
こんにちは。 ご機嫌いかがでしょうか。 "No human labor is no human error" が大好きな吉井 亮です。
2019年11月25日(アメリカ時間) に AWS Managed Rules for AWS WAF が公開されています。 AWS WAF 導入へのハードルがかなり低くなってきたと感じています。 弊社カジもアップデート記事を書いています。
AWS Managed Rules for AWS WAF をデプロイする CloudFormation テンプレートを作成してみました。 このテンプレートを実行すると以下のようなリソースがデプロイされます。
ルール
テンプレートを実行するとこのようなルールが入ります。
ルール名 | アクション | 優先度 |
---|---|---|
Custom-IPaddress-BlackList | Count | 0 |
AWS-AWSManagedRulesAmazonIpReputationList | Count | 1 |
AWS-AWSManagedRulesCommonRuleSet | Count | 2 |
AWS-AWSManagedRulesKnownBadInputsRuleSet | Count | 3 |
AWS-AWSManagedRulesLinuxRuleSet | Count | 4 |
AWS-AWSManagedRulesUnixRuleSet | Count | 5 |
Custom-Ratebased | Count | 6 |
Custom-IPaddress-BlackList
接続を拒否する IP アドレスを指定します。 これはマネージドルールではなくユーザー管理のルールです。
AWS-AWSManagedRulesAmazonIpReputationList
通常ボットやその他の脅威に関連付けられている IP アドレスをブロックする場合に役立ちます。 ここの IP アドレスは AWS 管理です。
AWS-AWSManagedRulesCommonRuleSet
Web アプリケーション防御の一般的なルールが含まれています。 OWASP 出版物や CVE で解説されている脆弱性を含んでいます。 AWS 管理のルールです。
AWS-AWSManagedRulesKnownBadInputsRuleSet
脆弱性や悪用のあるパターンに報告されているインプットをブロックするルールが含まれています。 AWS 管理のルールです。
AWS-AWSManagedRulesLinuxRuleSet
Linux 固有の LFI 攻撃を防ぐルールが含まれています。 AWS 管理のルールです。 次の AWS-AWSManagedRulesUnixRuleSet と組み合わせて使用します。
AWS-AWSManagedRulesUnixRuleSet
POSIX 固有の LFI 攻撃を防ぐルールが含まれています。 AWS 管理のルールです。
Custom-Ratebased
5分間で100リクエスト (調整可能) 以上送信してくる IP アドレスをブロックします。 このルールには IP アドレスホワイトリストが含まれており ホワイトリストに載っている IP アドレスはリクエスト数に関係なく無条件に許可します。 ホワイトリストには自社拠点などを指定します。
やってみた
CloudFormation スタック
本エントリの末に記載した CloudFormation テンプレートをローカルに保存してカスタマイズします。
カスタマイズしたテンプレートを使って CloudFormation スタックを作成します。
値 | 説明 |
---|---|
スタックの名前 | 任意の名称 |
BucketName | WAF ログを保存する S3 バケット名。{BucketName}-{アカウントID} になります。 |
WebACLName | WebACL の名称です。任意の名称を指定 |
WAF v2 ロギング
しばらくするとリソースが作成されます。 マネジメントコンソールで WebACL を開いてみます。 CloudFormation スタックを流したリージョンを選択すると無事に WebACL が作成されていることを確認できると思います。
その WebACL をクリックして、Logging and metrics タブを開きます。 Logging が Disabled になっています。 Enable logging をクリックします。
Amazon Kinesis Data Firehose Delivery Stream のドロップダウンから aws-waf-logs-リージョン-WebACL名称 を選択します。 Redacted Fields を任意で選択します。 Enable logging をクリックします。
関連付け
関連付けをします。 同じく WebACL の画面で Associated AWS resources タブを開きます。
Add AWS Resources をクリックします。
関連付けたいリソースを選択します。 Add をクリックします。
アクションの変更
テンプレートを使って作成した WebACL のルールは アクションがカウントになっています。 この状態で十分なテストを行って過検知がないことの確認や 細かい修正を行ってアクションをブロックなどに変更します。
CloudFormation テンプレート
テンプレートはカスタマイズしてお使いください。
カスタマイズ1
AWS::WAFv2::WebACL のプロパティで scope が REGIONAL になっています。 これは ALB または API Gateway 用のテンプレートです。 CloudFront 用の WebACL を作る場合は CLOUDFRONT へ変更します。
カスタマイズ2
IPWhiteList には無条件で許可する IP アドレスを IPBlackList には接続を拒否する IP アドレスを記述ください
カスタマイズ3
WebACL に付けるルールは要件に合わせて増減してください。 AWS 管理のルール一覧は こちら です。
カスタマイズ4
ルール名 Custom-Ratebased の設定値 limit: 100 を 要件に合わせて調整してください。
AWSTemplateFormatVersion: 2010-09-09
Description: WAF v2 Web ACL
Parameters:
WebACLName:
Description: The Name of WebACL.
Type: String
BucketName:
Type: String
Description: The name for the bucket.
Default: waf-logs
Resources:
### Waf logs bucket
S3Backet:
Type: "AWS::S3::Bucket"
Properties:
BucketName: !Sub ${BucketName}-${AWS::AccountId}
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: AES256
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
### Firehose
DeliveryStream:
Type: "AWS::KinesisFirehose::DeliveryStream"
Properties:
DeliveryStreamName: !Sub aws-waf-logs-${AWS::Region}-${WebACLName}
DeliveryStreamType: DirectPut
S3DestinationConfiguration:
BucketARN: !GetAtt S3Backet.Arn
BufferingHints:
IntervalInSeconds: 300
SizeInMBs: 5
CompressionFormat: GZIP
RoleARN: !GetAtt FirehoseRole.Arn
### IAM Role for firehose
FirehoseRole:
Type: AWS::IAM::Role
Properties:
Path: '/'
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service:
- firehose.amazonaws.com
Action:
- sts:AssumeRole
Condition:
StringEquals:
sts:ExternalId: !Sub ${AWS::AccountId}
Policies:
-
PolicyName: firehose_delivery_role
PolicyDocument:
Version: "2012-10-17"
Statement:
-
Effect: "Allow"
Action:
- glue:GetTable
- glue:GetTableVersion
- glue:GetTableVersions
Resource: "*"
-
Effect: "Allow"
Action:
- s3:AbortMultipartUpload
- s3:GetBucketLocation
- s3:GetObject
- s3:ListBucket
- s3:ListBucketMultipartUploads
- s3:PutObject
Resource:
- !Sub arn:aws:s3:::${BucketName}-${AWS::AccountId}
- !Sub arn:aws:s3:::${BucketName}-${AWS::AccountId}/*
- arn:aws:s3:::%FIREHOSE_BUCKET_NAME%
- arn:aws:s3:::%FIREHOSE_BUCKET_NAME%/*
-
Effect: "Allow"
Action:
- lambda:InvokeFunction
- lambda:GetFunctionConfiguration
Resource:
- !Sub arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:%FIREHOSE_DEFAULT_FUNCTION%:%FIREHOSE_DEFAULT_VERSION%
-
Effect: "Allow"
Action:
- kms:GenerateDataKey
- kms:Decrypt
Resource:
- !Sub arn:aws:kms:${AWS::Region}:${AWS::AccountId}:alias/aws/s3
Condition:
StringEquals:
kms:ViaService: !Sub s3.${AWS::Region}.amazonaws.com
StringLike:
kms:EncryptionContext:aws:s3:arn:
- !Sub arn:aws:s3:::${BucketName}-${AWS::AccountId}/*
- !Sub arn:aws:s3:::${BucketName}-${AWS::AccountId}/%FIREHOSE_BUCKET_PREFIX%*
-
Effect: "Allow"
Action:
- logs:PutLogEvents
Resource:
- !Sub arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/kinesisfirehose/aws-waf-logs-${AWS::Region}-${WebACLName}:log-stream:*
-
Effect: "Allow"
Action:
- kinesis:DescribeStream
- kinesis:GetShardIterator
- kinesis:GetRecords
Resource:
- !Sub arn:aws:kinesis:${AWS::Region}:${AWS::AccountId}:stream/%FIREHOSE_STREAM_NAME%
-
Effect: "Allow"
Action:
- kms:Decrypt
Resource:
- !Sub arn:aws:kms:${AWS::Region}:${AWS::AccountId}:key/%SSE_KEY_ID%
Condition:
StringEquals:
kms:ViaService: kinesis.%REGION_NAME%.amazonaws.com
StringLike:
kms:EncryptionContext:aws:kinesis:arn: !Sub arn:aws:kinesis:%REGION_NAME%:${AWS::AccountId}:stream/%FIREHOSE_STREAM_NAME%
### WAF WebACL
WebACL:
Type: AWS::WAFv2::WebACL
Properties:
Name: !Ref WebACLName
DefaultAction:
Allow: {}
Scope: REGIONAL
VisibilityConfig:
CloudWatchMetricsEnabled: true
MetricName: !Ref WebACLName
SampledRequestsEnabled: false
Rules:
-
Name: AWS-AWSManagedRulesAmazonIpReputationList
Priority: 1
Statement:
ManagedRuleGroupStatement:
VendorName: AWS
Name: AWSManagedRulesAmazonIpReputationList
OverrideAction:
Count: {}
VisibilityConfig:
CloudWatchMetricsEnabled: true
MetricName: AWSManagedRulesAmazonIpReputationList
SampledRequestsEnabled: false
-
Name: AWS-AWSManagedRulesCommonRuleSet
Priority: 2
Statement:
ManagedRuleGroupStatement:
VendorName: AWS
Name: AWSManagedRulesCommonRuleSet
OverrideAction:
Count: {}
VisibilityConfig:
CloudWatchMetricsEnabled: true
MetricName: AWSManagedRulesCommonRuleSet
SampledRequestsEnabled: false
-
Name: AWS-AWSManagedRulesKnownBadInputsRuleSet
Priority: 3
Statement:
ManagedRuleGroupStatement:
VendorName: AWS
Name: AWSManagedRulesKnownBadInputsRuleSet
OverrideAction:
Count: {}
VisibilityConfig:
CloudWatchMetricsEnabled: true
MetricName: AWSManagedRulesKnownBadInputsRuleSet
SampledRequestsEnabled: false
-
Name: AWS-AWSManagedRulesLinuxRuleSet
Priority: 4
Statement:
ManagedRuleGroupStatement:
VendorName: AWS
Name: AWSManagedRulesLinuxRuleSet
OverrideAction:
Count: {}
VisibilityConfig:
CloudWatchMetricsEnabled: true
MetricName: AWSManagedRulesLinuxRuleSet
SampledRequestsEnabled: false
-
Name: AWS-AWSManagedRulesUnixRuleSet
Priority: 5
Statement:
ManagedRuleGroupStatement:
VendorName: AWS
Name: AWSManagedRulesUnixRuleSet
OverrideAction:
Count: {}
VisibilityConfig:
CloudWatchMetricsEnabled: true
MetricName: AWSManagedRulesUnixRuleSet
SampledRequestsEnabled: false
-
Action:
Count: {}
Name: Custom-IPaddress-BlackList
Priority: 0
Statement:
IPSetReferenceStatement:
Arn: !GetAtt IPBlackList.Arn
VisibilityConfig:
CloudWatchMetricsEnabled: true
MetricName: Custom-IPaddress-BlackList
SampledRequestsEnabled: false
-
Action:
Count: {}
Name: Custom-Ratebased
Priority: 6
Statement:
RateBasedStatement:
AggregateKeyType: IP
Limit: 100
ScopeDownStatement:
NotStatement:
Statement:
IPSetReferenceStatement:
Arn: !GetAtt IPWhiteList.Arn
VisibilityConfig:
CloudWatchMetricsEnabled: true
MetricName: Custom-Ratebased
SampledRequestsEnabled: false
IPWhiteList:
Type: "AWS::WAFv2::IPSet"
Properties:
Name: Custom-ipaddress-whitelist
Scope: REGIONAL
IPAddressVersion: IPV4
Addresses:
- nnn.nnn.nnn.nnn/32
IPBlackList:
Type: "AWS::WAFv2::IPSet"
Properties:
Name: Custom-ipaddress-blacklist
Scope: REGIONAL
IPAddressVersion: IPV4
Addresses:
- nnn.nnn.nnn.nnn/32
参考
Announcing AWS Managed Rules for AWS WAF AWS Managed Rules for AWS WAF CloudFormation User Guide
以上、吉井 亮 がお届けしました。