Application Load Balancer を使用してユーザーを認証するを参照してください。 - Elastic Load Balancing

Application Load Balancer を使用してユーザーを認証するを参照してください。

Application Load Balancer を設定して、ユーザーがアプリケーションにアクセスしたときに安全に認証できます。これにより、アプリケーションがビジネスロジックに集中できるように、ユーザーを認証する作業をロードバランサーに任せることができます。

次にユースケースがサポートされています。

  • OpenID Connect (OIDC) に準拠する ID プロバイダー (IdP) を使用してユーザーを認証します。

  • Amazon、FaceBook、または Google などのソーシャル IdP を介して、Amazon Cognito でサポートされているユーザープールを経由して、ユーザーを認証します。

  • 企業アイデンティティを介して、SAML、LDAP、または Microsoft AD を使用して、Amazon Cognito でサポートされているユーザープールを経由して、ユーザーを認証します。

OIDC 準拠 IdP を使用する準備を整える

Application Load Balancer で OIDC 準拠 IdP を使用している場合は、以下を実行します。

  • IdP に新しい OIDC アプリを作成します。クライアント ID およびクライアントシークレットを設定する必要があります。

  • その IdP によって発行される次のエンドポイントを取得します。認証、トークン、およびユーザー情報。この情報は config で確認できます。

  • IdP アプリで次のリダイレクト URL のいずれかを許可します。ユーザーが使用するものであればどれでも構いません。ここで DNS はロードバランサーのドメイン名であり、CNAME はアプリケーションの DNS エイリアスです。

    • https://DNS/oauth2/idpresponse

    • https://CNAME/oauth2/idpresponse

Amazon Cognito を使用する準備を行う

Application Load Balancer でAmazon Cognito ユーザープールを使用している場合は、以下を実行します。

  • ユーザープールを作成します。詳細については、Amazon Cognito デベロッパーガイドAmazon Cognito user poolsを参照してください。

  • ユーザープールのクライアントを作成します。クライアントシークレットを生成し、コード付与フローを使用し、ロードバランサーが使用するものと同じ OAuth スコープをサポートするように、クライアントを設定する必要があります。詳細については、Amazon Cognito デベロッパーガイドConfiguring a user pool app client を参照してください。

  • ユーザープールのドメインを作成します。詳細については、Amazon Cognito デベロッパーガイドAdding a Domain name for your user pool を参照してください。

  • リクエストされたスコープで ID トークンが返されていることを確認します。たとえば、デフォルトのスコープ openid では ID トークンが返されますが、aws.cognito.signin.user.admin スコープでは返されません。

  • ソーシャルまたは企業 IdP と連携するには、フェデレーションセクションで IdP を有効にします。詳細については、Amazon Cognito デベロッパーガイドAdd social sign-in to a user pool または Add sign-in with a SAML IdP to a user pool を参照してください。

  • Amazon Cognito のコールバック URL フィールドで次のリダイレクト URL のいずれかを許可します。ここで DNS はロードバランサーのドメイン名であり、CNAME はアプリケーションの DNS エイリアス (使用している場合) です。

    • https://DNS/oauth2/idpresponse

    • https://CNAME/oauth2/idpresponse

  • IdP アプリのコールバック URL でユーザープールドメインを許可します。IdP の形式を使用します。以下に例を示します。

    • https://domain-prefix.auth.region.amazoncognito.com/saml2/idpresponse

    • https://user-pool-domain/oauth2/idpresponse

IAM ユーザーを有効にして、ロードバランサーで Amazon Cognito を使用してユーザーを認証するように設定するには、cognito-idp:DescribeUserPoolClient アクションを呼び出すアクセス権限をユーザーに付与する必要があります。

Amazon CloudFront を使用する準備を行う

Application Load Balancer の前面で CloudFront ディストリビューションを使用している場合は、次の設定を有効にします。

  • 転送リクエストヘッダー (すべて) — CloudFront が認証されたリクエストに対する応答をキャッシュしないようにします。これにより、認証セッションが期限切れになった後にキャッシュから処理されるのを防ぎます。または、キャッシュが有効になっている間にこのリスクを軽減するために、CloudFront ディストリビューションの所有者は、認証 Cookie が期限切れになる前に有効期限 (TTL) の値を期限切れに設定することができます。

  • クエリ文字列の転送とキャッシュ (すべて) — ロードバランサーが、IdP を使用してユーザーを認証するために必要なクエリ文字列パラメータにアクセスできるようにします。

  • Cookie 転送 (すべて) — CloudFront がすべての認証 Cookie をロードバランサーに転送するようにします。

