Azure ADをIdPに設定してALBでユーザ認証してみた

Azure ADをIdPに設定してALBでユーザ認証してみました。

https://docs.aws.amazon.com/ja_jp/elasticloadbalancing/latest/application/listener-authenticate-users.html

### 追記(2020-03-16)
ユーザークレーム(x-amzn-oidc-data)のexpireは2分のようですが、アクセストークン(x-amzn-oidc-accesstoken)のexpireは初回ログイン時から変わらない(＝期限切れになる)ようです。

- *IdP によって ID トークンに有効な更新トークンが提供されている場合、ロードバランサーは更新トークンを保存し、アクセストークンの有効期限が切れるたびにこれを使用して、セッションがタイムアウトするか、IdP の更新に失敗するまで、ユーザークレームを更新します。*

上記リンクのAWSのドキュメントの記述とちょっと合わない感じがしますが、バックエンド側はドキュメント記載の通りユーザークレームでユーザ認証するのであれば問題ないのかな？

# 手順

1. HTMLを出力するLambdaを作成し、ALBのターゲットに設定する
2. Azure ADにアプリケーションを登録する
3. ALBを設定する
4. テストする

# 1. HTMLを出力するLambdaを作成し、ALBのターゲットに設定する
以下記事を参考に、Lambdaを作成してALBのターゲットに設定します。
　https://docs.aws.amazon.com/ja_jp/elasticloadbalancing/latest/application/lambda-functions.html
ALBのリスナーは**HTTPS**に設定し、Route53にALBのエイリアスレコードを登録します。

```lambda_function.py
def lambda_handler(event, context):
    
    print(event)
    
    res = {
        "isBase64Encoded": False,
        "statusCode": 200,
        "statusDescription": "200 OK",
        "headers": {
            "Set-cookie": "cookies",
            "Content-Type": "text/html"
        }
    }
    
    res['body'] = """<html>
    <head>
	<title>hello world</title>
	</head>
	<body>
	<h1>Hello World</h1>
	</body>
    </html>"""
    
    return res
```


# 2. Azure ADにアプリケーションを登録する

Azureにログインして、Azure Active DirectoryーApp registrationsからアプリケーションを登録します。
Redirect URIは以下を指定します。
　https://*Route53に登録したALBのエイリアスレコード*/oauth2/idpresponse

<img width="738" alt="スクリーンショット 2020-03-10 4.25.56.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192584/c81d8ff0-9b69-e24b-3118-9ccb1e1b2959.png">


次にアプリケーションのクライアントシークレットを作成します。

<img width="1130" alt="2_sec.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192584/9f43d907-1652-bbf4-c53f-874b8923bc1c.png">

最後に各種エンドポイントを確認します。


<img width="1642" alt="3_ep.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192584/f1bb425d-7ae7-21f4-b5be-75acd2258210.png">

下記コマンドでも確認できます。

```bash
curl https://login.microsoftonline.com/********-****-****-****-************/v2.0/.well-known/openid-configuration
```

# 3. ALBを設定する

ALBのリスナーを編集して、Authenticateアクションを追加します。

<img width="374" alt="4_alb.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192584/48e85b38-929d-4d8a-8428-44bbc2963195.png">


|ALBの設定値|対応するAzure側の値|
|---|---|
|Authenticate|OIDC|
|Issure|Authorization endpointの"/oauth2/v2.0/authorize"の部分を"/v2.0"で置換したURL|
|Authorization endpoint|OAuth 2.0 authorization endpoint (v2)|
|Token endpoint|OAuth 2.0 token endpoint (v2)|
|User info endpoint|https://graph.microsoft.com/oidc/userinfo|
|Client ID|Application (client) ID|
|Client secret|作成したシークレット|

# 4. テストする

ALBのエイリアスレコードをURLに指定するとサインイン画面が表示されます。

<img width="457" alt="5_login.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192584/dda17b2a-0506-22f7-269a-eaffe963111d.png">

サインイン後、Lambdaが出力するHTMLが表示されれば成功です。

<img width="372" alt="6_lambda.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/192584/8b341d50-5a84-1314-c7a6-42b5478f18ba.png">

CloudwatchLogsを確認すると、アクセストークン等が渡されているのが分かります。

# 雑感

- 慣れてしまえば設定はとても簡単です。(多分)
- OpenID Connectで認証するがブラウザ・ALB間はアクセストークンでなくセッションクッキーでセキュリティを担保する方式は、アクセストークン漏洩の問題がなくてなんかいい感じ。