Skip to content

feat: Enable Bound Token for Agentic Identities - #13873

Open
macastelaz wants to merge 20 commits into
googleapis:agentic-identities-bound-tokenfrom
macastelaz:pr-13169-fixes
Open

feat: Enable Bound Token for Agentic Identities#13873
macastelaz wants to merge 20 commits into
googleapis:agentic-identities-bound-tokenfrom
macastelaz:pr-13169-fixes

Conversation

@macastelaz

@macastelazmacastelaz commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

This PR introduces a feature which enables the auth library to acquire bound access-tokens and bound id-tokens in Agentic Environments.

  1. We detect certs in default paths and check if they match the SPIFFE format for agents.

  2. If 1. is a yes then we call the MDS endpoint in a POST request with the certificate in the body.

Note this PR was based on #13169

@gemini-code-assistgemini-code-assistBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces Agent Identity token binding support for Cloud Run. It adds AgentIdentityUtils to resolve, load, and verify certificates and private keys, and updates ComputeEngineCredentials to request bound tokens via POST requests when a valid certificate chain is present. The review feedback suggests a cohesive improvement to implement a single-read pattern for certificate files. By reading the certificate chain once, caching it in CertInfo, and passing it to parseCertificate and getBoundTokenPayload, the implementation can avoid redundant disk I/O and prevent potential race conditions during certificate rotation.

@macastelazmacastelaz changed the title Pr 13169 fixesfeat: Enable Bound Token for Agentic IdentitiesJul 23, 2026
// Environment variables
static final String GOOGLE_API_CERTIFICATE_CONFIG = "GOOGLE_API_CERTIFICATE_CONFIG";
static final String GOOGLE_API_PREVENT_TOKEN_SHARING_FOR_GCP_SERVICES =
"GOOGLE_API_PREVENT_TOKEN_SHARING_FOR_GCP_SERVICES";

Copy link
Copy Markdown
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that based on googleapis/google-cloud-python#17698 (comment) this is not yet finalized

@macastelaz
macastelaz marked this pull request as ready for review July 24, 2026 03:21
@macastelaz
macastelaz requested review from a team as code ownersJuly 24, 2026 03:21
@lsirac
lsirac requested a review from nbayatiJuly 24, 2026 17:43
@macastelazmacastelaz reopened this Jul 28, 2026
@macastelaz
macastelaz requested a review from a team as a code ownerJuly 28, 2026 18:35
vvermanand others added 13 commits July 29, 2026 03:35
1. POST request to MDS with cert-chain
2. Cert-key matching
3. Included logic to consider the user's choice by looking at GOOGLE_API_USE_CLIENT_CERTIFICATE env variable
4. Bound ID tokens.
# Conflicts:
#	google-auth-library-java/oauth2_http/javatests/com/google/auth/oauth2/ComputeEngineCredentialsTest.java
#	google-auth-library-java/oauth2_http/javatests/com/google/auth/oauth2/MockMetadataServerTransport.java
…etry logic.
Nit fixes.
# Conflicts:
#	google-auth-library-java/oauth2_http/javatests/com/google/auth/oauth2/ComputeEngineCredentialsTest.java
# Conflicts:
#	google-auth-library-java/oauth2_http/java/com/google/auth/oauth2/ComputeEngineCredentials.java
…n binding
- Prevent 30-second polling delay and IOException on standard GCE/container environments when well-known credentials directory exists without certificate files unless mTLS is explicitly enabled.
- Fail fast on malformed certificate config JSON without retrying.
- Fix URI resource path decoding in AgentIdentityUtilsTest to prevent FileNotFoundException when workspace paths contain spaces.
- Copy matching private key in well-known fallback test to verify full key pair loading.
- Clean up static wellKnownDir state and temporary directories in ComputeEngineCredentialsTest.
- Correct opt-out environment variable value in test setup from 'true' to 'false'.
@InternalApi
public final class AgentIdentityUtils {

/** Javadoc. */

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove placeholder /** Javadoc. */ everywhere and replace with real docs where applicable

Comment on lines +118 to +129
static {
List<Long> intervals = new ArrayList<>();
for (int i = 0; i < FAST_POLL_CYCLES; i++) {
intervals.add(FAST_POLL_INTERVAL_MS);
}
long remainingTime = TOTAL_TIMEOUT_MS - (FAST_POLL_CYCLES * FAST_POLL_INTERVAL_MS);
int slowPollCycles = (int) (remainingTime / SLOW_POLL_INTERVAL_MS);
for (int i = 0; i < slowPollCycles; i++) {
intervals.add(SLOW_POLL_INTERVAL_MS);
}
POLLING_INTERVALS = Collections.unmodifiableList(intervals);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not do this directly in the polling loop?

static final String GOOGLE_API_CERTIFICATE_CONFIG = "GOOGLE_API_CERTIFICATE_CONFIG";

/** Javadoc. */
static final String GOOGLE_API_PREVENT_TOKEN_SHARING_FOR_GCP_SERVICES =

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

GOOGLE_API_PREVENT_AGENT_TOKEN_SHARING_FOR_GCP_SERVICES for the old one.

but I think they picked a new one.

* @throws IOException If an I/O error occurs while reading the files, or if the key-pair
* verification fails after retries.
*/
static CertInfo getAgentIdentityCertInfo() throws IOException {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we first check if GOOGLE_API_USE_CLIENT_CERTIFICATE=false? AIP 4114

private static final int CERT_KEY_MATCH_RETRIES = 3;

/** Javadoc. */
private static final long CERT_KEY_MATCH_RETRY_INTERVAL_MS = 100;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AIP-4118 recommends ~5s between attempts. What does Python do?

/** Javadoc. */
private static final List<Pattern> AGENT_IDENTITY_SPIFFE_PATTERNS =
ImmutableList.of(
Pattern.compile("^agents\\.global\\.org-\\d+\\.system\\.id\\.goog$"),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think in Python @nbayati went back and added non prod patterns. Let's add that + tests?

}

if (!matched) {
throw new IOException(

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this be an IOException or something else? perhaps a retryable GoogleAuthException?

transportFactory.transport.getRequest();
assertEquals("POST", transportFactory.transport.getRequestMethod());
String body = request.getContentAsString();
assertTrue(body.contains("certificate_chain"));

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's validate that it contains the full cert in these tests

"spiffe://agents.global.org-INVALID.system.id.goog/path";

private TestEnvironmentProvider envProvider;
private Path tempDir;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use @TempDir

* <p>To handle transient race conditions during certificate rotation on disk, this method employs
* a retry mechanism with backoff when reading the configuration and certificate files.
*
* @return A {@link CertInfo} object containing the loaded certificate and its path, or {@code

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

doesn't store the path?

Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

@macastelaz@lsirac@nbayati@vverman