ユーザー認証を設定する

1 つ以上のリスナールールの認証アクションを作成して、ユーザー認証を設定します。authenticate-cognito および authenticate-oidc アクションタイプは HTTPS リスナーでのみサポートされています。対応するフィールドの説明については、Elastic Load Balancing API リファレンスバージョン 2015-12-01AuthenticateCognitoActionConfig および AuthenticateOidcActionConfig を参照してください。

ロードバランサーは、認証ステータスを維持するためにセッション Cookie をクライアントに送信します。ユーザー認証には HTTPS リスナーが必要であるため、この Cookie には常に secure 属性が含まれます。この Cookie には、CORS (クロスオリジンリソース共有) リクエストを持つ SameSite=None 属性が含まれています。

独立したクライアント認証を必要とする複数のアプリケーションをサポートしているロードバランサーについては、認証アクションがある各リスナールールに一意の cookie 名が必要です。これは、クライアントが常に IdP で認証されてから、ルールで指定されているターゲットグループにルーティングされることを確実にします。

Application Load Balancer は、URL エンコードされた Cookie 値をサポートしていません。

デフォルトでは、SessionTimeout フィールドは 7 日に設定されています。セッションをこれより短くするばあいは、セッションタイムアウトを最短 1 秒に設定できます。詳細については、「セッションタイムアウト」を参照してください。

アプリケーションの必要に応じて、OnUnauthenticatedRequest フィールドを設定します。以下に例を示します。

  • ユーザーがソーシャル ID または企業 ID を使用してログインする必要があるアプリケーション — デフォルトのオプション authenticate でサポートされています。ユーザーがログインしていない場合は、ロードバランサーはリクエストを IdP 認証エンドポイントにリダイレクトし、IdP によってユーザーにユーザーインターフェイスを使用したログインを求めるプロンプトが表示されます。

  • ログインしているユーザーにはパーソナライズされたビューを、ログインしていないユーザーには一般的なビューを提供するアプリケーション — このタイプのアプリケーションをサポートするには、allow オプションを使用します。ユーザーがログインしている場合、ロードバランサーがユーザークレームを提供するため、アプリケーションはパーソナライズされたビューを提供できます。ユーザーがログインしていない場合、ロードバランサーはリクエストをユーザークレームなしで転送するため、アプリケーションは一般的なビューを提供できます。

  • 数秒ごとにロードされる JavaScript を使用した単一ページのアプリケーションdeny オプションを使用すると、ロードバランサーは認証情報のない AJAX 呼び出しに対して HTTP 401 Unauthorized エラーを返します。ただし、ユーザーに有効期限の切れた認証情報がある場合は、クライアントを IdP 認証エンドポイントにリダイレクトします。

ロードバランサーは、IdP トークンのエンドポイント (TokenEndpoint) および IdP ユーザー情報エンドポイント (UserInfoEndpoint) と通信できる必要があります。ロードバランサーのセキュリティグループおよび VPC のネットワーク ACL がこれらのエンドポイントに対するアウトバウンドアクセスを許可していることを検証します。VPC がインターネット接続されていることを確認します。内部向けロードバランサーがある場合は、NAT ゲートウェイを使用して、ロードバランサーからこれらのエンドポイントにアクセスできるようにします。詳細については、Amazon VPC ユーザーガイドNAT ゲートウェイベーシック を参照してください。

次の create-rule コマンドを使用して、ユーザー認証を設定します。

aws elbv2 create-rule --listener-arn listener-arn --priority 10 \ --conditions Field=path-pattern,Values="/login" --actions file://actions.json

actions.json ファイルの例を次に示します。authenticate-oidc アクションと forward アクション AuthenticationRequestExtraParams を使用すると、認証中に IdP に追加のパラメーターを渡すことができます。ID プロバイダーから提供されたドキュメントに従って、サポートされているフィールドを確認してください。

