Repository navigation
feat(auth): support bound access and ID tokens for GKE - #18594
Conversation
…Cloud Run (#17698) This PR adds the following: * Switch the MDS token acquisition from a GET to a POST request when the agentic cert is detected. * Add `get_agent_identity_certificate_and_bytes()` utility to read the raw certificate bytes alongside the parsed cert. * Update `_metadata.get_service_account_token()` (for access tokens) and `IDTokenCredentials.refresh()` (for ID tokens) to send a POST request with the `certificate_chain` payload instead of a GET request when bound tokens are supported. * Update `_metadata.get()` helper to support `method` and `body` params. * Add and update unit tests to verify the new POST request flows. ---- design: go/sdk-mds-bound-token id token verification: - test script: paste/4514812804595712 - log results: paste/6316867684794368 Note: 1. This PR relies on the existing pattern of locating the certificates using the path provided by the config file available at GOOGLE_API_CERTIFICATE_CONFIG. It does not currently fallback on checking the well known location if the env var is not set, which would limit the scope to CR, as GKE and GCE don't set this env var. 2. It uses the same condition to decide if a bound token should be requested for both access token and id token. We might decide to add a separate env var to opt out. 3. it still uses the existing `GOOGLE_API_PREVENT_AGENT_TOKEN_SHARING_FOR_GCP_SERVICES` flag to opt out. We might update it and add a new env var, but will keep the old one for backward compatibility.
This PR enables bound access tokens, bound ID tokens, and default mTLS certificate discovery for Agent Identity workloads on GKE, and adds per-request control for ID token binding: * Fall back to the well-known GKE workload credential bundle (`/var/run/secrets/workload-spiffe-credentials/x509.credential-bundle.private-key.pem`) in `_agent_identity_utils.get_agent_identity_certificate_path()`, `_mtls_helper._get_workload_cert_and_key()`, `_mtls_helper.check_use_client_cert()`, and `mtls.has_default_client_cert_source()` when no explicit or default certificate config file is present. * Add an optional `bind_id_token` parameter (`True`, `False`, or `None`) to `compute_engine.IDTokenCredentials`, `fetch_id_token_credentials()`, and `fetch_id_token()` (sync and async) so callers can explicitly opt in or out of binding metadata server ID tokens per request. * Scope default bound ID tokens to GKE by keeping ID tokens unbound when `GOOGLE_API_CERTIFICATE_CONFIG` is set (unless `bind_id_token=True`), while continuing to bind access tokens by default on both Cloud Run and GKE. * Add and update unit tests for GKE credential bundle fallback, `bind_id_token` options, and the `GOOGLE_API_CERTIFICATE_CONFIG` default gate. ---- Note: 1. GKE mounts a single combined PEM file (`x509.credential-bundle.private-key.pem`) at `/var/run/secrets/workload-spiffe-credentials/` without setting `GOOGLE_API_CERTIFICATE_CONFIG`. With this fallback, GKE Agent Identity workloads automatically use bound access tokens and bound ID tokens by default when the file is present. 2. On Cloud Run (where `GOOGLE_API_CERTIFICATE_CONFIG` is set), default ID token requests (`bind_id_token=None`) temporarily remain unbound so existing callers do not receive bound ID tokens. Callers on Cloud Run can pass `bind_id_token=True` to request bound ID tokens now, and a follow-up PR will remove this temporary gate to enable bound ID tokens by default on Cloud Run as well. design: go/sdk-mds-bound-token
There was a problem hiding this comment.
Code Review
This pull request introduces support for certificate-bound tokens using GKE workload credential bundles and Cloud Run mTLS endpoints, transitioning to the new GOOGLE_API_ENABLE_RUNTIME_BOUND_TOKEN environment variable. It refactors certificate parsing to handle chains and combined bundles, and adds options to control ID token binding. The review feedback suggests minor code improvements, such as passing the already-cleaned cert_bytes instead of raw_bytes to parse_certificate to avoid redundant parsing, and explicitly importing _mtls_helper in sessions.py to avoid relying on implicit package attribute binding.
|
|
||
| cert_bytes = b"\n".join(block.strip() for block in cert_blocks) + b"\n" | ||
| try: | ||
| return parse_certificate(raw_bytes), cert_bytes |
There was a problem hiding this comment.
Pass cert_bytes instead of raw_bytes to parse_certificate. Since cert_bytes has already been cleaned of non-certificate blocks (like private keys or bag attributes) and validated, parsing it directly is safer and avoids redundant regex parsing inside parse_certificate.
| return parse_certificate(raw_bytes), cert_bytes | |
| return parse_certificate(cert_bytes), cert_bytes |
There was a problem hiding this comment.
Rejecting the suggestion. Keeping raw_bytes here is intentional: cert_bytes is built from regex matches of complete PEM blocks and strips out any trailing block missing an END marker, so passing raw_bytes is required for parse_certificate to detect truncated certificate chains.
| import time | ||
| import urllib.parse | ||
| import warnings | ||
| from contextlib import asynccontextmanager |
There was a problem hiding this comment.
Explicitly import _mtls_helper from google.auth.transport instead of relying on implicit package attribute binding via google.auth.transport._mtls_helper.
| from contextlib import asynccontextmanager | |
| from google.auth.transport import _mtls_helper | |
| from contextlib import asynccontextmanager |
There was a problem hiding this comment.
False positive: google.auth.transport._mtls_helper is already explicitly imported on line 27, so this does not rely on implicit package attribute binding.
| is_mtls_endpoint = ( | ||
| google.auth.transport._mtls_helper.is_mtls_endpoint(url) | ||
| ) |
There was a problem hiding this comment.
Rejecting the suggestion: Keeping google.auth.transport._mtls_helper to match the existing import on line 27 and usage on line 304.
🤖 I have created a release *beep* *boop* --- ## [2.61.0](google-auth-v2.60.0...google-auth-v2.61.0) (2026-10-07) ### Features * **auth:** support bound access and ID tokens for GKE ([#18594](#18594)) ([9f5fd7b](9f5fd7b)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). Co-authored-by: release-please[bot] <55107282+release-please[bot]@users.noreply.github.com>
The feature branch contains code that has already been reviewed and approved in two previous RPs. This PR merges the changes to main for a release.
Note: the branch name says cr-bound-id-token because we're reusing a feature branch that was initially for CR, but now the change is going out for GKE first.
b/545779266