驗證執行個體的識別資訊

應用程式傳送機密資訊至虛擬機器執行個體前,可透過 Google 簽署的執行個體識別憑證驗證虛擬機器的識別資訊。每個執行個體都有專屬的 JSON Web Token (JWT),提供包含執行個體的詳細資料以及 Google 的 RS256 簽名。 應用程式可藉由 Google 的公用 Oauth2 憑證驗證簽章,確認已連線的執行個體識別資訊。

只有在執行個體透過執行個體中繼資料提出要求時,Compute Engine 才會產生已簽署的執行個體憑證。執行個體只能存取自己的專屬憑證,無法存取其他執行個體的憑證。

您可能會想要在下列情境中驗證執行個體的識別資訊:

  • 當您初次啟動執行個體時,您的應用程式可能需要先確保連線的執行個體具備有效的識別資訊,然後才可傳送機密資訊至執行個體。
  • 當政策要求您將憑證儲存至 Compute Engine 環境以外的位置,而您需要將這些憑證定期傳送至執行個體以供暫時使用時,您的應用程式會在每次需要傳送憑證時確認執行個體的識別資訊。

Google 的執行個體驗證方法具有以下優勢:

  • Compute Engine 會在執行個體每次提出要求時產生專屬憑證,且每個憑證都會在一小時內過期。您可將應用程式設為僅接受一次執行個體的識別憑證,藉此降低未經授權的系統重複使用憑證的風險。
  • Google 的私密金鑰與公用 Oauth2 憑證會每天輪替,以減少這些簽名的潛在受攻擊面。
  • 經過簽署的中繼資料憑證採用 RFC 7519 開放業界標準與 OpenID Connect 1.0 識別層級,如此現有的工具與函式庫才能順暢地使用識別憑證。

事前準備

驗證執行個體的識別資訊

在某些情況下,您的應用程式必須先驗證在 Compute Engine 上執行之執行個體的識別資訊,才能傳送機密資料到執行個體。某種常見的案例情況是,有個在 Compute Engine 以外的位置執行的系統,稱為「Host1」,另外有個 Compute Engine 執行個體,稱為「VM1」。VM1 可透過下列程序連線至 Host1,並驗證這個執行個體的識別資訊:

  1. VM1 會透過您選擇的安全連線通訊協定 (例如 HTTPS),建立與 Host1 的安全連線。

  2. VM1 會向中繼資料伺服器要求專屬的識別憑證,並指定憑證的目標對象。在這個範例中,Host1 的目標對象值為 URI。向中繼資料伺服器提出的要求包含目標對象的 URI,如此 Host1 之後才可在憑證驗證步驟期間檢查這個值。

  3. Google 會產生 JWT 格式的新專屬執行個體識別憑證並提供給 VM1。憑證酬載包含執行個體的多項相關詳細資料,另外也包含目標對象 URI。如需完整的憑證內容說明,請參閱憑證內容

  4. VM1 會透過現有的安全連線傳送識別憑證至 Host1。

  5. Host1 會將識別憑證解碼,以取得憑證標頭與酬載值。

  6. Host1 會檢查目標對象值並依據公用 Google 憑證驗證憑證簽名,以確認憑證由 Google 簽署

  7. 如為有效憑證,Host1 會繼續傳送,並在完成後關閉連線。對於後續與 VM1 的任何連線,Host1 與任何其他系統應要求新憑證。

取得執行個體識別憑證

當虛擬機器執行個體收到提供相關識別憑證的要求時,執行個體會透過取得執行個體中繼資料的一般程序,向中繼資料伺服器要求憑證。 舉例來說,您可能會採用下列其中一種方法:

cURL

建立 curl 要求並在 audience 參數中加入值。 您也可以加入參數 format,以指定是否要在酬載中加入專案和執行個體詳細資料。如果使用格式 full,則可以加入 licenses 參數,以指定是否要在酬載中包含授權碼。