[{ "Type": "authenticate-oidc", "AuthenticateOidcConfig": { "Issuer": "https://idp-issuer.com", "AuthorizationEndpoint": "https://authorization-endpoint.com", "TokenEndpoint": "https://token-endpoint.com", "UserInfoEndpoint": "https://user-info-endpoint.com", "ClientId": "abcdefghijklmnopqrstuvwxyz123456789", "ClientSecret": "123456789012345678901234567890", "SessionCookieName": "my-cookie", "SessionTimeout": 3600, "Scope": "email", "AuthenticationRequestExtraParams": { "display": "page", "prompt": "login" }, "OnUnauthenticatedRequest": "deny" }, "Order": 1 }, { "Type": "forward", "TargetGroupArn": "arn:aws:elasticloadbalancing:region-code:account-id:targetgroup/target-group-name/target-group-id", "Order": 2 }]

actions.json アクションと authenticate-cognito アクションを指定する forward ファイルの例を次に示します。

[{ "Type": "authenticate-cognito", "AuthenticateCognitoConfig": { "UserPoolArn": "arn:aws:cognito-idp:region-code:account-id:userpool/user-pool-id", "UserPoolClientId": "abcdefghijklmnopqrstuvwxyz123456789", "UserPoolDomain": "userPoolDomain1", "SessionCookieName": "my-cookie", "SessionTimeout": 3600, "Scope": "email", "AuthenticationRequestExtraParams": { "display": "page", "prompt": "login" }, "OnUnauthenticatedRequest": "deny" }, "Order": 1 }, { "Type": "forward", "TargetGroupArn": "arn:aws:elasticloadbalancing:region-code:account-id:targetgroup/target-group-name/target-group-id", "Order": 2 }]

詳細については、「リスナールール」を参照してください。

認証のフロー

次のネットワーク図は、Application Load Balancer が OIDC を使用してユーザーを認証する方法を示しています。


                    Application Load Balancer による OIDC を介したユーザーの認証方法

下の番号付き項目は、前のネットワーク図に示した要素を強調表示し、説明しています。

  1. ユーザーは、Application Load Balancer の背後にホストされているウェブサイトに HTTPS リクエストを送信します。認証アクションを持つルールの条件が満たされている場合、ロードバランサーはリクエストヘッダーに認証セッション Cookie があるかどうかを確認します。

  2. Cookie が存在しない場合、ロードバランサーはユーザーを IdP 認証エンドポイントにリダイレクトし、IdP でユーザーを認証できるようにします。

  3. ユーザーが認証されると、IdP は認可付与コードを伴ったユーザーをロードバランサーにリダイレクトして戻します。

  4. ロードバランサーは認可付与コードを IdP トークンエンドポイントに示します。

  5. 有効な認可付与コードを受け取ると、IdP は ID トークンとアクセストークンをApplication Load Balancer に提供します。

  6. 次に、Application Load Balancer がアクセストークンをユーザー情報エンドポイントに送信します。

  7. ユーザー情報エンドポイントは、ユーザーの要求に対してアクセストークンを交換します。

  8. Application Load Balancer は、AWSELB 認証セッション cookie を持つユーザーを元の URI にリダイレクトします。ほとんどのブラウザでは Cookie のサイズを 4K に制限しているため、ロードバランサーはサイズが 4K を超える Cookie を複数の Cookie に分割します。IdP から受け取ったユーザークレームとアクセストークンの合計サイズが 11K バイトを超える場合、ロードバランサーは HTTP 500 エラーをクライアントに返し、ELBAuthUserClaimsSizeExceeded メトリクスを増分します。

  9. Application Load Balancer は Cookie を検証し、ユーザー情報をX-AMZN-OIDC-*HTTP ヘッダー設定のターゲットに転送します。詳細については、「ユーザークレームのエンコードと署名の検証」を参照してください。

  10. ターゲットは応答をApplication Load Balancer に戻します。

  11. Application Load Balancer は、最終応答をユーザーに送信します。

新しいリクエストはステップ 1 ~ 11 を通過し、後続のリクエストはステップ 9 ~ 11 を通過します。つまり、cookie の有効期限が切れていない限り、後続のすべてのリクエストはステップ 9 から始まります。

IdP によって ID トークンに有効な更新トークンが提供されている場合、ロードバランサーは更新トークンを保存し、アクセストークンの有効期限が切れるたびにこれを使用して、セッションがタイムアウトするか、IdP の更新に失敗するまで、ユーザークレームを更新します。ユーザーがログアウトすると、更新は失敗し、ロードバランサーはユーザーを IdP 認証エンドポイントにリダイレクトします。これにより、ロードバランサーはユーザーがログアウト後にセッションを削除できます。詳細については、「セッションタイムアウト」を参照してください。

