使用 Application Load Balancer 驗證使用者 - Elastic Load Balancing

本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。

使用 Application Load Balancer 驗證使用者

您可以設定 Application Load Balancer 器,以便在使用者存取您的應用程式時安全地驗證使用者。這可讓您將驗證使用者的工作卸載到您的負載平衡器,使得您的應用程式可以專注在商業邏輯上。

支援下列使用案例:

  • 透過與 OpenID Connect (OIDC) 相容的身分提供者 (IdP) 驗證使用者。

  • 透過社交驗證使用者 IdPs, 如亞馬遜, 臉書, 或谷歌, 通過 Amazon Cognito 支持的用戶池.

  • 透過 Amazon Cognito 支援的使用者集區使用 SAML、LDAP 或微軟 AD,透過公司身分識別驗證使用者。

準備使用符合 OIDC 標準的 IdP

如果您要搭配 Application Load Balancer 器使用符合 OIDC 標準的 IdP,請執行下列動作:

  • 在 IdP 中建立新 OIDC 應用程式。IdP 的 DNS 必須是可公開解析的。

  • 您必須設定用戶端 ID 和用戶端機密。

  • 取得 IdP 發佈的以下端點:授權、字符和使用者資訊。您可以在配置中找到此信息。

  • 在您的 IdP 應用程式中允許下列其中一個重新導向 URL (無論使用者將使用哪一個),其中 DNS 是負載平衡器的網域名稱,而 CNAME 是應用程式的 DNS 別名:

    • https://DNS/oauth2/idpresponse

    • https://CNAME/oauth2/idpresponse

準備使用 Amazon Cognito

如果您將 Amazon Cognito 使用者集區與 Application Load Balancer 器搭配使用,請執行下列動作:

  • 建立使用者集區。如需詳細資訊,請參閱《》Amazon Cognito user poolsAmazon Cognito 開發人員指南

  • 建立使用者集區用戶端。您必須設定用戶端來產生用戶端機密,使用代碼授予流程,並支援負載平衡器使用的相同 OAuth 範圍。如需詳細資訊,請參閱《》配置使用者集區應用程式用戶端。Amazon Cognito 開發人員指南

  • 建立使用者集區物件網域。如需詳細資訊,請參閱《》為您的使用者集區新增網域名稱Amazon Cognito 開發人員指南

  • 驗證請求的範圍傳回 ID 字符。例如,預設範圍 openid 會傳回 ID 字符,但 aws.cognito.signin.user.admin 範圍則不會。

  • 若要聯合社交或公司 IdP,請在聯合區段啟用 IdP。如需詳細資訊,請參閱《》新增社交登入至使用者集區或者將使用 SAML IdP 的登入資訊新增至使用者集區Amazon Cognito 開發人員指南

  • 在 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/oauth2/oauth2/oauth2/oauth2/oauth2/

若要讓 IAM 使用者設定負載平衡器使用 Amazon Cognito 驗證使用者,您必須授與使用者呼叫cognito-idp:DescribeUserPoolClient動作。

準備使用 Amazon CloudFront

如果您使用的是,請啟用以下設定 CloudFront Application Load Balancer 前面的分佈:

  • 轉寄要求標頭 (全部) — 確保 CloudFront 不會快取已驗證要求的回應。這可避免在驗證工作階段過期後從快取中提供回應。或者,為了在啟用快取時降低此風險, CloudFront 分佈可以設置 time-to-live (TTL) 值要在驗證 Cookie 到期前過期。

  • 查詢字串轉送和快取 (全部) — 確保負載平衡器可存取使用者透過 IdP 驗證所需的查詢字串參數。

  • 餅乾轉發 (全部) — 確保 CloudFront 將所有驗證 Cookie 轉寄至負載平衡器。

設定使用者驗證

您透過為一個或多個接聽程式規則建立驗證動作來設定使用者身分驗證。authenticate-cognitoauthenticate-oidc 動作類型僅支援使用 HTTPS 接聽程式。如需相應欄位的描述,請參閱AuthenticateCognitoActionConfigAuthenticateOidcActionConfigElastic Load Balancing API 參考版