$ curl -H "Metadata-Flavor: Google" \
'http://metadata/computeMetadata/v1/instance/service-accounts/default/identity?audience=[AUDIENCE]&format=[FORMAT]&licenses=[LICENSES]'

其中:

  • [AUDIENCE] 是執行個體以及驗證執行個體識別資訊的系統雙方共同協議的專屬 URI。舉例來說,目標對象可以是兩個系統之間的連線網址。
  • [FORMAT] 是選用參數,指定專案和執行個體詳細資料是否包含在酬載中。指定 full 以在酬載中引入或 standard 省略這項資訊。預設值為 standard。如需完整的憑證格式詳細資料,請參閱識別憑證格式相關說明。
  • [LICENSES] 是選用參數,用於指定是否要在酬載中包含與此執行個體相關聯的映像檔的授權碼。指定 TRUE 可在酬載中包含這項資訊,指定 FALSE 則可從酬載中省略這項資訊。預設值為 FALSE。除非 format 是為 full,否則將沒有效果。

中繼資料伺服器會透過使用 RS256 演算法簽署的 JSON Web Token 回應這項要求。 憑證的酬載中會包含 Google 簽名及其他資訊。您可以將這個憑證傳送至其他系統與應用程式,讓這些系統與應用程式驗證憑證,並確認執行個體的識別資訊。

Python

您可以使用 Python requests 函式庫中的方法,從執行個體向中繼資料伺服器送出一個簡單的請求。以下範例會要求並列印執行個體識別憑證,該憑證專屬於提出這項要求的執行個體。

import requests

AUDIENCE_URL = 'http://www.example.com'
METADATA_HEADERS = {'Metadata-Flavor': 'Google'}
FORMAT = 'full'
LICENSES = 'TRUE'

# Construct a URL with the audience and format.
url = 'http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/identity?audience={}&format={}&licenses={}'
url = url.format(AUDIENCE_URL, FORMAT, LICENSES)

# Request a token from the metadata server.
r = requests.get(url, headers=METADATA_HEADERS)

# Extract the token from the response.
token = r.text

print(token)

中繼資料伺服器會透過使用 RS256 演算法簽署的 JSON Web Token 回應這項要求。 憑證的酬載中會包含 Google 簽名及其他資訊。您可以將這個憑證傳送至其他系統與應用程式,讓這些系統與應用程式驗證憑證,並確認執行個體的識別資訊。

驗證憑證

應用程式收到來自 Compute Engine 執行個體的識別憑證後,就會透過下列程序驗證憑證。

  1. 接收來自虛擬機器執行個體的憑證,使用 RS256 JWT 解碼器將其解碼後,讀取標頭的內容以取得 kid 資料值。

  2. 依據公用 Google 憑證檢查憑證,確認憑證經過簽署。 每個公開憑證中都有一個kid值,與符記標頭中的kid值相對應。

  3. 如為有效憑證,請比較酬載內容與預期值。如果符記酬載含有關於執行個體及專案的詳細資訊,則您的應用程式可以檢查instance_idproject_id以及zone資料值。這些是全域唯一的數值組合,可確認應用程式正在跟目標專案中的正確執行個體通訊。

您可以自行選擇任何工具將憑證解碼並驗證憑證,但一般的做法是使用所選語言的函式庫。舉例來說,您可以使用 Google OAuth 2.0 Python 函式庫中的verify_token方法。verify_token方法會將kid資料值與適當的憑證進行比對,驗證簽章,檢查目標裝置發出的聲明,並回傳符記酬載內容。

# Import libraries for token verification
import google.auth.transport.requests
from google.oauth2 import id_token

# Receive token from VM over an SSL connection
token = …
…

# Verify token signature and store the token payload
request = google.auth.transport.requests.Request()
payload = id_token.verify_token(token, request=request, audience=audience)
…

在應用程式驗證憑證及相關內容後,就可透過安全連線繼續與這個執行個體連線,並在完成後關閉連線。如要再次連線,請向執行個體要求新的憑證,然後重新驗證執行個體的識別資訊。

憑證內容

