Skip to content

fix(mysql): require TLS for SPIFFE users (#5929) - #6059

Merged
renecannao merged 1 commit into
v3.0from
fix/5929-spiffe-requires-tls-v3.0
Aug 14, 2026
Merged

fix(mysql): require TLS for SPIFFE users (#5929)#6059
renecannao merged 1 commit into
v3.0from
fix/5929-spiffe-requires-tls-v3.0

Conversation

@renecannao

@renecannao renecannao commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Force the runtime MySQL use_ssl flag when the final retained user attributes contain spiffe_id.
  • Preserve existing attribute validation and leave rejected attributes at the supplied TLS setting.
  • Add real authentication-store coverage for initial, retained, changed, and removed SPIFFE attributes.

Root cause

SPIFFE identity verification requires the client certificate SAN, but the authentication runtime could retain spiffe_id while accepting use_ssl=0.

Validation

  • PROXYSQL31=1 make build_lib -j"$(nproc)"
  • make -C test/tap/tests/unit auth_unit-t
  • test/tap/tests/unit/auth_unit-t (69 assertions)
  • git diff --check origin/v3.0..HEAD

Fixes #5929


Summary by cubic

Enforces TLS for MySQL frontend users with SPIFFE identities. Previously the runtime could retain a spiffe_id while accepting use_ssl=0; now use_ssl is forced to true when retained attributes include spiffe_id, preventing connections without certificate SAN verification.

  • Sets ad->use_ssl via an effective_use_ssl that becomes true when valid JSON attributes contain spiffe_id; otherwise preserves the supplied flag. Attribute validation is unchanged; invalid JSON or unknown keys leave TLS as provided. Retained valid spiffe_id continues to require TLS across updates.
  • Adds unit tests for initial add, retained, changed, and removed SPIFFE attributes; test plan increases from 60 to 69.

Operational impact

  • SPIFFE users must connect over TLS with a client certificate that includes the SPIFFE ID in SAN. Update client/proxy configs as needed.
  • No change for users without a spiffe_id or with invalid attributes.

Written for commit deb0722. Summary will update on new commits.

Review in cubic

Summary by CodeRabbit

  • New Features

    • Accounts with valid SPIFFE identities now automatically require TLS connections.
    • TLS requirements remain consistent when SPIFFE-enabled accounts are updated.
    • Changes to account attributes correctly update TLS enforcement.
  • Bug Fixes

    • Invalid or non-SPIFFE attributes no longer incorrectly alter TLS requirements.
    • Case variations in recognized attributes are handled consistently.

@coderabbitai

coderabbitai Bot commented Aug 13, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 976cc4a8-ca42-4a6c-977b-21178e461cbe

📥 Commits

Reviewing files that changed from the base of the PR and between 57dc075 and deb0722.

📒 Files selected for processing (2)
  • lib/MySQL_Authentication.cpp
  • test/tap/tests/unit/auth_unit-t.cpp
📜 Recent review details
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{cpp,h,hpp}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{cpp,h,hpp}: Class names must use PascalCase with protocol prefixes such as MySQL_, PgSQL_, and ProxySQL_.
Member variables must use snake_case.
Constants and macros must use UPPER_SNAKE_CASE.
Use C++17, and gate conditional code with #ifdef PROXYSQL31, #ifdef PROXYSQL40, #ifdef PROXYSQLFFTO, #ifdef PROXYSQLTSDB, and #ifdef PROXYSQLCLICKHOUSE; PROXYSQLGENAI must not guard core code outside plugins/genai/.
Consider performance implications when changing hot paths or other performance-critical code.
Use RAII for resource management and jemalloc for allocation.
Use pthread mutexes for synchronization and std::atomic<> for counters.

Files:

  • lib/MySQL_Authentication.cpp
  • test/tap/tests/unit/auth_unit-t.cpp
test/tap/tests/**/*.cpp

📄 CodeRabbit inference engine (CLAUDE.md)

test/tap/tests/**/*.cpp: Test files in test/tap/tests/ must follow the naming pattern test_*.cpp or *-t.cpp.
To add a new TAP test, add the <testname>-t.cpp file and register it in test/tap/tests/Makefile/groups.json; no special Makefile target is needed because make <testname>-t is generated by pattern rule.

Files:

  • test/tap/tests/unit/auth_unit-t.cpp
test/tap/tests/unit/**/*.cpp

📄 CodeRabbit inference engine (CLAUDE.md)

Unit tests in test/tap/tests/unit/ must use test_globals.h and test_init.h with the custom unit-test harness.

Files:

  • test/tap/tests/unit/auth_unit-t.cpp
🧠 Learnings (7)
📓 Common learnings
Learnt from: Snehil-Shah
Repo: sysown/proxysql PR: 6039
File: lib/PgSQL_Monitor.cpp:1273-1276
Timestamp: 2026-08-11T20:53:03.724Z
Learning: In the ProxySQL codebase, release builds retain assertions. `assert(0)` is an established pattern that exits the process, including in `lib/PgSQL_Monitor.cpp`.
Learnt from: renecannao
Repo: sysown/proxysql PR: 6033
File: docs/superpowers/plans/2026-08-11-ed25519-authentication.md:469-469
Timestamp: 2026-08-11T12:56:13.170Z
Learning: In `docs/superpowers/plans/2026-08-11-ed25519-authentication.md`, the historical-artifact notice states that embedded expected outputs are plan-time values. Review-driven changes can modify the MariaDB Ed25519 implementation and TAP assertion counts after the plan is written. The shipped implementation and tests are authoritative, so reviewers must not require retroactive synchronization of plan-time expected outputs.
Learnt from: peterlyoo
Repo: sysown/proxysql PR: 5925
File: lib/MySQL_Session.cpp:0-0
Timestamp: 2026-07-10T02:12:40.310Z
Learning: In lib/MySQL_Session.cpp, MySQL_Session::handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_COM_QUERY_qpo() has an early-return path for query cache hits (GloMyQC->get(...) keyed on client_myds->myconn->userinfo->hash) that occurs before the `__exit_set_destination_hostgroup` label. Any per-query session state mutation driven by qpo (e.g. qpo->destination_schema) that is placed after that label will be skipped entirely on a cache hit. The destination_schema switch (client_myds->myconn->userinfo->set_schemaname) is therefore applied right after the qpo->OK_msg/qpo->error_msg early-return checks (before the __exit_set_destination_hostgroup label and before the locked_on_hostgroup rejection check), not after the hostgroup-lock validation, specifically to avoid this cache-hit bypass. This placement was decided in PR `#5925` (commit 652ffa124) after discussion.
Learnt from: peterlyoo
Repo: sysown/proxysql PR: 5925
File: lib/MySQL_Session.cpp:0-0
Timestamp: 2026-07-10T02:12:40.310Z
Learning: In lib/MySQL_Session.cpp, mysql_query_rules.attributes.destination_schema (query-rule-driven session schema switching) is applied unconditionally, without the `transaction_persistent_hostgroup == -1` guard used for `destination_hostgroup`. This is intentional: switching a session's default schema mid-transaction via COM_INIT_DB has the same semantics as a client issuing `USE <schema>` mid-transaction through ProxySQL — it does not commit or invalidate the transaction and the sticky backend connection is preserved. Guarding on `transaction_persistent_hostgroup` was considered but rejected because it would make the destination_schema rule silently inert during an active transaction, which was judged more surprising than the current behavior.
Learnt from: yuji-hatakeyama
Repo: sysown/proxysql PR: 5548
File: lib/mysql_connection.cpp:1837-1843
Timestamp: 2026-03-26T16:39:02.446Z
Learning: In ProxySQL's lib/mysql_connection.cpp, `SHOW WARNINGS` detection for both `update_warning_count_from_connection()` and the `add_eof()` call in `ASYNC_USE_RESULT_CONT` intentionally uses `myds->sess->CurrentQuery.QueryParserArgs.digest_text` (comment-stripped digest text). This means the fix/feature does not work when `mysql-query_digests_keep_comment=1` (digest_text contains comments) or `mysql-query_digests=0` (digest_text is unavailable) — these configurations are explicitly excluded from the regression test for `reg_test_5306-show_warnings_with_comment-t`. This design is consistent across the codebase and is an accepted, documented limitation.
📚 Learning: 2026-08-11T12:56:13.170Z
Learnt from: renecannao
Repo: sysown/proxysql PR: 6033
File: docs/superpowers/plans/2026-08-11-ed25519-authentication.md:469-469
Timestamp: 2026-08-11T12:56:13.170Z
Learning: In `docs/superpowers/plans/2026-08-11-ed25519-authentication.md`, the historical-artifact notice states that embedded expected outputs are plan-time values. Review-driven changes can modify the MariaDB Ed25519 implementation and TAP assertion counts after the plan is written. The shipped implementation and tests are authoritative, so reviewers must not require retroactive synchronization of plan-time expected outputs.

Applied to files:

  • test/tap/tests/unit/auth_unit-t.cpp
📚 Learning: 2026-04-01T21:27:00.297Z
Learnt from: wazir-ahmed
Repo: sysown/proxysql PR: 5557
File: test/tap/tests/unit/gtid_set_unit-t.cpp:14-17
Timestamp: 2026-04-01T21:27:00.297Z
Learning: In ProxySQL unit tests under test/tap/tests/unit/, include test_globals.h and test_init.h only for tests that depend on ProxySQL runtime globals/initialization (i.e., tests that exercise components linked against libproxysql.a). For “pure” data-structure/utility tests (e.g., ezoption_parser_unit-t.cpp, gtid_set_unit-t.cpp, gtid_trxid_interval_unit-t.cpp) that do not require runtime globals/initialization, it is correct to omit test_globals.h and test_init.h and instead include only tap.h plus the relevant project header(s).

Applied to files:

  • test/tap/tests/unit/auth_unit-t.cpp
📚 Learning: 2026-07-08T13:19:04.649Z
Learnt from: CR
Repo: sysown/proxysql PR: 0
File: CLAUDE.md:0-0
Timestamp: 2026-07-08T13:19:04.649Z
Learning: Applies to test/tap/tests/unit/**/*.cpp : Unit tests in `test/tap/tests/unit/` must use `test_globals.h` and `test_init.h` with the custom unit-test harness.

Applied to files:

  • test/tap/tests/unit/auth_unit-t.cpp
📚 Learning: 2026-01-20T09:34:19.124Z
Learnt from: yuji-hatakeyama
Repo: sysown/proxysql PR: 5307
File: test/tap/tests/reg_test_5306-show_warnings_with_comment-t.cpp:39-48
Timestamp: 2026-01-20T09:34:19.124Z
Learning: In ProxySQL's TAP test suite, resource leaks (e.g., not calling mysql_close() on early return paths) are commonly tolerated because test processes are short-lived and OS frees resources on exit. This pattern applies to all C++ test files under test/tap/tests. When reviewing, recognize this as a project-wide test convention and focus on test correctness and isolation rather than insisting on fixing such leaks in these test files.

Applied to files:

  • test/tap/tests/unit/auth_unit-t.cpp
📚 Learning: 2026-01-20T07:40:34.938Z
Learnt from: yuji-hatakeyama
Repo: sysown/proxysql PR: 5307
File: test/tap/tests/reg_test_5306-show_warnings_with_comment-t.cpp:24-28
Timestamp: 2026-01-20T07:40:34.938Z
Learning: In ProxySQL test files, calling `mysql_error(NULL)` after `mysql_init()` failure is safe because the MariaDB client library implementation returns an empty string for NULL handles (not undefined behavior).

Applied to files:

  • test/tap/tests/unit/auth_unit-t.cpp
📚 Learning: 2026-08-12T05:27:01.785Z
Learnt from: renecannao
Repo: sysown/proxysql PR: 6035
File: docs/superpowers/plans/2026-08-11-gtid-sonar-cleanup.md:330-335
Timestamp: 2026-08-12T05:27:01.785Z
Learning: For ProxySQL isolated regression tests that use a fresh explicit `INFRA_ID`, `test/infra/control/ensure-infras.bash` detects the absent `proxysql.${INFRA_ID}` container and invokes `test/infra/control/start-proxysql-isolated.bash` before it provisions configuration. Do not invoke `start-proxysql-isolated.bash` again after `ensure-infras.bash`, because it removes the named container and its `proxysql.db`, which discards the provisioned configuration. The binary at `src/proxysql` is mounted when the container is initially created.

Applied to files:

  • test/tap/tests/unit/auth_unit-t.cpp
🪛 Cppcheck (2.21.0)
lib/MySQL_Authentication.cpp

[warning] 310-310: If memory allocation fails, then there is a possible null pointer dereference

(nullPointerOutOfMemory)

🔇 Additional comments (4)
lib/MySQL_Authentication.cpp (1)

181-181: LGTM!

Also applies to: 310-322

test/tap/tests/unit/auth_unit-t.cpp (3)

55-63: LGTM!


461-543: LGTM!


654-654: LGTM!

Also applies to: 673-676


📝 Walkthrough

Walkthrough

MySQL_Authentication::add now forces TLS for accounts with valid spiffe_id attributes. Unit tests cover creation, updates, invalid attributes, case variants, and TLS transitions.

Changes

SPIFFE TLS authentication

Layer / File(s) Summary
Derive effective TLS setting
lib/MySQL_Authentication.cpp
MySQL_Authentication::add derives an effective SSL flag from use_ssl. Valid spiffe_id attributes force TLS before the account record is stored.
Validate SPIFFE account updates
test/tap/tests/unit/auth_unit-t.cpp
Tests cover configurable attributes, valid and invalid SPIFFE data, case-variant updates, TLS enablement and disablement, and TAP registration.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Mergeability Score: ⚪ Minimal · up to deb07

The change ensures SPIFFE-authenticated MySQL users use TLS while preserving existing validation behavior, with focused authentication coverage added; no actionable merge-blocking risk remains beyond normal checks and review.

Possibly related issues

  • Issue 5928 — Covers SPIFFE-based TLS enforcement in MySQL_Authentication::add.
  • Issue 5474 — Covers the authentication unit-test expansion extended by these changes.

Possibly related PRs

Poem

A rabbit checks the SPIFFE trail,
And sets TLS when identities sail.
Bad JSON leaves the flag alone,
Updates keep the right state known.
Hop, hop—secure accounts now prevail!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The change prevents retained spiffe_id users from running with use_ssl=0 and adds coverage for SPIFFE attribute transitions [#5929].
Out of Scope Changes check ✅ Passed The implementation and tests directly support TLS enforcement for SPIFFE users and contain no unrelated changes.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: requiring TLS for MySQL users with SPIFFE identities.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/5929-spiffe-requires-tls-v3.0

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@gitar-bot

gitar-bot Bot commented Aug 13, 2026

Copy link
Copy Markdown
Code Review ✅ Approved

Forces the runtime MySQL use_ssl flag when user attributes contain a spiffe_id, ensuring TLS is required for SPIFFE users. No issues found.

Options

Auto-apply is off → Gitar will not commit updates to this branch.
Display: compact → Showing less information.

Comment with these commands to change the behavior for this request:

Auto-apply Compact
gitar auto-apply:on         
gitar display:verbose         

Was this helpful? React with 👍 / 👎 | Gitar

@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
B Maintainability Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

@renecannao
renecannao marked this pull request as ready for review August 13, 2026 18:29

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

2 issues found across 2 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="lib/MySQL_Authentication.cpp">

<violation number="1" location="lib/MySQL_Authentication.cpp:312">
P3: This re-parses `ad->attributes` that was just parsed and validated a few lines above in the same `add()` call (in both the new-account and attribute-change branches). Every `add()` for a user with non-empty attributes now parses the same JSON twice. The spiffe check could reuse the already-validated JSON instead of parsing again; as-is it's redundant work done on every user load (e.g. `LOAD MYSQL USERS TO RUNTIME` iterating many users).</violation>

<violation number="2" location="lib/MySQL_Authentication.cpp:313">
P2: The TLS-forcing path runs for every credential type, not only frontend users. In ProxySQL_Admin.cpp the LOAD MYSQL USERS handler calls `add()` once per usertype in `usertypes`, and a single `mysql_users` row flagged with both `frontend_=1` and `backend_=1` passes the same `attributes` (including `spiffe_id`) for the USERNAME_BACKEND credential too. As a result the backend account also gets `use_ssl=true`, forcing TLS on the proxy→MySQL backend connection for that user. This contradicts the PR scope ("require TLS for MySQL frontend users") and can break backend connectivity for a SPIFFE user that is also a backend user. Guard the spiffe check with `usertype == USERNAME_FRONTEND`.</violation>
</file>

Reply with feedback, questions, or to request a fix.

Fix all with cubic | Re-trigger cubic

if (ad->attributes && strlen(ad->attributes)) {
try {
nlohmann::json valid=nlohmann::json::parse(ad->attributes);
if (valid.find("spiffe_id") != valid.end()) {

@cubic-dev-ai cubic-dev-ai Bot Aug 13, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2: The TLS-forcing path runs for every credential type, not only frontend users. In ProxySQL_Admin.cpp the LOAD MYSQL USERS handler calls add() once per usertype in usertypes, and a single mysql_users row flagged with both frontend_=1 and backend_=1 passes the same attributes (including spiffe_id) for the USERNAME_BACKEND credential too. As a result the backend account also gets use_ssl=true, forcing TLS on the proxy→MySQL backend connection for that user. This contradicts the PR scope ("require TLS for MySQL frontend users") and can break backend connectivity for a SPIFFE user that is also a backend user. Guard the spiffe check with usertype == USERNAME_FRONTEND.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At lib/MySQL_Authentication.cpp, line 313:

<comment>The TLS-forcing path runs for every credential type, not only frontend users. In ProxySQL_Admin.cpp the LOAD MYSQL USERS handler calls `add()` once per usertype in `usertypes`, and a single `mysql_users` row flagged with both `frontend_=1` and `backend_=1` passes the same `attributes` (including `spiffe_id`) for the USERNAME_BACKEND credential too. As a result the backend account also gets `use_ssl=true`, forcing TLS on the proxy→MySQL backend connection for that user. This contradicts the PR scope ("require TLS for MySQL frontend users") and can break backend connectivity for a SPIFFE user that is also a backend user. Guard the spiffe check with `usertype == USERNAME_FRONTEND`.</comment>

<file context>
@@ -306,7 +307,19 @@ bool MySQL_Authentication::add(char * username, char * password, enum cred_usern
+	if (ad->attributes && strlen(ad->attributes)) {
+		try {
+			nlohmann::json valid=nlohmann::json::parse(ad->attributes);
+			if (valid.find("spiffe_id") != valid.end()) {
+				effective_use_ssl = true;
+			}
</file context>
Fix with cubic

ad->use_ssl=use_ssl;
if (ad->attributes && strlen(ad->attributes)) {
try {
nlohmann::json valid=nlohmann::json::parse(ad->attributes);

@cubic-dev-ai cubic-dev-ai Bot Aug 13, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P3: This re-parses ad->attributes that was just parsed and validated a few lines above in the same add() call (in both the new-account and attribute-change branches). Every add() for a user with non-empty attributes now parses the same JSON twice. The spiffe check could reuse the already-validated JSON instead of parsing again; as-is it's redundant work done on every user load (e.g. LOAD MYSQL USERS TO RUNTIME iterating many users).

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At lib/MySQL_Authentication.cpp, line 312:

<comment>This re-parses `ad->attributes` that was just parsed and validated a few lines above in the same `add()` call (in both the new-account and attribute-change branches). Every `add()` for a user with non-empty attributes now parses the same JSON twice. The spiffe check could reuse the already-validated JSON instead of parsing again; as-is it's redundant work done on every user load (e.g. `LOAD MYSQL USERS TO RUNTIME` iterating many users).</comment>

<file context>
@@ -306,7 +307,19 @@ bool MySQL_Authentication::add(char * username, char * password, enum cred_usern
-	ad->use_ssl=use_ssl;
+	if (ad->attributes && strlen(ad->attributes)) {
+		try {
+			nlohmann::json valid=nlohmann::json::parse(ad->attributes);
+			if (valid.find("spiffe_id") != valid.end()) {
+				effective_use_ssl = true;
</file context>
Fix with cubic

@codecov

codecov Bot commented Aug 13, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 77.77778% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 53.46%. Comparing base (efe5910) to head (deb0722).
⚠️ Report is 63 commits behind head on v3.0.

Files with missing lines Patch % Lines
lib/MySQL_Authentication.cpp 77.77% 2 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             v3.0    #6059      +/-   ##
==========================================
- Coverage   53.58%   53.46%   -0.13%     
==========================================
  Files         504      503       -1     
  Lines      148005   147279     -726     
  Branches    37488    37286     -202     
==========================================
- Hits        79314    78737     -577     
- Misses      51115    51116       +1     
+ Partials    17576    17426     -150     
Flag Coverage Δ
integration-tests 49.23% <44.44%> (-0.16%) ⬇️
unit-tests 16.08% <85.71%> (+0.02%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@renecannao
renecannao merged commit c6de1b5 into v3.0 Aug 14, 2026
82 of 85 checks passed
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.

Stale SPIFFE identity after toggling use_ssl

1 participant