負載平衡器會傳送工作階段 Cookie 給用戶端,以維護驗證狀態。此 Cookie 永遠包含 secure 屬性,因為使用者驗證需要 HTTPS 接聽程式。此 Cookie 包含具有 CORS (跨來源資源共享) 請求的 SameSite=None 屬性。

對於支援需要獨立用戶端驗證之多個應用程式的負載平衡器,每個具有驗證動作的接聽程式規則應具有唯一的 Cookie 名稱。這可確保用戶端在路由傳送至規則中指定的目標群組之前,一律會使用 IdP 進行驗證。

Application Load Balancer 不支援經過 URL 編碼的 Cookie 值不支援經過 URL 編碼的 Cookie 值。

依預設,SessionTimeout 欄位會設為 7 天。如果您需要較短的工作階段,您可以將工作階段逾時設定為最短至 1 秒。如需詳細資訊,請參閱 工作階段逾時

根據您的應用程式適當地設定 OnUnauthenticatedRequest 欄位。例如:

  • 需要使用者使用社交或企業身分登入的應用程式預設選項支援此選項,authenticate。如果使用者未登入,負載平衡器會將請求重新導向至 IdP 授權端點,並且 IdP 會提示使用者使用其使用者界面登入。

  • 提供個人化檢視給已登入的使用者或未登入之使用者的一般檢視的應用程式若要支援此類型的應用程式,請使用allow選項。如果使用者已登入,負載平衡器會提供使用者宣告,而應用程式可提供個人化的檢視。如果使用者未登入,負載平衡器會轉送不帶使用者宣告的請求,而應用程式可提供一般檢視。

  • 單頁應用程式 JavaScript 每隔幾秒鐘加載一次— 如果您使用deny選項中,負載平衡器會將 HTTP 401 未經授權的錯誤傳回給沒有驗證資訊的 AJAX 呼叫。但是,如果使用者已過期驗證資訊,則會將用戶端重新導向至 IdP 授權端點。

負載平衡器必須能夠與 IdP 字符端點 (TokenEndpoint) 和 IdP 使用者資訊端點 (UserInfoEndpoint) 通訊。驗證您的負載平衡器的安全群組和您的 VPC 的網路 ACL 允許對這些端點的傳出存取。驗證您的 VPC 具有網際網路存取。如果您有面對內部的負載平衡器,請使用 NAT 閘道來啟用負載平衡器對這些端點的存取。如需詳細資訊,請參閱《》NAT 閘道基本概念Amazon VPC User Guide

使用以下 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。請依照您的身分識別提供者提供的說明文件來判斷支援的欄位

