OpenAPI 擴充功能

Cloud Endpoints 接受一組 Google 專屬的 OpenAPI 規格擴充功能,這些擴充功能可設定可擴充服務 Proxy (ESP)可擴充服務 Proxy V2 (ESPv2)Service Control 的行為。本頁說明 Google 專屬的 OpenAPI 規格擴充功能。

雖然以下提供的範例為 YAML 格式,但也支援 JSON 格式。

命名慣例

Google OpenAPI 擴充功能的名稱會以前置字串「x-google-」開頭。

x-google-allow

x-google-allow: [configured | all]

這項擴充功能用於 OpenAPI 規格的頂層,可指出您應允許哪些網址路徑通過 ESP。

可能的值為 configuredall

預設值為 configured,代表只有 OpenAPI 規格中列出的 API 方法才能透過 ESP 提供。

如果您使用了 all,無論未經設定的呼叫是否具備 API 金鑰或通過使用者驗證,都會透過 ESP 傳送至您的 API。

ESP 會以區分大小寫的方式處理傳送至 API 的呼叫。舉例來說,ESP 會將 /widgets/Widgets 視為不同的 API 方法。

使用 all 時,請特別留意兩個部分:

  • API 金鑰或驗證規則。
  • 服務中的後端路徑轉送。

建議您將 API 設定為使用區分大小寫路徑轉送功能。使用區分大小寫的轉送功能後,如果網址中要求的方法與 OpenAPI 規格中列出的 API 方法名稱不相符,API 將傳回 HTTP 狀態碼 404。請注意,Node.js Express 等網頁應用程式架構中包含啟用或停用區分大小寫轉送功能的設定選項。預設行為視您使用的架構而定。建議您查看架構中的設定,以確定啟用區分大小寫轉送功能。這項建議與以下 OpenAPI 規格 v2.0 規範一致:「規格中的所有欄位名稱都必須區分大小寫」。

範例

假設:

  • x-google-allow 設為 all
  • OpenAPI 規格中列出的 API 方法是 widgets,而非 Widgets
  • 您已將 OpenAPI 規格設為必須使用 API 金鑰。

widgets 已列於您的 OpenAPI 規格,因此 ESP 會封鎖以下要求,因為該項要求不含任何 API 金鑰:

https://my-project-id.appspot.com/widgets

Widgets 未列於您的 OpenAPI 規格,因此 ESP 會在沒有 API 金鑰的情況下將以下要求傳送至您的服務:

https://my-project-id.appspot.com/Widgets/

如果您的 API 採用了必須區分大小寫的轉送功能,您也尚未將傳送至「Widgets」的呼叫轉送至任何程式碼,API 後端就會傳回 404。不過,如果您使用了不區分大小寫的轉送功能,API 後端就會將這項呼叫轉送至「Widgets」。

不同的程式語言和架構對於控制區分大小寫與轉送功能有不同的方法。詳情請參閱您的架構說明文件。

x-google-backend

x-google-backend 擴充功能會指定要求如何轉送至本機或遠端後端。擴充功能可在 OpenAPI 規格的頂層和/或操作層級指定。

