1818import hashlib
1919import os
2020import re
21+ import time
2122
22- from google .auth import _exponential_backoff
2323from google .auth import environment_vars
2424from google .auth import exceptions
2525
@@ -51,11 +51,10 @@ def get_agent_identity_certificate_path():
5151 if not cert_config_path :
5252 return None
5353
54- # Use exponential backoff to retry loading the certificate config file.
55- # This is to handle the race condition where the env var is set before the file exists.
56- backoff = _exponential_backoff .ExponentialBackoff (total_attempts = 5 )
57-
58- for _ in backoff :
54+ # Poll for the config file and the certificate file to be available.
55+ # Phase 1: Poll rapidly for 5 seconds (50 * 0.1s).
56+ # Phase 2: Slow down polling for the next 25 seconds (50 * 0.5s).
57+ for i in range (100 ):
5958 if os .path .exists (cert_config_path ):
6059 with open (cert_config_path , "r" ) as f :
6160 cert_config = json .load (f )
@@ -66,20 +65,41 @@ def get_agent_identity_certificate_path():
6665 )
6766 if cert_path and os .path .exists (cert_path ):
6867 return cert_path
68+ if i < 50 :
69+ time .sleep (0.1 )
70+ else :
71+ time .sleep (0.5 )
6972
7073 raise exceptions .RefreshError (
71- "Certificate config or certificate file not found after multiple retries."
74+ "Certificate config or certificate file not found after multiple retries. "
75+ f"If you are using Agent Engine, you can export "
76+ f"{ environment_vars .GOOGLE_API_PREVENT_AGENT_TOKEN_SHARING_FOR_GCP_SERVICES } to false to "
77+ "disable cert bound tokens to fall back to unbound tokens."
7278 )
7379
7480
75- def _is_agent_identity_certificate (cert_bytes ):
81+ def parse_certificate (cert_bytes ):
82+ """Parses a PEM-encoded certificate.
83+
84+ Args:
85+ cert_bytes (bytes): The PEM-encoded certificate bytes.
86+
87+ Returns:
88+ cryptography.x509.Certificate: The parsed certificate object.
89+ """
90+ from cryptography import x509
91+
92+ return x509 .load_pem_x509_certificate (cert_bytes )
93+
94+
95+ def _is_agent_identity_certificate (cert ):
7696 """Checks if a certificate is an Agent Identity certificate.
7797
7898 This is determined by checking the Subject Alternative Name (SAN) for a
7999 SPIFFE ID with a trust domain matching Agent Identity patterns.
80100
81101 Args:
82- cert_bytes (bytes ): The PEM-encoded certificate bytes .
102+ cert (cryptography.x509.Certificate ): The parsed certificate object .
83103
84104 Returns:
85105 bool: True if the certificate is an Agent Identity certificate,
@@ -88,7 +108,6 @@ def _is_agent_identity_certificate(cert_bytes):
88108 from cryptography import x509
89109 from cryptography .x509 .oid import ExtensionOID
90110
91- cert = x509 .load_pem_x509_certificate (cert_bytes )
92111 try :
93112 ext = cert .extensions .get_extension_for_oid (
94113 ExtensionOID .SUBJECT_ALTERNATIVE_NAME
@@ -107,37 +126,39 @@ def _is_agent_identity_certificate(cert_bytes):
107126 return False
108127
109128
110- def calculate_certificate_fingerprint (cert_bytes ):
129+ def calculate_certificate_fingerprint (cert ):
111130 """Calculates the base64-encoded SHA256 hash of a DER-encoded certificate.
112131
113132 Args:
114- cert_bytes (bytes ): The PEM-encoded certificate bytes .
133+ cert (cryptography.x509.Certificate ): The parsed certificate object .
115134
116135 Returns:
117136 str: The base64-encoded SHA256 fingerprint.
118137 """
119- from cryptography import x509
120138 from cryptography .hazmat .primitives import serialization
121139
122- cert = x509 .load_pem_x509_certificate (cert_bytes )
123140 der_cert = cert .public_bytes (serialization .Encoding .DER )
124141 fingerprint = hashlib .sha256 (der_cert ).digest ()
125- return base64 .b64encode (fingerprint ).decode ("utf-8" )
142+ return base64 .urlsafe_b64encode (fingerprint ). rstrip ( b"=" ).decode ("utf-8" )
126143
127144
128- def should_request_bound_token (cert_bytes ):
145+ def should_request_bound_token (cert ):
129146 """Determines if a bound token should be requested.
130147
131148 This is based on the GOOGLE_API_PREVENT_AGENT_TOKEN_SHARING_FOR_GCP_SERVICES
132149 environment variable and whether the certificate is an agent identity cert.
133150
151+ Args:
152+ cert (cryptography.x509.Certificate): The parsed certificate object.
153+
134154 Returns:
135155 bool: True if a bound token should be requested, False otherwise.
136156 """
137- is_agent_cert = _is_agent_identity_certificate (cert_bytes )
157+ is_agent_cert = _is_agent_identity_certificate (cert )
138158 is_opted_in = (
139159 os .environ .get (
140- "GOOGLE_API_PREVENT_AGENT_TOKEN_SHARING_FOR_GCP_SERVICES" , "true"
160+ environment_vars .GOOGLE_API_PREVENT_AGENT_TOKEN_SHARING_FOR_GCP_SERVICES ,
161+ "true" ,
141162 ).lower ()
142163 == "true"
143164 )
0 commit comments