AWS WAFだけで、Basic認証を設定してみた
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