AWS ALB と Entra ID (旧 Azure AD) を SAML 認証で連携する
AWS ALB には認証機能があり、バックのターゲットへリクエストを流す前に認証を行うようルールを構成することができます。ここでは Microsoft Entra ID (旧 Azure AD) と連携して SAML 認証を行う設定について説明します。
構成
ALB は認証方法として OpenID Connect (OIDC) または Amazon Cognito をサポートしています。ALB で直接 SAML を扱うことはできないので、ALB からは AWS Cognito を指定し、Cognito 側で Entra ID との SAML 連携を行います。
あくまで SAML を処理するのは Cognito であり、ALB は Cognito からユーザ情報を受け取るという点に留意してください[1]。
Cognito リソースの準備
最初に一部の Cognitor リソースを作成し、Entra ID の SAML 設定時に必要になる名前や ID を確定させておきます。
Cognito User Pool 作成
Cognito ユーザープールを作成します。Web コンソールの GUI で作成してもよいのですが、選択項目が多めなので、ここについてはシンプルに作成できる AWS CLI を使って作成します。
AWS CLI を使う環境が整っていない場合は、Web コンソール上部にある Cloud Shell が簡単でおすすめです。
以下のコマンドでユーザープールを作成します。my-user-pool
を適当な名前で置き換えてください。このコマンドでは Entra ID 外ユーザのサインアップを防ぐために --admin-create-user-config '{"AllowAdminCreateUserOnly":true}'
を指定しています。
aws cognito-idp create-user-pool \
--pool-name my-user-pool \
--admin-create-user-config '{"AllowAdminCreateUserOnly":true}'
出力が以下のようになるので、Id
の値を控えておきます。この場合は ap-northeast-1_3dmYPi9Cn
です。
{
"UserPool": {
"Id": "ap-northeast-1_3dmYPi9Cn",
"Name": "my-user-pool",
"Policies": {
...
}
}
}
Cognito ドメイン作成
Cognito のホステッド UI を使うためのドメインを作成します。このドメインは SAML 認証後の応答の宛先 (Reply URL) として使われます。
独自ドメインを使うこともできますが、簡単のため Cognito のサブドメインを使って作成します。作成されるドメインは https://<yourDomainPrefix>.auth.<aws-region>.amazoncognito.com
の形になるので、グローバルユニークな名前になるようにコマンドの --domain <yourDomainPrefix>
部分を置き換えてください。
aws cognito-idp create-user-pool-domain \
--domain <yourDomainPrefix> \
--user-pool-id <yourUserPoolID>
ここでは以下のように実行したものとします。もしドメインが既に使われていてエラーになる場合は適宜変更してください。
aws cognito-idp create-user-pool-domain \
--domain my-cognito-auth-test \
--user-pool-id ap-northeast-1_3dmYPi9Cn \
--region ap-northeast-1
このとき生成されるドメインは次のようになります。これも控えておきます。
https://my-cognito-auth-test.auth.ap-northeast-1.amazoncognito.com
なお、Web UI からドメイン作成を行う場合は、Amazon Cognito > ユーザープール > [対象のユーザープール]
内にあるタブの アプリケーションの統合
から作成できます。
Entra ID (Azure AD) SAML 設定
次に Azure Entra ID 側を設定します。
エンタープライズアプリケーションから、独自のアプリケーションの作成
に進みます。任意の名前でアプリケーションを作成します。
シングルサインオンの設定では SAML を選択し設定を進めます。
SAML SSO セットアップ
入力が必要になるのは
- 識別子 (エンティティ ID)
- 応答 URL (Reply URL, Assertion Consumer Service URL)
です。先ほど作成した Cognito の情報を使って入力していきます。
識別子 (エンティティ ID) に入力する値は、Cognito のユーザープール ID を含む urn:amazon:cognito:sp:<user pool id>
の形式になります。
今回作成したユーザープール ID ap-northeast-1_3dmYPi9Cn
の例では以下のようになります。
urn:amazon:cognito:sp:ap-northeast-1_3dmYPi9Cn
応答 URL には、Cognito の https://<ホステッド UI のドメイン>/saml2/idpresponse
を入力します。例えば、先ほど作成したドメインの例であれば以下です。
https://my-cognito-auth-test.auth.ap-northeast-1.amazoncognito.com/saml2/idpresponse
基本的な SAML 構成が入力できたら、下部証明書の中にあるフェデレーションメタデータ URL をコピーして控えておきます。
設定保存時にテストをするかを聞かれるかもしれませんが、この構成ではテストできないためスキップで問題ありません。
(省略可) クレームの追加
ユーザーの属性やロールの割り当てによって認可情報を渡したい場合は、属性とクレームより任意の情報を追加するこができます。
例えば、エンタープライズアプリケーション内で割り当てたロールを渡したい場合は user.assignedroles
をクレームに含めます。
クレーム名を http://my.examples.com/claims/roles
としたならば、以下の図のようになります。
ここで設定したクレーム名は Cognito でユーザ属性にマッピングする必要があります。
ALB のドメインを確定
アクセスの起点および認証後に戻ってくる URL となる ALB のドメインを確定します。HTTPS でアクセスできる必要があるので、適切に証明書を設定可能なドメインを使ってください。
Cognito 設定
作成したユーザープールが Entra ID を外部 ID プロバイダとして使えるように設定します。
Entra ID を ID プロバイダーとして追加
アイデンティティプロバイダーを追加します。
SAML を選択し、先ほど控えたフェデレーションメタデータ URL を入力します。
必要に応じて、属性のマッピングを設定してください。後から追加、変更も可能です。
マッピング例
ユーザープール属性 | SAML属性 |
---|---|
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress | |
custom:roles | http://my.examples.com/claims/roles |
※ custom:roles
のようなカスタム属性は先にユーザープールに定義しておく必要があります。プールの サインアップエクスペリエンス
から設定します。
アプリケーションクライアントを作成
アプリケーションの統合
よりアプリケーションクライアントを作成します。これは ALB が Cognito から情報取得するためのクライアントです。
秘密クライアント
を選択し、許可されているコールバック URL
に https://<ALB ドメイン>/oauth2/idpresponse
(本記事の例では https://my-alb-domain.example.com/oauth2/idpresponse
) を追加します。
ここまでで Entra ID と Cognito の基本設定は完了です。
ALB から Cognito への認証設定
テスト用 Lambda ターゲット
テスト用に適当な Lambda を作成し ALB からの認証済みリクエストを受け付けるようにします。以下は ALB から渡されるヘッダをそのまま表示する関数の例です。あくまで本記事の説明用なのでご注意ください。
export const handler = async (event, context) => {
const headers = event.headers;
let content = '';
for (let key in headers) {
content += `${key} : ${headers[key]}\n`;
}
const response = {
statusCode: 200,
headers: {"content-type": "text/plain"},
body: content,
};
return response;
};
この Lambda 関数を作成しターゲットグループとして登録しておきます。
ALB 認証ルール設定
ALB のルールアクションで、認証に Cognito を使うよう設定します。認証後にルーティングされるターゲットグループとして先程の Lambda のものを指定します。
ユーザープール、ドメイン、アプリケーションクライアントがここまで作成したものになっているか確認してください。
動作確認
準備ができたら、プライベートブラウジングで開発ツールを開きながら ALB にアクセスしてみます。うまく行っていれば概ね以下のような流れでリクエストが流れるはずです。
- ALB
https://my-alb-domain.example.com/
にアクセス - Cognito のログイン画面
https://my-cognito-auth-test.auth.ap-northeast-1.amazoncognito.com/
にリダイレクト - Entra ID のログイン画面
https://login.microsoftonline.com
にリダイレクト - Microsoft アカウントのログイン処理が続く
- Cognito の応答 URL
https://my-cognito-auth-test.auth.ap-northeast-1.amazoncognito.com/saml2/idpresponse
に戻ってくる - ALB のコールバック URL
https://my-alb-domain.example.com/oauth2/idpresponse
にリダイレクト - 元の URL
https://my-alb-domain.example.com/
にリダイレクト - Lambda で用意したコンテンツが表示される
ブラウザには先程のテスト用 Lambda により ALB から渡されるヘッダが表示されるはずです。
accept : text/html,...
accept-encoding : gzip, deflate, br, zstd
...
x-amzn-oidc-accesstoken : eyJraWQi......
x-amzn-oidc-data : eyJ0eXAiOiJKV1......
x-amzn-oidc-identity : ********-****-****-****-************
...
x-amzn-oidc-data
が Entra ID の SAML レスポンスを反映した内容になっています。公式ドキュメントいわく JWT ということですが、2024/07/20現在、標準に沿わないパディングが含まれた形式になっています。JWT ライブラリによってはデコードできないことがあるかと思いますのでご注意ください。
これをデコードすると Entra ID の SAML 設定で指定したクレームが含まれていることが確認できます。デコードはテスト目的であれば https://jwt.io/ などのサービスを使うと簡単です。
ローカルでデコードする場合は、公式ドキュメント中の python の例や npm の jwt-decode、rubygem jwt (検証 false にする必要あり)、あるいは coreutils に含まれる basenc
コマンドなどが使えます。
echo eyJ0eXAiOiJKV1...... | tr '.' '\n' | head -n2 | basenc -d --base64url
また、 x-amzn-oidc-accesstoken
は Cognito から発行されたアクセストークンです。これを使って Cognito からユーザ情報を取得することもできます[2]。
実際のアプリケーションではこれらのヘッダを使って SAML 認証されたユーザー情報を扱うことができます。
まとめ
肝心の x-amzn-oidc-data
部分が非標準 JWT になっているという扱いにくさはあるものの、ALB と Cognito を使えばフルマネージドで SAML を受けることができます。ALB の豊富な機能と合わせ、バックエンドのターゲットをシンプルに保ちつつ、認証の選択肢を増やせるかと思います。
参考資料・関連リンク
- How to set up Amazon Cognito for federated authentication using Azure AD | AWS Security Blog
- Application Load Balancer を使用してユーザーを認証する - Elastic Load Balancing
- RFC 7515 - JSON Web Signature (JWS)
- JSON Web Tokens - jwt.io
- ALB + Cognito認証で付与されるユーザー情報をEC2サイドから眺めてみる | DevelopersIO
Discussion