注記

cookie の有効期限は、認証セッションの有効期限とは異なります。cookie の有効期限は cookie の属性で、40 年に設定されています。有効期限が長くなる理由は、ブラウザが常に cookie を再生するようにするためです。認証セッションの実際の長さは、認証機能用に Application Load Balancer で設定されたセッションタイムアウトによって決まります。このセッションタイムアウトは、認証 cookie 値に含まれ、暗号化されます。

ユーザークレームのエンコードと署名の検証

ロードバランサーがユーザーの認証に成功すると、IdP から受け取ったユーザークレームがターゲットに送信されます。ロードバランサーはユーザークレームに署名するため、アプリケーションは署名の検証およびそのクレームがロードバランサーから送信されたものであることの検証を行うことができます。

ロードバランサーは以下の HTTP ヘッダーを追加します。

x-amzn-oidc-accesstoken

トークンエンドポイントからのアクセストークン (プレーンテキスト)。

x-amzn-oidc-identity

ユーザー情報エンドポイントからの件名フィールド (sub) (プレーンテキスト)。

x-amzn-oidc-data

ユーザークレーム (JSON ウェブトークン (JWT) 形式)

アクセストークンとユーザーの要求が、ID トークンと異なります。アクセストークンとユーザーの要求は、サーバーリソースへのアクセスのみを許可しますが、ID トークンはユーザーを認証するための追加情報を保持しています。Application Load Balancer はユーザを認証し、アクセストークンと要求のみをバックエンドに渡しますが、ID トークン情報は渡しません。

これらのトークンは JWT 形式に従いますが、ID トークンではありません。JWT 形式には、base64 URL エンコードされたヘッダー、ペイロード、および署名が含まれ、末尾にパディング文字が含まれます。JWT 署名は ECDSA + P-256 + SHA256 です。

この JWT ヘッダーは、次のフィールドを持つ JSON オブジェクトです。

{ "alg": "algorithm", "kid": "12345678-1234-1234-1234-123456789012", "signer": "arn:aws:elasticloadbalancing:region-code:account-id:loadbalancer/app/load-balancer-name/load-balancer-id", "iss": "url", "client": "client-id", "exp": "expiration" }

この JWT ペイロードは、IdP ユーザー情報エンドポイントから受け取ったユーザークレームを含む JSON オブジェクトです。

{ "sub": "1234567890", "name": "name", "email": "alias@example.com", ... }

ロードバランサーではユーザークレームが暗号化されないため、HTTPS を使用するようにターゲットグループを設定することをお勧めします。HTTP を使用するようにターゲットグループを設定する場合は、ロードバランサーへのトラフィックをセキュリティグループを使用するトラフィックのみに制限してください。また、クレームに基づいて認証を行う前に、署名を検証することもお勧めします。パブリックキーを取得するには、JWT ヘッダーからキー ID を取得し、それを使用して次のエンドポイントからパブリックキーを検索します: それぞれの AWS リージョンの場合、エンドポイントは次のとおりです:

https://public-keys.auth.elb.region.amazonaws.com/key-id

AWS GovCloud (US) の場合、エンドポイントは次のとおりです。

https://s3-us-gov-west-1.amazonaws.com/aws-elb-public-keys-prod-us-gov-west-1/key-id https://s3-us-gov-east-1.amazonaws.com/aws-elb-public-keys-prod-us-gov-east-1/key-id

次の例では、Python 3.x でパブリックキーを取得する方法を示しています。

import jwt import requests import base64 import json # Step 1: Get the key id from JWT headers (the kid field) encoded_jwt = headers.dict['x-amzn-oidc-data'] jwt_headers = encoded_jwt.split('.')[0] decoded_jwt_headers = base64.b64decode(jwt_headers) decoded_jwt_headers = decoded_jwt_headers.decode("utf-8") decoded_json = json.loads(decoded_jwt_headers) kid = decoded_json['kid'] # Step 2: Get the public key from regional endpoint url = 'https://public-keys.auth.elb.' + region + '.amazonaws.com/' + kid req = requests.get(url) pub_key = req.text # Step 3: Get the payload payload = jwt.decode(encoded_jwt, pub_key, algorithms=['ES256'])