根據預設,ESP 會設定為將所有流量代理至單一本機後端。--backend 標記 (預設為 http://127.0.0.1:8081) 會指定本機後端位址。您可以使用 x-google-backend 擴充功能覆寫這個預設行為,並指定一或多個可接收要求的本機 遠端後端。

x-google-backend 擴充功能也可以為本機和遠端後端設定其他設定,例如驗證和逾時。所有這些設定都可以依個別作業套用。

x-google-backend 擴充功能包含下列欄位:

address

address: URL

(非必要) 目標後端的網址。地址的架構必須是 httphttps

將路由導向至遠端後端 (無伺服器) 時,應設定地址,且配置部分應為 https

如果作業使用 x-google-backend,但未指定 address,ESPv2 會將要求轉送至 --backend 標記指定的本機後端。

jwt_audience | disable_auth

請只設定這兩個屬性中的其中一個。

如果作業使用 x-google-backend,但未指定 jwt_audiencedisable_auth,ESPv2 會自動將 jwt_audience 設為與 address 相符。如果沒有設定 address,ESPv2 會自動將 disable_auth 設為 true

jwt_audience

jwt_audience: string

(非必要) ESPv2 取得執行個體 ID 符記時指定的 JWT 目標對象,日後提出目標後端要求時即會使用這項設定。

設定無伺服器適用的 Endpoints 時,請確保遠端後端只允許 ESPv2 的流量。ESPv2 在代理要求時,會將執行個體 ID 符記附加至 Authorization 標頭。執行個體 ID 權杖代表用於部署 ESPv2 的執行階段服務帳戶。接著,遠端後端就能根據這個附加的符記,驗證要求是否來自 ESPv2。

舉例來說,在 Cloud Run 上部署的遠端後端可以使用 IAM 來執行以下操作:

  1. 從特殊 allUsers 使用者主體撤銷 roles/run.invoker,藉此限制未經驗證的叫用作業。
  2. roles/run.invoker 角色授予 ESPv2 執行階段服務帳戶,只允許 ESPv2 叫用後端。

根據預設,ESPv2 會使用與 address 欄位相符的 JWT 目標對象,建立執行個體 ID 權杖。只有在目標後端使用以 JWT 為基礎的驗證機制,且預期目標對象與 address 欄位不同時,您才需要手動指定 jwt_audience。如果是部署在 App Engine 或透過 IAP 的遠端後端,您必須覆寫 JWT 目標對象。App Engine 和 IAP 會使用其 OAuth 用戶端 ID 做為預期目標對象。

啟用這項功能後,ESPv2 會變更要求中的標頭。如果要求已設定 Authorization 標頭,ESPv2 會執行以下操作:

  1. 將原始值複製到新的標頭 X-Forwarded-Authorization
  2. 使用執行個體 ID 權杖覆寫 Authorization 標頭。

因此,如果 API 用戶端設定 Authorization 標頭,在 ESPv2 後方執行的後端應使用 X-Forwarded-Authorization 標頭擷取整個 JWT。後端必須驗證這個標頭中的 JWT,因為如果未設定驗證方法,ESPv2 就不會執行驗證。

disable_auth

disable_auth: bool

(非必要) 這項屬性會決定 ESPv2 是否應避免取得執行個體 ID 權杖,並避免將其附加至要求。

設定目標後端時,如果符合下列任一情況,建議您不要使用 IAP 或 IAM 驗證 ESPv2 的請求:

  1. 後端應允許未經驗證的叫用。
  2. 後端需要 API 用戶端的原始 Authorization 標頭,且無法使用 X-Forwarded-Authorization (請參閱 jwt_audience 部分)。

在這種情況下,請將這個欄位設為 true

path_translation

path_translation: [ APPEND_PATH_TO_ADDRESS | CONSTANT_ADDRESS ]

(非必要) 可在將要求轉送至目標後端時,設定 ESPv2 採用的路徑轉譯策略。

如要進一步瞭解路徑轉譯,請參閱「瞭解路徑轉譯」一節。

x-google-backend 用於 OpenAPI 規格的頂層時,path_translation 的預設值為 APPEND_PATH_TO_ADDRESSx-google-backend 用於 OpenAPI 規格的操作層級時,path_translation 的預設值則為 CONSTANT_ADDRESS。如果缺少 address 欄位,path_translation 就會保持未指定狀態,不會發生。

deadline

deadline: double

(非必要) 等待要求完整回應的秒數。如果回應時間超過設定的期限,系統就會逾時。預設期限為 15.0 秒。

系統不會採用非正值。在這種情況下,ESPv2 會自動使用預設值。

您無法停用截止期限,但可以將其設為較大的數字,例如 3600.0 (一小時)。

protocol

protocol: [ http/1.1 | h2 ]

(非必要) 用於將要求傳送至後端的通訊協定。支援的值為 http/1.1h2

對於 HTTP 和 HTTPS 後端,預設值為 http/1.1

如果是支援 HTTP/2 的安全 HTTP 後端 (https://),請將此欄位設為 h2,以提升效能。這是 Google Cloud 無伺服器後端的建議選項。

啟用 ESP 中的後端支援

ESPv2 會自動偵測 x-google-backend 的設定。

如要啟用這項功能,ESP 需要手動變更設定。在執行 ESP 容器時提供 --enable_backend_routing 引數,藉此啟用 ESP 中的 x-google-backend 支援。針對您無法控制 ESP 容器選項的執行階段,系統已為您提供這個選項。以下是將 ESP 容器部署至 GKE 時啟用 x-google-backend 支援的範例,這個範例是以 GKE 教學課程中的端點範例為基礎:

- name: esp
  image: gcr.io/endpoints-release/endpoints-runtime:1
  args: [
    "--http_port", "8081",
    "--service", "SERVICE_NAME",
    "--rollout_strategy", "managed",
    "--enable_backend_routing"
  ]

瞭解路徑轉譯

ESP 會在處理要求時擷取原始要求路徑,並在向目標後端提出要求前進行轉譯。這項轉譯作業的具體執行方法取決於您採用的路徑轉譯策略。路徑轉譯策略共有兩種:

  • APPEND_PATH_TO_ADDRESS:將原始要求路徑附加至 x-google-backend 擴充功能的 address 網址,藉此計算目標後端要求的路徑。
  • CONSTANT_ADDRESS:如 x-google-backend 擴充功能的 address 網址所定義,目標要求路徑為固定值。如果相對應的 OpenAPI 路徑含有參數,參數名稱及其值會變為查詢參數。

範例:

  • APPEND_PATH_TO_ADDRESS
    • address: https://my-project-id.appspot.com/BASE_PATH
    • 含有 OpenAPI 路徑參數
      • OpenAPI 路徑:/hello/{name}
      • 要求路徑:/hello/world
      • 目標要求網址:https://my-project-id.appspot.com/BASE_PATH/hello/world
    • 不含 OpenAPI 路徑參數
      • OpenAPI 路徑:/hello
      • 要求路徑:/hello
      • 目標要求網址:https://my-project-id.appspot.com/BASE_PATH/hello
  • CONSTANT_ADDRESS
    • addresshttps://us-central1-my-project-id.cloudfunctions.net/helloGET
    • 含有 OpenAPI 路徑參數
      • OpenAPI 路徑:/hello/{name}
      • 要求路徑:/hello/world
      • 目標要求網址:https://us-central1-my-project-id.cloudfunctions.net/helloGET?name=world
    • 不含 OpenAPI 路徑參數
      • OpenAPI 路徑:/hello
      • 要求路徑:/hello
      • 目標要求網址:https://us-central1-my-project-id.cloudfunctions.net/helloGET

x-google-endpoints

本節將說明如何使用 x-google-endpoints 擴充功能。

設定 cloud.goog 網域的 DNS

如果您已將應用程式部署至 Compute Engine 或 Google Kubernetes Engine,可以將下列項目新增至 OpenAPI 文件,為 cloud.goog 網域的 Endpoints 服務建立 DNS 項目:

x-google-endpoints:
- name: "API_NAME.endpoints.PROJECT_ID.cloud.goog"
  target: "IP_ADDRESS"

在 OpenAPI 文件的頂層 (未使用縮排或巢狀結構) 新增 x-google-endpoints 擴充功能。您必須以下列格式設定網域名稱:.endpoints.PROJECT_ID.cloud.goog

例如:

swagger: "2.0"
host: "my-cool-api.endpoints.my-project-id.cloud.goog"
x-google-endpoints:
- name: "my-cool-api.endpoints.my-project-id.cloud.goog"
  target: "192.0.2.1"

.cloud.goog 是由 Google 代管的網域,可供Google Cloud 客戶共用。由於 Google Cloud 專案 ID 在全域範圍內不會重複,因此採用 .endpoints.PROJECT_ID.cloud.goog 格式的網域名稱即為您的 API 專屬網域名稱。

為求簡便,請為 hostx-google-endpoints.name 欄位設定相同的值。在您部署 OpenAPI 文件時,Service Management 會建立以下項目:

  • 代管服務,名稱為您在 host 欄位中指定的值。
  • DNS A 記錄,使用您在 x-google-endpoints 擴充功能中設定的名稱和 IP 位址。

針對在 App Engine 彈性環境中託管的 API,您可以使用 appspot.com 網域。詳情請參閱設定 Endpoints 一文。

設定 ESP 來允許 CORS 要求

如果會有來自不同來源的網路應用程式呼叫您的 API,則該 API 必須支援跨來源資源共用 (CORS)。如要瞭解如何將 ESP 設為支援 CORS,請參閱為 ESP 新增 CORS 支援一節。

如要在後端程式碼中導入自訂 CORS 支援,請設定 allowCors: True,讓 ESP 將所有 CORS 要求傳送至您的後端程式碼:

x-google-endpoints:
- name: "API_NAME.endpoints.PROJECT_ID.cloud.goog"
  allowCors: True

請在 OpenAPI 文件頂層 (未使用縮排或巢狀結構) 新增 x-google-endpoints 擴充功能,例如:

swagger: "2.0"
host: "my-cool-api.endpoints.my-project-id.cloud.goog"
x-google-endpoints:
- name: "my-cool-api.endpoints.my-project-id.cloud.goog"
  allowCors: True

x-google-issuer

x-google-issuer: URI | EMAIL_ADDRESS

這項擴充功能用於 OpenAPI securityDefinitions 區段,可指定憑證的核發者,其值可以採用主機名稱或電子郵件地址的形式。

x-google-jwks_uri

x-google-jwks_uri: URI

將提供者公開金鑰的 URI 設為驗證 JSON Web Token 的簽名。

ESP 支援 x-google-jwks_uri OpenAPI 擴充功能定義的兩種非對稱式公開金鑰格式:

  • JWK 集合格式。例如:
    x-google-jwks_uri: "https://YOUR_ACCOUNT_NAME.YOUR_AUTH_PROVIDER_URL/.well-known/jwks.json"
    
  • X509。例如:
    x-google-jwks_uri: "https://www.googleapis.com/service_accounts/v1/metadata/x509/securetoken@system.gserviceaccount.com"
    

如果您使用的是對稱式金鑰格式,請將 x-google-jwks_uri 設為含有 base64url 編碼金鑰字串的檔案 URI。

如果您省略 x-google-jwks_uri,ESP 會依照 OpenID Connect Discovery 通訊協定,自動探索指定 OpenID 提供者的 JWKS URI。ESP 會向 x-google-issuer/.well-known/openid-configuration 提出要求、剖析 JSON 回應,並從頂層 jwks_uri 欄位讀取 JWKS URI。

請注意,省略 x-google-jwks_uri 會導致冷啟動時間增加,因為 ESP 必須在啟動時進行額外的遠端呼叫。因此,只有在 JWKS URI 經常變更時,才建議省略這個欄位。大多數經認證的 OpenID 供應商 (例如 Google、Auth0 和 Okta) 都有穩定的 JWKS URI。

x-google-jwt-locations

根據預設,JWT 會透過 Authorization 標頭 (前置 "Bearer ")、X-Goog-Iap-Jwt-Assertion 標頭或 access_token 查詢參數傳遞。如需傳遞 JWT 的範例,請參閱「向 Endpoints API 發出經過驗證的呼叫」。

或者,您也可以在 OpenAPI 的 securityDefinitions 部分中使用 x-google-jwt-locations 擴充功能,提供自訂位置,以便從中擷取 JWT 權杖。

x-google-jwt-locations 擴充功能接受 JWT 位置清單。每個 JWT 位置都包含下列欄位:

元素 說明
header/query 這是必要旗標,含有 JWT 的標頭名稱,或含有 JWT 的查詢參數名稱。
value_prefix (非必要) 僅限標頭。設定 value_prefix 時,其值必須與包含 JWT 的標頭值的前置字串相符。

例如:

x-google-jwt-locations:
  # Expect header "Authorization": "MyBearerToken <TOKEN>"
  - header: "Authorization"
    value_prefix: "MyBearerToken "
  # expect header "jwt-header-foo": "jwt-prefix-foo<TOKEN>"
  - header: "jwt-header-foo"
    value_prefix: "jwt-prefix-foo"
  # expect header "jwt-header-bar": "<TOKEN>"
  - header: "jwt-header-bar"
  # expect query parameter "jwt_query_bar=<TOKEN>"
  - query: "jwt_query_bar"

如果您只想支援部分預設 JWT 位置,請在 x-google-jwt-locations 擴充功能中明確列出這些位置。舉例來說,如要只支援使用 "Bearer " 前置字串的 Authorization 標頭:

  x-google-jwt-locations:
    # Support the default header "Authorization": "Bearer <TOKEN>"
    - header: "Authorization"
      value_prefix: "Bearer "

x-google-audiences

x-google-audiences: STRING

這項擴充功能用於 OpenAPI securityDefinitions 區段,可提供 JWT 驗證期間 JWT aud 欄位應比對的目標對象清單。這項擴充功能接受以逗號分隔資料值的單一字串,但不同目標對象之間不得使用空格。如未指定,JWT aud 欄位應與 OpenAPI 文件中的 host 欄位相符,除非使用標記 --disable_jwt_audience_service_name_check。如果使用旗標且未指定 x-google-audiences,系統不會檢查 JWT aud 欄位。

securityDefinitions:
  google_id_token:
    type: oauth2
    authorizationUrl: ""
    flow: implicit
    x-google-issuer: "https://accounts.google.com"
    x-google-jwks_uri: "https://www.googleapis.com/oauth2/v1/certs"
    x-google-audiences: "848149964201.apps.googleusercontent.com,841077041629.apps.googleusercontent.com"

x-google-management

x-google-management 擴充功能可以控制 API 管理作業的各個不同層面,並包含本節所述的欄位。

metrics

您可以將 metrics配額x-google-quota 搭配使用,為您的 API 設定配額。設定配額之後,您就能控制應用程式呼叫 API 中方法的頻率。例如:

x-google-management:
  metrics:
    - name: read-requests
      displayName: Read requests
      valueType: INT64
      metricKind: DELTA

metrics 欄位中包含具備以下鍵/值組合的清單:

元素 說明
name (必填) 這個指標的名稱。通常這是專門用來辨識指標的要求類型 (例如,「read-requests」或「write-requests」)。
displayName

(選填,但建議使用) 在Google Cloud 主控台「Endpoints」 >「Services」(服務) 頁面的「Quotas」分頁中顯示的文字,用來識別指標。您的 API 使用者也會在「Quotas」(配額)頁面的「IAM & admin」(IAM 與管理員) 和「APIs & Services」(API 和服務) 下方看到該文字。顯示名稱長度上限為 40 個字元。

為方便閱讀,相關聯配額限制的單位會自動附加至Google Cloud 主控台中的顯示名稱後方。舉例來說,如果您將顯示名稱指定為「Read requests」(讀取要求),Google Cloud 主控台就會顯示「Read requests per minute per project」(每個專案每分鐘的讀取要求數)。如果您沒有指定,API 使用者就會在「Quotas」(配額) 頁面的「IAM & admin」(IAM 與管理員) 和「APIs & Services」(APIs 和服務) 下方看到「unlabeled quota」(未加標籤的配額)。

為了與 API 使用者在「Quotas」(配額) 頁面上看到的 Google 服務顯示名稱保持一致,我們對於顯示名稱有以下建議:

  • 當您只有一個指標時,請使用「要求數」。
  • 如果您同時使用多項指標,則每個指標名稱都應說明要求類型,並含有「要求數」一詞,例如「讀取要求數」或「寫入要求數」。
  • 如有任何與指標相關聯的費用大於 1,請使用「配額單位」,而不要使用「要求數」。
valueType (必填) 必須為 INT64
metricKind (必填) 必須為 DELTA

quota

quota 區段中,您可以為已定義的指標指定配額限制。例如:

quota:
  limits:
    - name: read-requests-limit
      metric: read-requests
      unit: 1/min/{project}
      values:
        STANDARD: 5000

quota.limits 欄位中包含具備以下鍵/值組合的清單:

元素 說明
name (必填) 限制的名稱,在服務中不能重複。該名稱可以包含大小寫字母、數字和「-」(連字號字元),長度必須在 64 個字元以內。
metric (必填) 此限制適用的指標名稱。此名稱必須與指標名稱中指定的文字相符。如果指定的文字與指標名稱不相符,部署 OpenAPI 文件時就會發生錯誤。
unit (必填) 限制的單位。目前僅支援「1/min/{project}」,這代表該項限制是以「專案」為單位強制實行,且用量每分鐘重設一次。
(必填) 指標的用量限制。您必須將這個值指定為鍵/值組合,格式如下:
STANDARD: YOUR-LIMIT-FOR-THE-METRIC
您可以將 YOUR-LIMIT-FOR-THE-METRIC 替換為以指定單位 (目前只有「每分鐘」和「每項專案」) 計算的要求次數上限整數值,例如:
values:
  STANDARD: 5000

x-google-quota

x-google-quota 擴充功能用於 OpenAPI 的 paths 區段,可連結 API 方法與指標。配額限制不會套用至未定義 x-google-quota 的方法,例如:

x-google-quota:
  metricCosts:
    read-requests: 1

x-google-quota 擴充功能中包含下列項目:

元素 說明
metricCosts 使用者定義的鍵/值組合:"YOUR-METRIC-NAME": METRIC-COST
  • "YOUR-METRIC-NAME":"YOUR-METRIC-NAME" 的文字必須與已定義的指標名稱相符。
  • METRIC-COST: 定義各項要求費用的整數值。要求提出之後,相關聯的指標會按照指定的費用遞增。在同一項指標中,費用可讓方法以不同的速率使用配額。舉例來說,如果某項指標的配額限制是 1,000、費用為 1,則在超過限制之前,呼叫端應用程式每分鐘可以提出 1,000 次要求。如果同一項指標的費用為 2,則在超過限制之前,呼叫端應用程式每分鐘只能提出 500 次要求。

配額範例

以下範例說明如何為讀取要求數和寫入要求數新增指標與限制。

x-google-management:
  metrics:
    # Define a metric for read requests.
    - name: "read-requests"
      displayName: "Read requests"
      valueType: INT64
      metricKind: DELTA
    # Define a metric for write requests.
    - name: "write-requests"
      displayName: "Write requests"
      valueType: INT64
      metricKind: DELTA
  quota:
    limits:
      # Rate limit for read requests.
      - name: "read-requests-limit"
        metric: "read-requests"
        unit: "1/min/{project}"
        values:
          STANDARD: 5000
      # Rate limit for write requests.
      - name: "write-request-limit"
        metric: "write-requests"
        unit: "1/min/{project}"
        values:
          STANDARD: 5000

paths:
  "/echo":
    post:
      description: "Echo back a given message."
      operationId: "echo"
      produces:
      - "application/json"
      responses:
        200:
          description: "Echo"
          schema:
            $ref: "#/definitions/echoMessage"
      parameters:
      - description: "Message to echo"
        in: body
        name: message
        required: true
        schema:
          $ref: "#/definitions/echoMessage"
      x-google-quota:
        metricCosts:
          read-requests: 1
      security:
      - api_key: []

x-google-api-name

如果您的服務只有一個 API,則 API 名稱會與 Endpoints 服務名稱相同,而 Endpoints 會使用您在 OpenAPI 文件的 host 欄位中指定的名稱來當做服務名稱。如果您的服務含有多個 API,您可以將 x-google-api-name 擴充功能新增至 OpenAPI 文件,藉此指定各個 API 的名稱。x-google-api-name 擴充功能可讓您明確地為各個 API 命名,並為每個 API 建立獨立的版本管理機制。

舉例來說,針對含有 ProducerConsumer 這兩個 API 的 api.example.com 服務,您可以使用下列 OpenAPI 文件片段加以設定:

  • producer.yaml 中的 Producer API:

    swagger: 2.0
    host: api.example.com
    x-google-api-name: producer
    info:
      version: 1.0.3
    

  • consumer.yaml 中的 Consumer API:

    swagger: 2.0
    host: api.example.com
    x-google-api-name: consumer
    info:
      version: 1.1.0
    

您可以利用下列指令,同時部署這兩份 OpenAPI 文件:

gcloud endpoints services deploy producer.yaml consumer.yaml