-
Notifications
You must be signed in to change notification settings - Fork 935
Oauth/OIDC Azure IMDS metadata based authentication for Schema Registry #2058
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
base: master
Are you sure you want to change the base?
Conversation
to be common for the sync and async clients
🎉 All Contributor License Agreements have been signed. Ready to merge. |
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.
Pull Request Overview
This PR implements OAuth/OIDC metadata-based authentication with Azure IMDS (Instance Metadata Service) for Schema Registry clients. The implementation refactors the authentication system to make it more maintainable and adds Azure IMDS support for both synchronous and asynchronous clients.
Key changes:
- Adds new Azure IMDS authentication method supporting metadata-based token retrieval
- Refactors authentication code into reusable builder patterns to reduce duplication
- Implements comprehensive validation for Azure IMDS configuration parameters
Reviewed Changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 4 comments.
Show a summary per file
File | Description |
---|---|
src/confluent_kafka/schema_registry/common/_oauthbearer.py |
New module containing abstract base classes and builders for OAuth bearer authentication |
src/confluent_kafka/schema_registry/_sync/schema_registry_client.py |
Refactored sync client with new authentication architecture and Azure IMDS support |
src/confluent_kafka/schema_registry/_async/schema_registry_client.py |
Refactored async client with new authentication architecture and Azure IMDS support |
tests/schema_registry/_sync/test_config.py |
Added comprehensive tests for Azure IMDS configuration validation |
tests/schema_registry/_async/test_config.py |
Added comprehensive tests for Azure IMDS configuration validation |
tests/schema_registry/_sync/test_bearer_field_provider.py |
Updated tests for refactored OAuth client structure |
tests/schema_registry/_async/test_bearer_field_provider.py |
Updated tests for refactored OAuth client structure |
examples/oauth_schema_registry.py |
Added example demonstrating Azure IMDS authentication |
examples/oauth_oidc_ccloud_azure_imds_producer.py |
New example showing Azure IMDS OAuth for Kafka producer |
Comments suppressed due to low confidence (1)
examples/oauth_oidc_ccloud_azure_imds_producer.py:1
- Invalid Azure IMDS query string with empty parameter values. The query string contains empty values for required parameters (
resource=
,api-version=
,client_id=
) which will cause authentication failures. These should either be removed or contain valid placeholder values.
#!/usr/bin/env python
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
expiry_window = self.token_object['expires_in'] * self.token_expiry_threshold | ||
return self.token_object['expires_on'] < time.time() + expiry_window |
Copilot
AI
Sep 19, 2025
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.
Inconsistent expiry field usage in Azure IMDS token expiration check. The method uses expires_in
to calculate expiry_window but then compares against expires_on
. According to Azure IMDS documentation, tokens have expires_on
(absolute timestamp) but may not have expires_in
(relative seconds). Should use only expires_on
for comparison or handle both fields appropriately.
expiry_window = self.token_object['expires_in'] * self.token_expiry_threshold | |
return self.token_object['expires_on'] < time.time() + expiry_window | |
# Azure IMDS returns 'expires_on' as an absolute timestamp (string or int). | |
expires_on = int(self.token_object['expires_on']) | |
buffer_seconds = 300 # 5 minutes buffer before actual expiry | |
return expires_on < time.time() + buffer_seconds |
Copilot uses AI. Check for mistakes.
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.
expires_in
is available too from documentation, but will check when testing on an instance.
expiry_window = int(self.token_object['expires_in']) * self.token_expiry_threshold | ||
return int(self.token_object['expires_on']) < time.time() + expiry_window |
Copilot
AI
Sep 19, 2025
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.
Inconsistent expiry field usage in Azure IMDS token expiration check. The method uses expires_in
to calculate expiry_window but then compares against expires_on
. According to Azure IMDS documentation, tokens have expires_on
(absolute timestamp) but may not have expires_in
(relative seconds). Should use only expires_on
for comparison or handle both fields appropriately.
expiry_window = int(self.token_object['expires_in']) * self.token_expiry_threshold | |
return int(self.token_object['expires_on']) < time.time() + expiry_window | |
# Use only 'expires_on' (absolute timestamp) for expiry check, as per Azure IMDS docs. | |
expires_on = int(self.token_object['expires_on']) | |
now = time.time() | |
# If 'expires_in' is present, use it to calculate a threshold window; else use a default buffer (e.g., 5 min) | |
if 'expires_in' in self.token_object: | |
total_lifetime = int(self.token_object['expires_in']) | |
expiry_buffer = total_lifetime * (1 - self.token_expiry_threshold) | |
else: | |
expiry_buffer = 300 # 5 minutes default buffer | |
return expires_on < now + expiry_buffer |
Copilot uses AI. Check for mistakes.
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.
same
self.token_object = self.client.get(self.token_endpoint, headers=[ | ||
('Metadata', 'true') | ||
]).json() |
Copilot
AI
Sep 19, 2025
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.
Missing error handling for Azure IMDS token requests. The method should handle HTTP errors, network timeouts, and invalid JSON responses that could occur when accessing the metadata service, and provide meaningful error messages for debugging authentication failures.
self.token_object = self.client.get(self.token_endpoint, headers=[ | |
('Metadata', 'true') | |
]).json() | |
try: | |
response = self.client.get(self.token_endpoint, headers=[('Metadata', 'true')], timeout=10.0) | |
response.raise_for_status() | |
try: | |
self.token_object = response.json() | |
except Exception as e: | |
raise OAuthTokenError(f"Failed to decode JSON from Azure IMDS token response: {e}") from e | |
except httpx.HTTPStatusError as e: | |
raise OAuthTokenError(f"HTTP error when requesting Azure IMDS token: {e.response.status_code} {e.response.text}") from e | |
except httpx.RequestError as e: | |
raise OAuthTokenError(f"Network error when requesting Azure IMDS token: {e}") from e | |
except Exception as e: | |
raise OAuthTokenError(f"Unexpected error when requesting Azure IMDS token: {e}") from e |
Copilot uses AI. Check for mistakes.
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.
Exceptions and retries are handled in superclass' generate_access_token
self.token_object = await self.client.get(self.token_endpoint, headers=[ | ||
('Metadata', 'true') | ||
]).json() |
Copilot
AI
Sep 19, 2025
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.
Missing error handling for Azure IMDS token requests. The method should handle HTTP errors, network timeouts, and invalid JSON responses that could occur when accessing the metadata service, and provide meaningful error messages for debugging authentication failures.
self.token_object = await self.client.get(self.token_endpoint, headers=[ | |
('Metadata', 'true') | |
]).json() | |
try: | |
response = await self.client.get( | |
self.token_endpoint, | |
headers={'Metadata': 'true'}, | |
timeout=5.0 | |
) | |
if response.status_code != 200: | |
raise OAuthTokenError( | |
f"Failed to fetch Azure IMDS token: HTTP {response.status_code} - {response.text}" | |
) | |
try: | |
self.token_object = response.json() | |
except json.JSONDecodeError as e: | |
raise OAuthTokenError( | |
f"Failed to decode Azure IMDS token response as JSON: {e} - Response: {response.text}" | |
) | |
except (httpx.RequestError, httpx.TimeoutException) as e: | |
raise OAuthTokenError( | |
f"Network error while fetching Azure IMDS token: {e}" | |
) |
Copilot uses AI. Check for mistakes.
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.
Exceptions and retries are handled in superclass' generate_access_token
This comment has been minimized.
This comment has been minimized.
ccc80a6
to
f6f4851
Compare
This comment has been minimized.
This comment has been minimized.
1 similar comment
This comment has been minimized.
This comment has been minimized.
f6f4851
to
6df4cce
Compare
807345b
to
ab09f28
Compare
What
Implement metadata based authentication with Azure IMDS returning an OAuth/OIDC token.
Implementation is for both the synchronous and asynchronous client.
Before implementing the feature did a refactor to make it more maintainable to add new authentication methods.
Checklist
References
JIRA:
Test & Review
Run the normal test suite.
An example in present for how to use the SR authentication methods and the Kafka one as well.
Open questions / Follow-ups