この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
AWS事業本部の梶原@福岡オフィスです。
Basic認証のコードをよく見てたら、もしかして401のレスポンスが返せれば、WAFだけでいけんじゃね?って思ったので
やってみました。
AWS WAF Rule 作成
AWS コンソールで作成する場合は、以下のRuleをコンソールより作成します。 Rule部のみのご案内ですが、適時適切なRoleGroup, WAF ACL等に紐づけて頂ければと思います。 CloudFormationでサクッと作成されたい方は飛ばしてください
AWS WAF 条件部
項目 | 値 | 備考 |
---|---|---|
If a request | doesn't match the statement (NOT) |
Statement
項目 | 値 | 備考 |
---|---|---|
Inspect | Header | |
Header field name | authorization | |
Match type | Exactly matches string | |
String to match | Basic XXXXXXXXXX | echo -n user:password | base64 |
※ String to match で設定する Basic XXXXXXXXXX の部分は事前にLinuxのshell等で
echo -n user:password | base64
を実施し、User:Password を Base64エンコードした値を設定してください
AWS WAF レスポンス部分
Action
項目 | 値 | 備考 |
---|---|---|
Action | Block |
Custom response
項目 | 値 | 備考 |
---|---|---|
Enable | ✅ | |
Response code | 401 |
Response headers
項目 | 値 | 備考 |
---|---|---|
Key | www-authenticate | |
Value | Basic |
JSON
{
"Name": "BasicAuthRule",
"Priority": 0,
"Statement": {
"NotStatement": {
"Statement": {
"ByteMatchStatement": {
"SearchString": "Basic XXXXXXXXXX",
"FieldToMatch": {
"SingleHeader": {
"Name": "authorization"
}
},
"TextTransformations": [
{
"Priority": 0,
"Type": "NONE"
}
],
"PositionalConstraint": "EXACTLY"
}
}
}
},
"Action": {
"Block": {
"CustomResponse": {
"ResponseCode": 401,
"ResponseHeaders": [
{
"Name": "www-authenticate",
"Value": "Basic"
}
]
}
}
},
"VisibilityConfig": {
"SampledRequestsEnabled": true,
"CloudWatchMetricsEnabled": false,
"MetricName": "BasicAuthRule"
}
}
CloudFormation で AWS WAF Rule 作成
相変わらず、CloudFormationもご用意しているのでAWSコンソールにログイン後、下記URLをクリックしてください (クラウドフロント用のWAF のRuleを作成するため、米国東部 (バージニア北部) us-east-1 でスタックが作成されます。
Ruleの条件追加の余地を持たせるため、Capacityは10で作成していますが、条件を増やしたい場合はテンプレートをご自由に変更して下さい
ベーシック認証をサイト全体に設定する場合
パラメータ設定
User 名、Passwordをパラメータに設定し、スタックの作成を行ってください
CloudFormationの処理で、Basic認証のユーザー、パスワード変換部分を処理しています。
CreateWebACLをtrue
に設定すると作成した、Basic認証のRuleGroupと紐づいたWebACLが作成されます。
ベーシック認証のみをおこなうWebACLを使用する機会はあまりないかと思いますが、確認等で検証いただけたらと思います。
ベーシック認証を特定のURL配下に設定する場合
特定のパス配下のみにベーシック認証を掛けたいというご要望にお応えしました!
パラメータ設定
UriPath に設定したい特定のパスを設定してください。
User 名、Passwordをパラメータに設定し、スタックの作成を行ってください
CloudFormationの処理で、Basic認証のユーザー、パスワード変換部分を処理しています。
作成されたリソースの確認
正常にスタックが作成されますと、BasicAuthRuleGroup-XXXXXXXX が作成されているかと思うので確認してください
https://console.aws.amazon.com/wafv2/homev2/rule-groups?region=global
WebACLへRuleの追加
既存のWebACLへ設定する場合は、作成したRuleGroupを選択し、ルールを追加してください。
検証
WAFを紐づけたCloudFront のサイトにアクセスし、Basic認証が適切に行われているかご検証ください。
まとめ
このためだけに、WAFのBasic認証を導入するのは、あまりないかもしれませんが、
すでにWAFを導入されている場合、既存のCloudFrontへ影響なく、一つ外側のレイヤーで認証処理をかけることができます。
Bot対策や、公開前コンテンツの一時保護など既存のCloudFrontでLambda@Edge, CloudFront Functionsで処理をしている場合、影響をださずに実現できるかと思います
また、IPアドレス制限、Bot対策などの別のWAFの条件と組み合わせて設定することもできるかと思いますので、ご要件にあえば応用できるかと思います。
参考
CloudFormationを使用して、既存のCloudFrontにCloudFront Functions(CF2)でBasic認証を設定する
CloudFormation テンプレート
AWSTemplateFormatVersion: "2010-09-09"
Parameters:
User:
Type: String
Default: user
Password:
NoEcho: true
Type: String
CreateWebACL:
Type: String
Default: no
AllowedValues: [yes, no]
Conditions:
CreateWebACL: !Equals [ !Ref CreateWebACL, yes ]
Resources:
BasicAuthRuleGroup:
Type: AWS::WAFv2::RuleGroup
Properties:
Capacity: 10
Scope: CLOUDFRONT
VisibilityConfig:
CloudWatchMetricsEnabled: false
MetricName: BasicAuthRuleGroup
SampledRequestsEnabled: true
Rules:
- Name: BasicAuthRule
Priority: 0
Statement:
NotStatement:
Statement:
ByteMatchStatement:
SearchString: !Sub
- Basic ${authString}
- authString : !Base64
Fn::Join: [ ":", [ !Ref User, !Ref Password ] ]
FieldToMatch:
SingleHeader:
Name: authorization
TextTransformations:
- Priority: 0
Type: NONE
PositionalConstraint: EXACTLY
Action:
Block:
CustomResponse:
ResponseCode: 401
ResponseHeaders:
- Name: www-authenticate
Value: Basic
VisibilityConfig:
SampledRequestsEnabled: true
CloudWatchMetricsEnabled: false
MetricName: BasicAuthRule
MyWebACL:
Condition: CreateWebACL
Type: AWS::WAFv2::WebACL
Properties:
DefaultAction:
Allow: {}
Scope: CLOUDFRONT
Rules:
- Name: MyRule
Priority: 0
Statement:
RuleGroupReferenceStatement:
Arn: !GetAtt BasicAuthRuleGroup.Arn
OverrideAction:
None: {}
VisibilityConfig:
SampledRequestsEnabled: true
CloudWatchMetricsEnabled: false
MetricName: MyRule
VisibilityConfig:
CloudWatchMetricsEnabled: false
MetricName: MyWebACL
SampledRequestsEnabled: true
CloudFormation テンプレート(特定URLを条件に追加)
AWSTemplateFormatVersion: "2010-09-09"
Parameters:
UriPath:
Type: String
Default: /basic-auth
User:
Type: String
Default: user
Password:
NoEcho: true
Type: String
CreateWebACL:
Type: String
Default: no
AllowedValues: [yes, no]
Conditions:
CreateWebACL: !Equals [ !Ref CreateWebACL, yes ]
Resources:
BasicAuthRuleGroup:
Type: AWS::WAFv2::RuleGroup
Properties:
Capacity: 10
Scope: CLOUDFRONT
VisibilityConfig:
CloudWatchMetricsEnabled: false
MetricName: BasicAuthRuleGroup
SampledRequestsEnabled: true
Rules:
- Name: BasicAuthRule
Priority: 0
Statement:
AndStatement:
Statements:
- ByteMatchStatement:
SearchString: !Ref UriPath
FieldToMatch:
UriPath: {}
TextTransformations:
- Priority: 0
Type: NONE
PositionalConstraint: STARTS_WITH
- NotStatement:
Statement:
ByteMatchStatement:
SearchString: !Sub
- Basic ${authString}
- authString : !Base64
Fn::Join: [ ":", [ !Ref User, !Ref Password ] ]
FieldToMatch:
SingleHeader:
Name: authorization
TextTransformations:
- Priority: 0
Type: NONE
PositionalConstraint: EXACTLY
Action:
Block:
CustomResponse:
ResponseCode: 401
ResponseHeaders:
- Name: www-authenticate
Value: Basic
VisibilityConfig:
SampledRequestsEnabled: true
CloudWatchMetricsEnabled: false
MetricName: BasicAuthRule
MyWebACL:
Condition: CreateWebACL
Type: AWS::WAFv2::WebACL
Properties:
DefaultAction:
Allow: {}
Scope: CLOUDFRONT
Rules:
- Name: MyRule
Priority: 0
Statement:
RuleGroupReferenceStatement:
Arn: !GetAtt BasicAuthRuleGroup.Arn
OverrideAction:
None: {}
VisibilityConfig:
SampledRequestsEnabled: true
CloudWatchMetricsEnabled: false
MetricName: MyRule
VisibilityConfig:
CloudWatchMetricsEnabled: false
MetricName: MyWebACL
SampledRequestsEnabled: true