Skip to content

Conversation

@agrawalradhika-cell
Copy link
Contributor

@agrawalradhika-cell agrawalradhika-cell commented Dec 15, 2025

This PR includes adding changes which are for -

nbayati and others added 2 commits December 9, 2025 14:52
This change introduces support for requesting certificate-bound access
tokens for Agent Identities on GKE and Cloud Run. The design doc:
[go/sdk-agent-identity](http://goto.google.com/sdk-agent-identity)
…als & Agent Identity workloads (#1841)

feat: Add retry logic when certificate mismatch for existing credentials
& Agent Identity workloads

This change introduces retry support when requests are created for
existing credentials and Agent Identities on GKE and Cloud Run
Workloads. When 401(Unauthorized) error is created, due to certificate
at time of configuration of mTLS channel being different from the
current certificate, a retry is added to the request by configuring the
mTLS channel with the current certificate.

---------

Signed-off-by: Radhika Agrawal <agrawalradhika@google.com>
Co-authored-by: nbayati <99771966+nbayati@users.noreply.github.com>
Co-authored-by: Andy Zhao <andyzhao@google.com>
@agrawalradhika-cell agrawalradhika-cell requested review from a team as code owners December 15, 2025 18:08
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @agrawalradhika-cell, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the security and resilience of Agent Identity authentication by introducing certificate-bound tokens and robust retry mechanisms for certificate management. It ensures that access tokens are securely tied to specific client certificates and that the system can dynamically adapt to certificate rotations without manual intervention, particularly for workloads on GKE and Cloud Run.

Highlights

  • Agent Identity Certificate Utilities: Introduced a new module, _agent_identity_utils.py, to centralize logic for handling Agent Identity certificates. This includes functions for parsing certificates, determining if a certificate is an Agent Identity type, calculating certificate fingerprints, and managing certificate file paths with retry mechanisms.
  • Certificate-Bound Token Support: Implemented support for certificate-bound tokens for Agent Identities. This enhances security by binding access tokens to specific client certificates, preventing token sharing. This is integrated into compute_engine, external_account, and identity_pool credentials.
  • Dynamic mTLS Channel Reconfiguration: Added retry logic to requests.py and urllib3.py transport layers. If an UNAUTHORIZED (401) response is received during an mTLS request and the client certificate has changed, the mTLS channel will attempt to reconfigure itself with the new certificate, improving resilience to certificate rotation.
  • New Environment Variables: Defined two new environment variables: GOOGLE_API_CERTIFICATE_CONFIG to specify the path to the certificate configuration file, and GOOGLE_API_PREVENT_AGENT_TOKEN_SHARING_FOR_GCP_SERVICES to allow users to opt-out of certificate-bound tokens.
  • Cryptography as Optional Dependency: The cryptography library, essential for certificate operations, has been moved to an optional dependency, allowing for more flexible installations.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

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 support for Agent Identity bound tokens, which enhances security by binding access tokens to the client's mTLS certificate. It adds a new utility module, _agent_identity_utils.py, for handling agent identity certificates. The changes also include retry logic in the requests and urllib3 transports to handle certificate rotation by reconfiguring the mTLS channel upon receiving a 401 Unauthorized response. My review focuses on improving maintainability and robustness. I've suggested refactoring repeated code in _agent_identity_utils.py into a decorator and improving error logging in the certificate polling logic. I've also pointed out the use of overly broad exception handling in the transport layers, which could mask bugs, and recommended using more specific exceptions.

self.configure_mtls_channel(
lambda: (call_cert_bytes, call_key_bytes)
)
except Exception as e:
Copy link
Contributor

Choose a reason for hiding this comment

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

high

Catching the base Exception class is too broad. It can mask unexpected errors and even catch system-exiting exceptions like KeyboardInterrupt. Since configure_mtls_channel is documented to raise google.auth.exceptions.MutualTLSChannelError on failure, it would be safer to catch that specific exception.

Suggested change
except Exception as e:
except exceptions.MutualTLSChannelError as e:

call_key_bytes,
)
)
except Exception as e:
Copy link
Contributor

Choose a reason for hiding this comment

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

high

Catching the base Exception class is too broad. It can mask unexpected errors and even catch system-exiting exceptions like KeyboardInterrupt. Since configure_mtls_channel is documented to raise google.auth.exceptions.MutualTLSChannelError on failure, it would be safer to catch that specific exception.

