今回は、AWSのWeb Application Firewall(WAF)とそのレートベースルールについて解説し、実際に検証を行う方法を紹介します。
AWS WAFとは
AWS WAFは、ウェブアプリケーションを保護するためのウェブアプリケーションファイアウォールです。以下のような機能を提供します。
- SQL インジェクションやクロスサイトスクリプティング(XSS)などの一般的なウェブ攻撃からの保護
- 特定のIPアドレスやIPレンジからのアクセス制限
- カスタムルールの作成と適用
- Amazon CloudFront、API Gateway、Application Load Balancer(ALB)などのAWSサービスと統合
レートベースルールとは
レートベースルールは、特定の IP アドレスからのリクエスト数を制限するためのルールです。
これにより、DDoS 攻撃やブルートフォース攻撃を防ぐことができます。
例えば、1分間に1000リクエストを超えるIPアドレスをブロックするルールを設定することができます。
今回は最小限のレートベースルールとするため1分間に10リクエストを超えるIPアドレスはブロックするルールを設定します。
検証環境の構築
WAFのレートベースルールを検証するための環境をAWS CloudFormationを使用して構築します。
このテンプレートは、WAFのレートベースルールを検証するための環境をAWS CloudFormationを使用して構築するためのものです。以下のリソースが作成されます。
- VPC
- サブネット
- インターネットゲートウェイ
- ルートテーブル
- セキュリティグループ
- EC2インスタンス
- API Gateway
- WAF WebACL
- レートベースルール
※注意事項
このテンプレートはあくまで検証用です。以下の点に注意してください。
- 本番環境ではセキュリティグループを適切に設定してください。
- 本番環境では、リソースの設定を適切に行い、セキュリティやパフォーマンスの観点から最適化を行ってください。
AWS CloudFormation テンプレート
AWSTemplateFormatVersion: 2010-09-09
Description: CloudFormation template to create resources for WAF rate-based rule testing
Parameters:
Environment:
Type: String
Description: Environment Name
Resources:
# VPC
VPC:
Type: AWS::EC2::VPC
Properties:
CidrBlock: "10.0.0.0/16"
EnableDnsSupport: true
EnableDnsHostnames: true
Tags:
- Key: Name
Value: !Sub ${Environment}-VPC-${AWS::StackName}
# Subnet
Subnet:
Type: AWS::EC2::Subnet
Properties:
AvailabilityZone: !Select [0, !GetAZs ""]
VpcId: !Ref VPC
CidrBlock: "10.0.1.0/24"
MapPublicIpOnLaunch: true
Tags:
- Key: Name
Value: !Sub ${Environment}-Subnet-${AWS::StackName}
# IGW
IGW:
Type: AWS::EC2::InternetGateway
Properties:
Tags:
- Key: Name
Value: !Sub ${Environment}-IGW-${AWS::StackName}
IGWAttachment:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
InternetGatewayId: !Ref IGW
VpcId: !Ref VPC
# RouteTable
RouteTable:
Type: AWS::EC2::RouteTable
Properties:
Tags:
- Key: Name
Value: !Sub ${Environment}-RouteTable-${AWS::StackName}
VpcId: !Ref VPC
# RouteTable Association
RouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
RouteTableId: !Ref RouteTable
SubnetId: !Ref Subnet
# Route
Route:
Type: AWS::EC2::Route
Properties:
DestinationCidrBlock: 0.0.0.0/0
RouteTableId: !Ref RouteTable
GatewayId: !Ref IGW
#SG
SecurityGroupEC2:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: Allow outbound traffic
GroupName: !Sub ${Environment}-SG-EC2-${AWS::StackName}
SecurityGroupEgress:
- CidrIp: 0.0.0.0/0
IpProtocol: -1
Tags:
- Key: Name
Value: !Sub ${Environment}-SG-${AWS::StackName}
VpcId: !Ref VPC
# Role
EC2InstanceRole:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Version: 2012-10-17
Statement:
- Effect: Allow
Principal:
Service:
- ec2.amazonaws.com
Action:
- sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
RoleName: !Sub ${Environment}-EC2-SSM-Role-${AWS::StackName}
Path: /
# EC2InstanceProfile
EC2InstanceProfile:
Type: AWS::IAM::InstanceProfile
Properties:
InstanceProfileName: !Sub ${Environment}-EC2-InstanceProfile-${AWS::StackName}
Roles:
- !Ref EC2InstanceRole
Path: /
# EC2Instance
EC2Instance:
Type: AWS::EC2::Instance
Properties:
InstanceType: t2.micro
ImageId: ami-0d4aa492f133a3068
SubnetId: !Ref Subnet
SecurityGroupIds:
- !Ref SecurityGroupEC2
IamInstanceProfile: !Ref EC2InstanceProfile
Tags:
- Value: Name
Key: !Sub ${Environment}-EC2-${AWS::StackName}
# APIGatewayRestApi
APIGatewayRestApi:
Type: AWS::ApiGateway::RestApi
Properties:
Name: !Sub ${Environment}-Api-${AWS::StackName}
Description: API Gateway for WAF testing
# APIGatewayResource
APIGatewayResource:
Type: AWS::ApiGateway::Resource
Properties:
ParentId: !GetAtt APIGatewayRestApi.RootResourceId
PathPart: test
RestApiId: !Ref APIGatewayRestApi
# APIGatewayMethod
APIGatewayMethod:
Type: AWS::ApiGateway::Method
Properties:
AuthorizationType: NONE
AuthorizerId: "String"
HttpMethod: GET
ResourceId: !Ref APIGatewayResource
RestApiId: !Ref APIGatewayRestApi
Integration:
Type: MOCK
IntegrationResponses:
- StatusCode: 200
ResponseTemplates:
application/json: '{"status": "ok"}'
RequestTemplates:
application/json: '{"statusCode": 200}'
MethodResponses:
- StatusCode: 200
# APIGatewayDeployment
APIGatewayDeployment:
Type: AWS::ApiGateway::Deployment
DependsOn: APIGatewayMethod
Properties:
RestApiId: !Ref APIGatewayRestApi
# APIGatewayStage
APIGatewayStage:
Type: AWS::ApiGateway::Stage
Properties:
DeploymentId: !Ref APIGatewayDeployment
RestApiId: !Ref APIGatewayRestApi
StageName: dev
# WAFWebACL
WAFWebACL:
Type: AWS::WAFv2::WebACL
Properties:
Name: !Sub ${Environment}-WAF-WebACL-${AWS::StackName}
Scope: REGIONAL
DefaultAction:
Allow: {}
VisibilityConfig:
MetricName: !Sub ${Environment}-WAF-WebACL-Metric-${AWS::StackName}
SampledRequestsEnabled: true
CloudWatchMetricsEnabled: true
Rules:
- Priority: 0
Action:
Block: {}
Statement:
RateBasedStatement:
EvaluationWindowSec: 60
AggregateKeyType: IP
Limit: 10
VisibilityConfig:
MetricName: !Sub ${Environment}-WAF-RateBaseRule-Metric-${AWS::StackName}
SampledRequestsEnabled: true
CloudWatchMetricsEnabled: true
Name: RateBasedRule
# WAFWebACLAssociation
WAFWebACLAssociation:
Type: AWS::WAFv2::WebACLAssociation
Properties:
ResourceArn: !Sub "arn:aws:apigateway:${AWS::Region}::/restapis/${APIGatewayRestApi}/stages/${APIGatewayStage}"
WebACLArn: !GetAtt WAFWebACL.Arn
検証方法
1. デプロイ
上記のAWS CloudFormationテンプレートを使用してスタックをデプロイします。
AWS Management Console、AWS CLIまたはAWS SDKを使用してデプロイできます。
2. SSMを使用してEC2インスタンスに接続
AWS Management Consoleから、Systems Manager > セッションマネージャーに移動し、作成したEC2インスタンスに接続します。
3. WAFのレートベースルールの動作確認
以下のコマンドを使用してAPI Gatewayのエンドポイントに対してリクエストを送信します。
curl https://<apiのid>.execute-api.ap-northeast-1.amazonaws.com/dev/test
1分間に10回以上のリクエストを送信します。
WAFのレートベースルールが適用され、リクエストがブロックされることを確認します。

まとめ
AWS WAFとレートベースルールを使用することで、ウェブアプリケーションを一般的なウェブ攻撃から保護し、特定のIPアドレスからのリクエスト数を制限することができます。
AWS WAFの詳細については、公式ドキュメントを参照してください。
最後に
Sky株式会社は、AWS WAFのSDP(サービスデリバリープログラム)認定を取得しております。
AWSのベストプラクティスに則った最適な提案や支援を提供することが可能です。
WAFの導入や運用に関するご相談やご質問がございましたら、どうぞお気軽にお問い合わせください。

