LoginSignup
2
1

概要

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認証.png

Basic認証未済のリクエストはLambdaへ、Basic認証済のリクエストはEC2へ。

AWS設定

以下の順序
1.Lambda作成
2.EC2作成
3.ターゲットグループ作成
4.ALB作成

1.Lambda作成

以下条件で作成。
・ランタイム
 Python12
・VPC
 非VPC(VPCの場合だとSecurityGroupの設定が面倒だったため)
・IAM
 デフォルトのまま

BasicAuthLambda
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をインストールした際の例

command
> sudo yum -y install httpd
> sudo systemctl httpd status
> sudo systemctl enable httpd.service
> sudo systemctl start httpd.service

インストール後、動くか確認

command
> curl http://localhost
<html><body><h1>It works!</h1></body></html>
> 

3.ターゲットグループ作成

2つ作成。Basic認証Lambda用とWebServerEC2用。

Basic認証Lambda

ターゲットタイプはLambda関数
image.png

ヘルスチェックは有効にしておく
image.png

1.で作成したLambda関数を設定
image.png

WebServerEC2用

Basic認証Lambdaに倣い、2で作成したEC2のターゲットグループを作成。

4.ALB作成

ALBは、今回は外部からのアクセスのためインターネットフェイシングで作成。
ポイントはリスナールール。
image.png
青枠の部分が特徴で、HTTPヘッダーのAuthorizationがBasic XXXXXの時、WebServerであるEC2のターゲットグループへルーティングする、というルールである。

「Basic XXXXX」の生成方法

basic認証で入力するユーザ・パスワードはbase64エンコードされ、この値を登録している。シェルが叩けるサーバやCloudShellで、ユーザ・パスワードのbase64エンコード文字列を生成する。

echo -n <ユーザ>:<パスワード> | base64

command
[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 <エンコード文字列>」(←ルール登録時、「」は不要)。

検証

ALBのDNSへアクセス。Basic認証が求められる
image.png

ユーザにuser1、パスワードにpass1を入力しログインを押下すると、問題なく稼働
image.png

+α(一度認証に失敗したリクエストをError画面へ遷移)

上記だとBasic認証に失敗した場合、常にLambdaへリクエストが飛ぶ。
通常のリクエストであれば問題はないが、ブルートフォース等によるパスワードクラックの可能性を踏まえると、認証の回数制限などを設けることが良いと考えている。

回数制限の実装は大掛かりになるので、本章では楽に実装が可能な一度認証に失敗したリクエストをError画面に遷移する方法を紹介する。

具体的にはALBのルールに一つ追加するのみ。
(便宜上、不要なところは削除)
image.png

初回アクセス時は、Authorizationヘッダが存在しないため、一番下のデフォルトルールに到達し、2回目以降は、空白であってもAuthorizationヘッダはつくため、1番目か2番目のルールで評価となる。
正しい認証情報(ユーザ・パスワード)以外はAuthorizationが*の箇所で評価され、固定レスポンスを応答する。という流れ。

これにより、むやみやたらにBasic認証用Lambdaが叩かれる心配が減る。
なお、ブラウザキャッシュをクリアすればAuthorizationヘッダもクリアされるため、再度Basic認証にトライ可能。

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1