次の例では、Python 2.7 でパブリックキーを取得する方法を示しています。

import jwt import requests import base64 import json # Step 1: Get the key id from JWT headers (the kid field) encoded_jwt = headers.dict['x-amzn-oidc-data'] jwt_headers = encoded_jwt.split('.')[0] decoded_jwt_headers = base64.b64decode(jwt_headers) decoded_json = json.loads(decoded_jwt_headers) kid = decoded_json['kid'] # Step 2: Get the public key from regional endpoint url = 'https://public-keys.auth.elb.' + region + '.amazonaws.com/' + kid req = requests.get(url) pub_key = req.text # Step 3: Get the payload payload = jwt.decode(encoded_jwt, pub_key, algorithms=['ES256'])

標準ライブラリは、JWT 形式のApplication Load Balancer 認証トークンに含まれているパディングと互換性がないことにご注意ください。

セッションタイムアウト

更新トークンとセッションタイムアウトは連携して次のように動作します。

  • セッションタイムアウトがアクセストークンの有効期限より短い場合、ロードバランサーはセッションタイムアウトを優先させます。IdP とのセッションがまだアクティブであれば、ユーザーは再度ログインするように求められないことがあります。それ以外の場合、ユーザーはログインにリダイレクトされます。

    • IdP セッションタイムアウトが Application Load Balancer セッションタイムアウトよりも長い場合、ユーザーは再ログインするために認証情報を入力する必要はありません。代わりに、IdP は新しい認可付与コードを使用して Application Load Balancer にリダイレクトします。認可コードは、再ログインがない場合でも、一度の使用となります。

    • IdP セッションタイムアウトが Application Load Balancer セッションタイムアウト以下の場合、ユーザーは再ログインするための認証情報を指定する必要があります。再ログイン後、IdP は新しい認可コードを使用して Application Load Balancer にリダイレクトし、残りの認証フローはリクエストがバックエンドに到達するまで続行されます。

  • セッションタイムアウトがアクセストークンの有効期限よりも長く、IdP が更新トークンをサポートしていない場合、ロードバランサーは認証セッションをタイムアウトまで維持します。その後、ユーザーが再びログインします。

  • セッションタイムアウトがアクセストークンの有効期限よりも長く、IdP が更新トークンをサポートしている場合、ロードバランサーはアクセストークンの有効期限が切れるたびにユーザーセッションを更新します。ロードバランサーは、認証セッションがタイムアウトした後、または更新フローに失敗した場合にのみ、ユーザーに再度ログインさせます。

認証ログアウト

アプリケーションで認証済みユーザーをログアウトさせる必要がある場合、認証セッション Cookie の有効期限を -1 に設定し、クライアントを IdP ログアウトエンドポイントにリダイレクト (IdP でサポートされている場合) する必要があります。ユーザーが削除された Cookie を再利用しないようにするには、アクセストークンの有効期限を問題のない範囲でできるだけ短く設定することをお勧めします。有効期限切れのアクセストークンと null 以外の更新トークンがあるセッション Cookie を持つロードバランサーをクライアントが提供する場合、ロードバランサーは IdP に接続してユーザーがまだログインしているかどうかを判別します。

クライアントのログアウトランディングページは、認証されていないページです。つまり、認証を必要とする Application Load Balancer ルールの背後に存在することはできません。

  • リクエストがターゲットに送信されると、アプリケーションは、すべての認証 Cookie に対して有効期限を -1 に設定する必要があります。Application Load Balancer は、最大 16K のサイズの Cookie をサポートするため、クライアントに送信するシャードを最大 4 つ作成できます。

    • IdP にログアウトエンドポイントがある場合、IdP ログアウトエンドポイントへのリダイレクトを発行する必要があります。例えば、Amazon Cognito デベロッパーガイド に記載されている ログアウトエンドポイント

    • IdP にログアウトエンドポイントがない場合、リクエストはクライアントのログアウトランディングページに戻り、ログインプロセスが再起動されます。

  • IdP にログアウトエンドポイントがあると仮定すると、IdP はアクセストークンを期限切れにしてトークンを更新し、ユーザーをクライアントのログアウトランディングページにリダイレクトし直す必要があります。

  • 後続のリクエストは、元の認証フローに従います。