除了對使用者進行驗證之外,您可能還需要允許其他服務與您的 API 互動。雖然用戶端應用程式可以提供網路登入提示給使用者,請使用者提交其憑證,但還需要另一種方法來進行安全的服務對服務通訊。此頁會介紹進行服務之間驗證的建議方式,並提供範例程式碼。
總覽
為了識別傳送要求至您 API 的服務,需要使用服務帳戶。呼叫服務會使用服務帳戶的私密金鑰來簽署安全的 JSON Web Token (JWT),並將要求中的已簽署 JWT 傳送給您的 API。
在 API 和呼叫服務內進行服務對服務的驗證:
- 建立呼叫服務要使用的服務帳戶與金鑰。
- 在 Cloud Endpoints 服務的 OpenAPI 文件新增驗證支援。
將程式碼新增到呼叫服務,如此就會:
- 建立 JWT 並以服務帳戶私密金鑰簽署。
- 在要求中將已簽署的 JWT 傳送至 API。
ESP 將要求轉送至您的 API 前,會先驗證 JWT 內的憑證附加資訊是否符合您 OpenAPI 文件的設定。ESP 不會檢查該服務帳戶已經獲准的 Cloud Identity 權限。
必要條件
本頁假設您已具備以下條件:
使用金鑰建立服務帳戶
您會需要一個服務帳戶,這個服務帳戶需擁有呼叫服務用來簽署 JWT 的私密金鑰檔案。如果您有多個服務會向您的 API 發送要求,則可建立一個服務帳戶來代表所有的呼叫服務。如果您需要區別不同服務 (例如各服務具有的權限可能各不相同),就可以為每個呼叫服務建立服務帳戶和金鑰。
本節會示範如何使用 Google Cloud 控制台與 gcloud 指令列工具來建立服務帳戶與私密金鑰檔案,並將服務帳戶憑證建立者角色指派給服務帳戶。如要瞭解如何使用 API 進行這項工作,請參閱「建立和管理服務帳戶」。
如何建立服務帳戶和金鑰:
Google Cloud 控制台
建立服務帳戶:
前往 Google Cloud 控制台的「建立服務帳戶」頁面。
選取要使用的專案。
在 [Service account name] (服務帳戶名稱) 欄位中輸入一個名稱。
選用:在「服務帳戶說明」欄位中輸入說明。
點選「建立」。
按一下 [完成]。
請勿關閉瀏覽器視窗。您將在下一個步驟中使用此項目。
建立服務帳戶金鑰:
- 在 Google Cloud 控制台中,按一下您建立的服務帳戶電子郵件地址。
- 點選「金鑰」。
- 依序點選「新增金鑰」和「建立新的金鑰」。
- 按一下「建立」,隨後一個包含服務帳戶私密金鑰的 JSON 檔案就會下載到電腦中。
- 按一下 [關閉]。
gcloud
您可以使用本機電腦上的 Google Cloud CLI 或在 Cloud Shell 內執行下列指令。
設定
gcloud的預設帳戶。如果您有多個帳戶,請確認所選擇的帳戶位於您要使用的 Google Cloud 專案中。gcloud auth login顯示 Google Cloud 專案的專案 ID。
gcloud projects list設定預設專案。將
PROJECT_ID替換為您要使用的 Google Cloud 專案 ID。gcloud config set project PROJECT_ID
建立服務帳戶。將
SA_NAME和SA_DISPLAY_NAME替換為您要使用的名稱和顯示名稱。gcloud iam service-accounts create SA_NAME \ --display-name "SA_DISPLAY_NAME"
顯示剛剛建立的服務帳戶的電子郵件地址。
gcloud iam service-accounts list新增服務帳戶憑證建立者角色。將
SA_EMAIL_ADDRESS替換成服務帳戶的電子郵件地址。gcloud projects add-iam-policy-binding PROJECT_ID \ --member serviceAccount:SA_EMAIL_ADDRESS \ --role roles/iam.serviceAccountTokenCreator
在目前的工作目錄中建立服務帳戶金鑰檔案。將
FILE_NAME替換為您要用於金鑰檔案的名稱。根據預設,gcloud指令會建立一個 JSON 檔案。gcloud iam service-accounts keys create FILE_NAME.json \ --iam-account SA_EMAIL_ADDRESS
如要進一步瞭解上述指令,請參閱 gcloud 參考資料。
如需私密金鑰保護措施的相關資訊,請參閱管理憑證的最佳做法。
設定 API 以支援驗證
在您的 OpenAPI 文件中必須擁有安全性需求物件與安全性定義物件,讓 ESP 能夠驗證已簽署 JWT 中的憑證附加資訊。
在 OpenAPI 文件中將服務帳戶新增為發行者:
securityDefinitions: DEFINITION_NAME: authorizationUrl: "" flow: "implicit" type: "oauth2" x-google-issuer: "SA_EMAIL_ADDRESS" x-google-jwks_uri: "https://www.googleapis.com/robot/v1/metadata/x509/SA_EMAIL_ADDRESS"- 將
DEFINITION_NAME替換成可用來識別此安全性定義的字串。建議將其替換成服務帳戶名稱或是能辨別呼叫服務的名稱。 - 將
SA_EMAIL_ADDRESS替換成服務帳戶的電子郵件地址。 - 您可以在 OpenAPI 文件中定義多項安全定義,但是每項定義必須要有不同的
x-google-issuer。如果您為每個呼叫服務建立了個別的服務帳戶,則可以再為每個服務帳戶建立安全性定義,例如:
securityDefinitions: service-1: authorizationUrl: "" flow: "implicit" type: "oauth2" x-google-issuer: "service-1@example-project-12345.iam.gserviceaccount.com" x-google-jwks_uri: "https://www.googleapis.com/robot/v1/metadata/x509/service-1@example-project-12345.iam.gserviceaccount.com" service-2: authorizationUrl: "" flow: "implicit" type: "oauth2" x-google-issuer: "service-2@example-project-12345.iam.gserviceaccount.com" x-google-jwks_uri: "https://www.googleapis.com/robot/v1/metadata/x509/service-2@example-project-12345.iam.gserviceaccount.com"- 將
也可以將
x-google-audiences新增至securityDefinitions區段。如果您沒有新增x-google-audiences,ESP 會要求 JWT 中的"aud"(目標對象) 憑證附加資訊格式為https://SERVICE_NAME,其中 SERVICE_NAME 是您的 Endpoints 服務名稱 (您已在 OpenAPI 文件的host欄位中設定的名稱),除非使用--disable_jwt_audience_service_name_check旗標。如果使用這個旗標但未指定x-google-audiences,系統就不會檢查 JWTaud欄位。也可以將
x-google-jwt-locations新增至securityDefinitions區段。您可以使用這個值定義自訂 JWT 位置。JWT 預設位置為Authorization標頭 (前置字串為「Bearer 」)、X-Goog-Iap-Jwt-Assertion標頭或access_token查詢參數。注意:- 如果您指定
x-google-jwt-locations,Endpoints 會忽略所有預設位置。 - ESPv2 僅支援
x-google-jwt-locations。
- 如果您指定
在檔案頂層 (非縮排或巢狀結構) 新增一個
security區段,並套用至整個 API,或是在方法層中套用至特定方法。如果您在 API 層級和方法層級使用security區段,方法層級的設定就會覆寫 API 層級的設定。security: - DEFINITION_NAME: []
- 將
DEFINITION_NAME替換成您在securityDefinitions區段中使用的名稱。 如果您在
securityDefinitions區段中有多個定義,請將其新增至security區段,例如:security: - service-1: [] - service-2: []
- 將
部署更新後的 OpenAPI 文件。將
OPENAPI_DOC替換為 OpenAPI 文件的名稱。gcloud endpoints services deploy OPENAPI_DOC
在 ESP 向您的 API 轉送要求之前,ESP 會驗證以下項目:
- 使用公開金鑰的 JWT 簽署,位於 OpenAPI 文件中
x-google-jwks_uri欄位指定的 URI。 - JWT 中的
"iss"(發行者) 憑證附加資訊與x-google-issuer欄位指定的值是否相符。 - JWT 中的
"aud"(目標對象) 憑證附加資訊是否含有您的 Endpoints 服務名稱,或是否與x-google-audiences欄位指定的其中一個值相符。 - 使用
"exp"(到期時間) 憑證附加資訊,確認憑證並未過期。
如要進一步瞭解 x-google-issuer、x-google-jwks_uri、x-google-audiences 和 x-google-jwt-locations,請參閱 OpenAPI 擴充功能。
向 Endpoints API 發出經過驗證的要求
為了發出經過驗證的要求,呼叫服務會傳送您在 OpenAPI 文件中指定的服務帳戶簽署的 JWT。呼叫服務必須:
- 建立一個 JWT,並以服務帳戶私密金鑰簽署。
- 在要求中將簽署的 JWT 傳送至 API。
以下範例程式碼示範了部分語言的這項程序。如要以其他語言提出已驗證的要求,請參閱 jwt.io,瞭解支援的程式庫清單。
- 在呼叫服務中,新增以下函式,並將以下參數傳送給函式:
Java saKeyfile:服務帳戶私密金鑰檔案的完整路徑。saEmail:服務帳戶的電子郵件地址。-
audience:如果已在 OpenAPI 文件中新增了x-google-audiences欄位,請將audience設定為您指定給x-google-audiences的其中一個值。或是將audience設定為https://SERVICE_NAME,其中SERVICE_NAME是您的 Endpoints 服務名稱。 expiryLength:JWT 的到期時間,以秒為單位。
Python sa_keyfile:服務帳戶私密金鑰檔案的完整路徑。sa_email:服務帳戶的電子郵件地址。-
audience:如果已在 OpenAPI 文件中新增了x-google-audiences欄位,請將audience設定為您指定給x-google-audiences的其中一個值。或是將audience設定為https://SERVICE_NAME,其中SERVICE_NAME是您的 Endpoints 服務名稱。 expiry_length:JWT 的到期時間,以秒為單位。
Go saKeyfile:服務帳戶私密金鑰檔案的完整路徑。saEmail:服務帳戶的電子郵件地址。-
audience:如果已在 OpenAPI 文件中新增了x-google-audiences欄位,請將audience設定為您指定給x-google-audiences的其中一個值。或是將audience設定為https://SERVICE_NAME,其中SERVICE_NAME是您的 Endpoints 服務名稱。 expiryLength:JWT 的到期時間,以秒為單位。
此函式會建立一個 JWT,並使用私密金鑰檔案來簽署 JWT,然後將已簽署的 JWT 傳回。
Java Python Go - 在呼叫服務中,新增下列函式,以在要求中使用
Authorization: Bearer標頭傳送已簽署的 JWT 給 API:Java Python Go
當您使用 JWT 傳送一項要求時,基於安全考量,建議您將驗證憑證放入 Authorization: Bearer 標頭之中。例如:
curl --request POST \
--header "Authorization: Bearer ${TOKEN}" \
"${ENDPOINTS_HOST}/echo"
其中 ENDPOINTS_HOST 和 TOKEN 分別是內含您 API 主機名稱和 API 驗證憑證的環境變數。
在 API 中接收驗證結果
ESP 通常會轉發所有接收到的標頭。不過,如果後端位址是由 OpenAPI 規格中的 x-google-backend 或 gRPC 服務設定中的 BackendRule 指定,系統就會覆寫原始的 Authorization 標頭。
ESP 會將 X-Endpoint-API-UserInfo 中的驗證結果傳送至後端 API。建議您使用這個標頭,取代原始的 Authorization 標頭。這個標頭是字串,base64url 會編碼 JSON 物件。ESPv2 和 ESP 的 JSON 物件格式不同。
如果是 ESPv2,JSON 物件就是原始 JWT 酬載。對於 ESP,JSON 物件會使用不同的欄位名稱,並將原始 JWT 酬載放在 claims 欄位下。如要進一步瞭解格式,請參閱「在後端服務中處理 JWT」。