Skip to content

Auth(mtls): _has_logged_mtls_warning masks distinct mTLS configuration errors #17697

Description

@nbayati

Determine this is the right repository

  • I determined this is the correct repository in which to report this bug.

Summary of the issue

Describe the bug

In google.auth.transport._mtls_helper.py, the global boolean flag _has_logged_mtls_warning is used to prevent log spam when mTLS auto-enablement fails. However, because it is a single global flag, it suppresses multiple distinct error conditions.

If a long-running application encounters one configuration error (e.g., file not found), the flag is set to True. If the user attempts to fix the configuration but introduces a different error (e.g., the JSON structure is invalid), the new error is silently swallowed for the lifetime of the process.

To Reproduce

  1. Create a Google API client with GOOGLE_API_CERTIFICATE_CONFIG pointing to a non-existent file.
  2. The client will log: WARNING: mTLS auto-enablement failed: Could not read/parse certificate file...
  3. Create the file at that path, but omit the required ['cert_configs']['workload'] JSON section.
  4. Create another Google API client in the same Python process.
  5. Expected behavior: A new warning should be logged stating the file is missing the required workload section.
  6. Actual behavior: No warning is logged. The client silently disables mTLS.

Root Cause & Context

This behavior was introduced in PR #17470 where the implementation used _LOGGER.warning combined with a custom global boolean _has_logged_mtls_warning.
Because the custom flag does not track which warning was logged, it permanently disables all future configuration warnings in the process after the first failure. Additionally, it never clears the cache upon a successful read, meaning transient errors will permanently disable warnings for the remainder of the process's lifetime.

Proposed Solution

We should drop the custom global _has_logged_mtls_warning state entirely and revert the log level back to _LOGGER.debug(...).

Reasoning:

  1. It restores the intended fallback behavior: Auto-enablement is designed to be a "best-effort" enhancement. If it fails, falling back to standard TLS silently keeps the application running.

  2. Users requiring strict mTLS are protected: If a user strictly requires mTLS, they should explicitly set GOOGLE_API_USE_CLIENT_CERTIFICATE="true". Doing so bypasses this auto-enablement fallback and hard-fails with a ClientCertError if the config is broken.

  3. Debuggability is preserved: If auto-enablement fails and the standard TLS fallback is subsequently rejected by a server requiring mTLS (e.g., returning a 401/403), the user can turn on debug logging to see exactly why their mTLS configuration was rejected.

  4. Removes custom state: Reverting to debug entirely eliminates the log spam risk, allowing us to safely remove the buggy global cache from this foundational library.

Metadata

Metadata

Assignees

No one assigned

    Labels

    type: bugError or flaw in code with unintended results or allowing sub-optimal usage patterns.

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions