概要
AWS WAFを使って、特定のエンドポイントにのみIP制限をかける方法を紹介します。
- Lambda関数が複数のエンドポイント(例:
/hoge、/foo)を持っている -
/hogeにはIP制限をかけたい(特定IPからのみアクセス可能) -
/fooは全てのIPからアクセス可能にしたい
色々と試行錯誤しましたが、
結論、WAFのルールで正規表現パターンとIPセットを組み合わせることで実現できます。
設計方針
WAFのルール評価順序を活用します。
| 優先度 | ルール名 | 条件 | アクション |
|---|---|---|---|
| 1 | allow-api-for-ipset |
/hoge パス かつ 許可IPリスト |
Allow |
| 2 | allow-api-for-all-ips |
/foo パス |
Allow |
| - | DefaultAction | 上記に該当しない全て | Block |
サンプルコード(Cloudformation)
Resources:
######
# ApiGateway作成などは省略
######
# /hoge パスにマッチする正規表現パターン
HogeApiPathRegexPatternSet:
Type: AWS::WAFv2::RegexPatternSet
Properties:
Name: !Sub "${Env}-HogeApiPathPattern"
Scope: REGIONAL
RegularExpressionList:
- "^/(?:[^/]+/)?hoge(/.*)?$"
# /foo パスにマッチする正規表現パターン
FooApiPathRegexPatternSet:
Type: AWS::WAFv2::RegexPatternSet
Properties:
Name: !Sub "${Env}-FooApiPathPattern"
Scope: REGIONAL
RegularExpressionList:
- "^/(?:[^/]+/)?foo(/.*)?$"
# WebACL本体
ApiGatewayWebACL:
Type: AWS::WAFv2::WebACL
Properties:
Name: !Sub "${Env}-WebACL"
Scope: REGIONAL
DefaultAction:
Block: {}
VisibilityConfig:
SampledRequestsEnabled: true
CloudWatchMetricsEnabled: true
MetricName: !Sub "${Env}-WebACL"
Rules:
- Name: "allow-api-for-ipset"
Priority: 1
Action:
Allow: {}
Statement:
AndStatement:
Statements:
- IPSetReferenceStatement:
Arn: !GetAtt AllowedIPSet.Arn
- RegexPatternSetReferenceStatement:
Arn: !GetAtt HogeApiPathRegexPatternSet.Arn
FieldToMatch:
UriPath: {}
TextTransformations:
- Priority: 0
Type: NONE
VisibilityConfig:
SampledRequestsEnabled: true
CloudWatchMetricsEnabled: true
MetricName: "allow-api-for-ipset"
- Name: "allow-api-for-all-ips"
Priority: 2
Action:
Allow: {}
Statement:
RegexPatternSetReferenceStatement:
Arn: !GetAtt FooApiPathRegexPatternSet.Arn
FieldToMatch:
UriPath: {}
TextTransformations:
- Priority: 0
Type: NONE
VisibilityConfig:
SampledRequestsEnabled: true
CloudWatchMetricsEnabled: true
MetricName: "allow-api-for-all-ips"
# 許可IPリスト
AllowedIPSet:
Type: AWS::WAFv2::IPSet
Properties:
Name: !Sub "${Env}-AllowedIPSet"
Scope: REGIONAL
IPAddressVersion: IPV4
Addresses:
- !Ref AllowedIPCIDR # Parameterで対象のIPを設定してある前提とします
# WebACLをAPI Gatewayに関連付け
ApiGatewayWebACLAssociation:
Type: AWS::WAFv2::WebACLAssociation
Properties:
# ApiGatewayRestApiという名前でApiGatewayが作成してある前提とします
ResourceArn: !Sub "arn:aws:apigateway:${AWS::Region}::/restapis/${ApiGatewayRestApi}/stages/${Env}"
WebACLArn: !GetAtt ApiGatewayWebACL.Arn
これにより、以下の動作となります。
- /hoge → AllowedIPからのみアクセス可能
- /foo → 全てのIPからアクセス可能
- その他のパス → 全てブロック
正規表現パターン
設定した
"^/(?:[^/]+/)?hoge(/.*)?$"
は、具体的には以下のようなパスが含まれます。
- /hoge
- /hoge/xxx
- /v1/hoge
- /v1/hoge/xxx
参考
以下のように書くとエラーになります。
RegularExpressionList:
- RegexString: "^/[^/]+/hoge(/.*)?$"
エラーメッセージはこちら。
Model validation failed (#/RegularExpressionList/0: expected type: String, found: JSONObject)
これは、オブジェクト形式になっているからでした。
正しくは、文字列のリストとして記述すると、エラーが解消されました。
RegularExpressionList:
- "^/[^/]+/hoge(/.*)?$"