Suggested change
except Exception as e:
except exceptions.MutualTLSChannelError as e:

Comment on lines +100 to +110
except (IOError, ValueError, KeyError):
if not has_logged_warning:
_LOGGER.warning(
"Certificate config file not found at %s (from %s environment "
"variable). Retrying for up to %s seconds.",
cert_config_path,
environment_vars.GOOGLE_API_CERTIFICATE_CONFIG,
_TOTAL_TIMEOUT,
)
has_logged_warning = True
pass
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

The except (IOError, ValueError, KeyError): pass block is broad and silences all but the first error encountered during the polling loop. This can make debugging difficult. For instance, if the file is initially not found (IOError), a warning is logged. If on a subsequent attempt the file is found but is malformed (ValueError), this error will be silently ignored until the timeout. To improve debuggability, consider logging subsequent errors at a DEBUG level.

        except (IOError, ValueError, KeyError) as e:
            if not has_logged_warning:
                _LOGGER.warning(
                    "Certificate config file not found at %s (from %s environment "
                    "variable). Retrying for up to %s seconds.",
                    cert_config_path,
                    environment_vars.GOOGLE_API_CERTIFICATE_CONFIG,
                    _TOTAL_TIMEOUT,
                )
                has_logged_warning = True
            else:
                _LOGGER.debug("Polling for certificate failed again: %s", e)
            pass

Comment on lines +171 to +176
try:
from cryptography import x509

return x509.load_pem_x509_certificate(cert_bytes)
except ImportError as e:
raise ImportError(CRYPTOGRAPHY_NOT_FOUND_ERROR) from e
Copy link
Contributor

Choose a reason for hiding this comment

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

medium

To improve maintainability and reduce code duplication, the repeated try...except ImportError block for the cryptography dependency in parse_certificate, _is_agent_identity_certificate, and calculate_certificate_fingerprint could be refactored into a decorator.

For example, you could define a decorator like this:

import functools

def _require_cryptography(func):
    """A decorator to handle the optional cryptography dependency."""
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        try:
            return func(*args, **kwargs)
        except ImportError as e:
            raise ImportError(CRYPTOGRAPHY_NOT_FOUND_ERROR) from e
    return wrapper

And then apply it to the relevant functions:

@_require_cryptography
def parse_certificate(cert_bytes):
    from cryptography import x509
    return x509.load_pem_x509_certificate(cert_bytes)

@_require_cryptography
def _is_agent_identity_certificate(cert):
    # ... function body ...

@_require_cryptography
def calculate_certificate_fingerprint(cert):
    # ... function body ...

This would make the code cleaner and easier to maintain.

@agrawalradhika-cell agrawalradhika-cell changed the title Agent identity staging feat: [Agent identity staging to main] Adding Agent Identity bound token support and retry condition for when certificates mismatch for these Agent Identities Dec 15, 2025
@daniel-sanche daniel-sanche changed the title feat: [Agent identity staging to main] Adding Agent Identity bound token support and retry condition for when certificates mismatch for these Agent Identities feat: Adding Agent Identity bound token support and verification logic Dec 15, 2025
Copy link
Collaborator

@daniel-sanche daniel-sanche left a comment

Choose a reason for hiding this comment

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

LGTM

This PR is from a stanging branch, which was made up of individually approved PRs

@daniel-sanche daniel-sanche changed the title feat: Adding Agent Identity bound token support and verification logic feat: Adding Agent Identity bound token support and handling certificate mismatches with retries Dec 15, 2025
@daniel-sanche daniel-sanche merged commit b32c934 into main Dec 15, 2025
14 of 15 checks passed
@daniel-sanche daniel-sanche deleted the agent_identity_staging branch December 15, 2025 19:31
daniel-sanche added a commit that referenced this pull request Dec 15, 2025
PR created by the Librarian CLI to initialize a release. Merging this PR
will auto trigger a release.

Librarian Version: v0.7.0
Language Image:
us-central1-docker.pkg.dev/cloud-sdk-librarian-prod/images-prod/python-librarian-generator:latest
<details><summary>google-auth: 2.45.0</summary>

##
[2.45.0](v2.44.0...v2.45.0)
(2025-12-15)

### Features

* Adding Agent Identity bound token support and handling certificate
mismatches with retries (#1890)
([b32c934](b32c934e))

</details>
Sign up for free to 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