[{ "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 }]

下列是會指定 authenticate-cognito 動作和 forward 動作的 actions.json 檔案的範例。

[{ "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. 使用者將 HTTPS 要求傳送至 Application Load Balancer 器後方託管的網站。當規則的條件滿足某個驗證動作時,負載平衡器會請求標頭中檢查身分驗證工作階段 Cookie。

  2. 如果 Cookie 不存在,負載平衡器會將使用者重新導向到 IdP 授權端點,使得 IdP 可驗證使用者。

  3. 驗證使用者之後,IdP 會使用授權授與代碼將使用者傳回負載平衡器。

  4. 負載平衡器向 IdP 令牌端點提供授權授予代碼。

  5. 在收到有效的授權授與代碼後,IdP 會向 Application Load Balancer 器提供 ID 權杖和存取權杖。

  6. 然後,Application Load Balancer 將訪問令牌發送到用戶信息端點。

  7. 用戶信息端點將訪問令牌交換為用戶聲明。

  8. Application Load Balancer 器會重新導向使用者AWSELB原始 URI 的驗證工作階段 Cookie。由於大多數瀏覽器將 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 到期時間與驗證工作階段到期時間不同。餅乾有效期是餅乾的一個屬性,它被設置為 40 年。長期到期的原因是為了確保瀏覽器始終重播 cookie。驗證工作階段的實際長度取決於在 Application Load Balancer 器上為驗證功能設定的工作階段逾時。此會話超時包含在身份驗證 cookie 值中,該值也經過加密。

用戶聲明編碼和簽名驗證

負載平衡器成功驗證使用者之後,它會將從 IdP 收到的使用者宣告傳送到目標。負載平衡器會簽署使用者宣告,讓應用程式可以驗證簽章並驗證宣告是由負載平衡器傳送。

負載平衡器會新增下列 HTTP 標頭:

x-amzn-oidc-accesstoken

來自字符端點的存取字符,純文字格式。

x-amzn-oidc-identity

來自使用者資訊端點的主旨欄位 (sub),純文字格式。

x-amzn-oidc-data

使用者宣告,JSON Web 字符 (JWT) 格式。

訪問令牌和用戶聲明與 ID 令牌不同。訪問令牌和用戶聲明僅允許訪問服務器資源,而 ID 令牌攜帶其他信息來驗證用戶。應用程序負載平衡器對用戶進行身份驗證,並僅將訪問令牌和聲明傳遞給後端,但不會傳遞 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 承載為 JSON 物件,其中包含從 IdP 使用者資訊端點收到的使用者宣告。

{ "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 器驗證 Token 中包含的填充不相容。

逾時

工作階段逾時

重新整理字符和工作階段逾時的共同運作方式如下所示:

  • 如果工作階段逾時短於存取字符過期,負載平衡器會採用該工作階段逾時。如果使用者有 IdP 的主動工作階段,應該就不會提示使用者再次登入。否則,系統會將使用者重新導向至登入。

    • 如果 IdP 工作階段逾時長於 Application Load Balancer 器工作階段逾時,使用者不需要提供認證即可重新登入。而是使用新的授權授與代碼將 IdP 重新導向回 Application Load Balancer 器。即使沒有重新登錄,授權碼也是一次性使用。

    • 如果 IdP 工作階段逾時等於或短於「Application Load Balancer 器」工作階段逾時,系統會要求使用者提供認證以重新登入。使用者登入後,IdP 會使用新的授權授與代碼重新導向回 Application Load Balancer 器,其餘的驗證流程會繼續進行,直到要求到達後端為止。

  • 如果工作階段逾時時間長於存取權杖到期時間,且 IdP 不支援重新整理權杖,則負載平衡器會保留驗證工作階段,直到逾時為止。然後,它讓用戶再次登錄。

  • 如果工作階段逾時為長於存取字符過期,並且 IdP 支援重新整理字符,負載平衡器會在每次存取字符過期時重新整理該使用者工作階段。負載平衡器只會在驗證工作階段逾或重新整理流程失敗時,才會將使用者再次登入。

用戶端登入逾時

用戶端必須在 15 分鐘內啟動並完成驗證程序。如果用戶端無法在 15 分鐘內完成驗證,則會從負載平衡器收到 HTTP 401 錯誤。此逾時值無法變更或移除。

例如,如果使用者透過 Application Load Balancer 器載入登入頁面,則必須在 15 分鐘內完成登入程序。如果使用者等待 15 分鐘逾時後嘗試登入,負載平衡器會傳回 HTTP 401 錯誤。使用者必須重新整理頁面並嘗試再次登入。

驗證登出

當應用程式需要將已驗證的使用者登出時,您應該將驗證工作階段 Cookie 的過期時間設定為 -1,並將用戶端重新導向至 IdP 登出端點 (如果 IdP 有支援)。為了防止使用者重複使用已刪除的 Cookie,建議您將存取字符設定為合理的簡短過期時間。如果用戶端為負載平衡器提供具有已過期存取權杖且具有非 Null 重新整理權杖的工作階段 Cookie,則負載平衡器會聯絡 IdP 以判斷使用者是否仍然登入。

用戶端登出登陸頁面是未經驗證的頁面。這表示它不能落後於需要驗證的 Application Load Balancer 器規則之後。

  • 將要求傳送至目標時,應用程式必須將所有驗證 Cookie 的到期時間設定為 -1。應用程式負載平衡器支援最大 16K 的 Cookie,因此最多可建立 4 個碎片以傳送給用戶端。

    • 如果 IdP 具有登出端點,則應發出重新導向至 IdP 登出端點,例如登出端點記錄在Amazon Cognito 開發人員指南

    • 如果 IdP 沒有登出端點,請求會返回到用戶端登出登陸頁面,並重新啟動登入程序。

  • 假設 IdP 具有登出端點,則 IdP 必須使存取權杖和重新整理權杖過期,並將使用者重新導向回用戶端登出登入頁面。

  • 後續要求會遵循原始驗證流程。