概要
AWSで何度かALBに対しBasic認証を行う機会があり、毎回調べながら試行錯誤して作っていたので備忘を目的に記載。
(個人的な感覚で、Node.jsの記事は良く見かけるが、Pythonの記事はあまり見かけないので、いつも一苦労・・・)
なんでPython?
個人的に、Node.jsよりPythonの方がバージョンのサポート期間が長いイメージなので、Pythonを使いたい。
参考:
https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/lambda-runtimes.html
構成
Basic認証未済のリクエストはLambdaへ、Basic認証済のリクエストはEC2へ。
AWS設定
以下の順序
1.Lambda作成
2.EC2作成
3.ターゲットグループ作成
4.ALB作成
1.Lambda作成
以下条件で作成。
・ランタイム
Python12
・VPC
非VPC(VPCの場合だとSecurityGroupの設定が面倒だったため)
・IAM
デフォルトのまま
import json
import base64
def lambda_handler(event, context):
# eventのヘッダからuserAgentを取得する
useragent = event.get('headers').get('user-agent')
# ALBヘルスチェックはBasic認証を除外。ALBヘルスチェックはuserAgentがELB-HealthChecker/2.0となるので、これに注目。
if useragent == 'ELB-HealthChecker/2.0':
return {
'statusCode': 200,
'Content-Type': 'text/html; charset=utf-8'
}
# ALBヘルスチェック以外はBasic認証対象。このLambdaに着信するリクエストは全てBasic認証を応答する。
else:
return {
'statusCode': 401,
'statusDescription': '401 Unauthorized',
'body': 'Unauthorized',
'isBase64Encoded': False,
'headers': {
'WWW-Authenticate': 'Basic',
'Content-Type': 'text/html'
}
}
2.EC2作成
適当なEC2を作成しapacheをインストールする。
以下はAmazonlinux2023でapacheをインストールした際の例
> sudo yum -y install httpd
> sudo systemctl httpd status
> sudo systemctl enable httpd.service
> sudo systemctl start httpd.service
インストール後、動くか確認
> curl http://localhost
<html><body><h1>It works!</h1></body></html>
>
3.ターゲットグループ作成
2つ作成。Basic認証Lambda用とWebServerEC2用。
Basic認証Lambda
WebServerEC2用
Basic認証Lambdaに倣い、2で作成したEC2のターゲットグループを作成。
4.ALB作成
ALBは、今回は外部からのアクセスのためインターネットフェイシングで作成。
ポイントはリスナールール。
青枠の部分が特徴で、HTTPヘッダーのAuthorizationがBasic XXXXXの時、WebServerであるEC2のターゲットグループへルーティングする、というルールである。
「Basic XXXXX」の生成方法
basic認証で入力するユーザ・パスワードはbase64エンコードされ、この値を登録している。シェルが叩けるサーバやCloudShellで、ユーザ・パスワードのbase64エンコード文字列を生成する。
echo -n <ユーザ>:<パスワード> | base64
[cloudshell-user@ip-XXX-XXX-XXX-XXX ~]$ echo -n user1:pass1 | base64
<エンコード文字列>
[cloudshell-user@ip-XXX-XXX-XXX-XXX ~]$
注意点としては、Basic認証で入力したユーザ・パスワードのエンコードは「Basic XXXXX」という形となる。このため、ALBのリスナールールにも、base64でエンコードした上記の結果に、Basicを付与する。
上記の例だと「Basic <エンコード文字列>」(←ルール登録時、「」は不要)。
検証
ユーザにuser1、パスワードにpass1を入力しログインを押下すると、問題なく稼働
+α(一度認証に失敗したリクエストをError画面へ遷移)
上記だとBasic認証に失敗した場合、常にLambdaへリクエストが飛ぶ。
通常のリクエストであれば問題はないが、ブルートフォース等によるパスワードクラックの可能性を踏まえると、認証の回数制限などを設けることが良いと考えている。
回数制限の実装は大掛かりになるので、本章では楽に実装が可能な一度認証に失敗したリクエストをError画面に遷移する方法を紹介する。
具体的にはALBのルールに一つ追加するのみ。
(便宜上、不要なところは削除)
初回アクセス時は、Authorizationヘッダが存在しないため、一番下のデフォルトルールに到達し、2回目以降は、空白であってもAuthorizationヘッダはつくため、1番目か2番目のルールで評価となる。
正しい認証情報(ユーザ・パスワード)以外はAuthorizationが*の箇所で評価され、固定レスポンスを応答する。という流れ。
これにより、むやみやたらにBasic認証用Lambdaが叩かれる心配が減る。
なお、ブラウザキャッシュをクリアすればAuthorizationヘッダもクリアされるため、再度Basic認証にトライ可能。