-
Notifications
You must be signed in to change notification settings - Fork 346
feat: Adding Agent Identity bound token support and handling certificate mismatches with retries #1890
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
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>
Summary of ChangesHello @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
Using Gemini Code AssistThe 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
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 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
|
There was a problem hiding this 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: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
| except Exception as e: | |
| except exceptions.MutualTLSChannelError as e: |
| call_key_bytes, | ||
| ) | ||
| ) | ||
| except Exception as e: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
| except Exception as e: | |
| except exceptions.MutualTLSChannelError as e: |
| 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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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| 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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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 wrapperAnd 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.
daniel-sanche
left a comment
There was a problem hiding this 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
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>
This PR includes adding changes which are for -