執行個體識別憑證可分為三大部分:

標頭中含有kid資料值,以識別哪些公開 Oauth2 憑證必需用來驗證簽章,標頭中包含alg值,以確認由 RS256 演算法所產生的簽章。

{
  "alg": "RS256",
  "kid": "511a3e85d2452aee960ed557e2666a8c5cedd8ae",
}

酬載

酬載包含aud目標對象的聲明。如果執行個體在要求憑證時指定了format=full,則所發出請求的符記酬載中,也會包含虛擬機器執行個體及其專案的聲明。 在請求一完整格式的符記時,指定licenses=TRUE將會包含與該執行個體相關聯的授權聲明。

{
   "iss": "[TOKEN_ISSUER]",
   "iat": [ISSUED_TIME],
   "exp": [EXPIRED_TIME],
   "aud": "[AUDIENCE]",
   "sub": "[SUBJECT]",
   "azp": "[AUTHORIZED_PARTY]",
   "google": {
    "compute_engine": {
      "project_id": "[PROJECT_ID]",
      "project_number": [PROJECT_NUMBER],
      "zone": "[ZONE]",
      "instance_id": [INSTANCE_ID],
      "instance_name": "[INSTANCE_NAME]",
      "instance_creation_timestamp": [CREATION_TIMESTAMP],
      "license_id": [
        "[LICENSE_1]",
          ...
        "[LICENSE_N]"
      ]
    }
  }
}

其中:

  • [TOKEN_ISSUER] 是可識別憑證核發者的 URL。對於 Compute Engine,此值為https://accounts.google.com
  • [ISSUED_TIME] 是表示憑證核發時間的 Unix 時間戳記。 每當執行個體向中繼資料伺服器要求憑證時,這個值就會更新。
  • [EXPIRED_TIME] 是表示憑證到期時間的 Unix 時間戳記。
  • [AUDIENCE] 是執行個體以及驗證執行個體識別資訊的系統雙方共同協議的專屬 URI。舉例來說,目標對象可以是兩個系統之間的連線網址。
  • [SUBJECT] 代表憑證的主旨,也就是與執行個體相關聯的服務帳戶專屬 ID。
  • [AUTHORIZED_PARTY] 代表核發 ID 憑證的目標對象,是您與執行個體連結的服務帳戶專屬 ID。
  • [PROJECT_ID] 是您建立執行個體的專案 ID。
  • [PROJECT_NUMBER] 是您建立執行個體之專案的專屬編號。
  • [ZONE] 是執行個體所在的區域。
  • [INSTANCE_ID] 是這個憑證所屬執行個體的專屬 ID。此 ID 必須是唯一值,不得重複使用。
  • [INSTANCE_NAME] 是這個憑證所屬執行個體的名稱。多個執行個體會重複使用此名稱一段時間,因此請使用instance_id資料值來識別執行個體的獨特ID。
  • [CREATION_TIMESTAMP]是表示執行個體建立時間的 Unix 時間戳記。
  • [LICENSE_1][LICENSE_N] 是與此執行個體相關聯的映像檔的授權碼

您的酬載可能類似以下範例:

{
  "iss": "https://accounts.google.com",
  "iat": 1496953245,
  "exp": 1496956845,
  "aud": "https://www.example.com",
  "sub": "107517467455664443765",
  "azp": "107517467455664443765",
  "google": {
    "compute_engine": {
      "project_id": "my-project",
      "project_number": 739419398126,
      "zone": "us-west1-a",
      "instance_id": "152986662232938449",
      "instance_name": "example",
      "instance_creation_timestamp": 1496952205,
      "license_id": [
        "1000204"
      ]
    }
  }
}

簽章

Google 會以 base64url 將標頭與酬載編碼並連結兩值,以產生簽章。您可以透過公用 Oauth2 憑證檢查這個值以驗證憑證。

後續步驟

本頁內容對您是否有任何幫助?請提供意見:

傳送您對下列選項的寶貴意見...

這個網頁
Compute Engine 說明文件