Skip to content

[fix](auth) Mask credentials in authentication and Stream Load logs - #66618

Open
bobhan1 wants to merge 2 commits into
apache:masterfrom
bobhan1:agent/mask-http-auth-credentials
Open

[fix](auth) Mask credentials in authentication and Stream Load logs#66618
bobhan1 wants to merge 2 commits into
apache:masterfrom
bobhan1:agent/mask-http-auth-credentials

Conversation

@bobhan1

@bobhan1 bobhan1 commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

What problem does this PR solve?

Issue Number: CIR-21336

Problem Summary: Authentication credentials could be exposed by HTTP authentication and Stream Load diagnostic logs. In addition to the original HTTP authentication request logging, several FE and BE Stream Load paths formatted complete Thrift requests containing passwd, token, auth_code, or auth_code_uuid. The deprecated auth_code HTTP header was also missing from the sensitive-header filter, and two Stream Load authentication errors included the invalid token value.

This PR logs sanitized copies of authentication-related requests. Credential values are masked or omitted while non-sensitive request fields remain available for diagnostics.

Release note

Mask authentication credentials in HTTP authentication and Stream Load logs while retaining non-sensitive request context.

Check List (For Author)

  • Test

    • Regression test
    • Unit Test
      • ./run-be-ut.sh --run --filter=HttpAuthTest.* -j100 (7 tests passed)
      • ./run-fe-ut.sh --run org.apache.doris.common.util.ThriftLogHelperTest,org.apache.doris.service.FrontendServiceImplTest,org.apache.doris.load.StreamLoadHandlerTest (24 tests passed)
      • clang-format --dry-run --Werror be/src/load/stream_load/stream_load_executor.cpp be/src/service/http/http_request.cpp
      • git diff --check
    • Manual test (add detailed scripts or steps below)
    • No need to test or manual test. Explain why:
      • This is a refactor/code format and no logic has been changed.
      • Previous test can cover this change.
      • No code files have been changed.
      • Other reason
  • Behavior changed:

    • No.
    • Yes. Credential values are no longer emitted by the affected logs and invalid-token errors; other request fields are unchanged.
  • Does this need documentation?

    • No.
    • Yes.

Implementation notes

  • FE uses one Thrift-metadata-based helper to deep-copy requests and sanitize credential fields by field name, so request structs with different field IDs share the same logic.
  • String credentials (passwd, token, and auth_code_uuid) are replaced with ***MASKED***; the numeric deprecated auth_code is omitted from log-only copies.
  • BE uses a dedicated helper to sanitize the Stream Load commit request before formatting it.
  • FE and BE HTTP request formatters also treat the deprecated auth_code header as sensitive.
  • The helper unit test covers two different Thrift request types, preservation of non-sensitive fields, and immutability of the original requests.

### What problem does this PR solve?

Issue Number: close #xxx

Related PR: #xxx

Problem Summary: A failed HTTP authentication request caused the BE warning log to print the complete TCheckAuthRequest, including its plaintext password. The FE checkAuth debug log exposed the same field. Copy the request before logging and replace only the password with the standard ***MASKED*** marker, preserving the user, client IP, privilege, and other non-secret diagnostic fields. The existing HTTP request formatter continues to mask authentication tokens and Authorization headers.

### Release note

Mask passwords in BE and FE HTTP authentication logs while retaining non-sensitive request context.

### Check List (For Author)

- Test
    - [ ] Regression test
    - [x] Unit Test
    - [ ] Manual test (add detailed scripts or steps below)
    - [ ] No need to test or manual test. Explain why:
        - [ ] This is a refactor/code format and no logic has been changed.
        - [ ] Previous test can cover this change.
        - [ ] No code files have been changed.
        - [ ] Other reason

- Behavior changed:
    - [ ] No.
    - [x] Yes. Password values are replaced with ***MASKED*** in authentication logs; other request fields are unchanged.

- Does this need documentation?
    - [x] No.
    - [ ] Yes.
@hello-stephen

Copy link
Copy Markdown
Contributor

Thank you for your contribution to Apache Doris.
Don't know what should be done next? See How to process your PR.

Please clearly describe your PR:

  1. What problem was fixed (it's best to include specific error reporting information). How it was fixed.
  2. Which behaviors were modified. What was the previous behavior, what is it now, why was it modified, and what possible impacts might there be.
  3. What features were added. Why was this function added?
  4. Which code was refactored and why was this part of the code refactored?
  5. Which functions were optimized and what is the difference before and after the optimization?

@bobhan1
bobhan1 marked this pull request as ready for review August 10, 2026 11:23
@bobhan1 bobhan1 changed the title [fix](auth) Mask passwords in HTTP authentication logs [fix](auth) Mask credentials in authentication and Stream Load logs Aug 10, 2026
@bobhan1

bobhan1 commented Aug 10, 2026

Copy link
Copy Markdown
Contributor Author

/review

@bobhan1

bobhan1 commented Aug 10, 2026

Copy link
Copy Markdown
Contributor Author

run buildall

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Requesting changes: the local masking helpers are sound for their current call sites, but the patch does not achieve its end-to-end credential-redaction goal. Five inline findings identify live paths that still emit usable passwords, bearer/session/cluster tokens, or rejected credential values.

Review status: capped/incomplete. A distinct Arrow Flight/bootstrap token finding appeared in the third and final allowed review round. All currently known candidates have been independently verified, deduplicated, and adjudicated, but the workflow did not reach a clean no-new-findings round.

Critical checkpoints:

  • Goal and proof: Not met. The focused tests prove selected Thrift/header serializers, but production query parameters, parallel RPCs, redirects/COPY/session handling, direct BE token paths, and Arrow Flight token lifecycle logs remain credential-bearing.
  • Scope/focus: The individual edits are small, but the redaction policy is split among local helpers and does not cover functionally parallel paths; a shared safe-rendering boundary is needed.
  • Concurrency: No production thread/lock or shared-state behavior is changed. The copied request objects are local to each logging call, and no race or lock-order issue was found.
  • Lifecycle/static initialization: No new production lifecycle or cross-TU static-initialization hazard was found. The new BE mask constant is compile-time initialized and the Java utility is stateless.
  • Configuration: No configuration item is added or changed. Existing cloud-forwarding and default-enabled Arrow Flight conditions expose missed paths, as described inline.
  • Compatibility: No wire, storage, symbol, or rolling-upgrade compatibility change is introduced.
  • Parallel paths: Blocking gaps remain across FE transaction RPCs, FE HTTP/COPY/session paths, BE query/direct-token paths, and FE Arrow Flight/bootstrap token handling.
  • Special conditions: The current helpers correctly handle password, token, deprecated auth code/UUID, and certificate branches at their actual call sites, but equivalent conditional/error paths outside those call sites remain unredacted.
  • Test coverage: The new unit tests are deterministic and useful for the touched serializers, but they omit a real credential-bearing URI and end-to-end coverage for every blocking parallel path.
  • Test results: No result files are changed. Per the automated-review constraint I did not run local builds/tests; the author reports 7 BE and 24 FE unit tests passing. Current live style/license/secret/dependency checks pass, while BE UT (macOS) is still in progress.
  • Observability: Preserving non-secret request fields is appropriate, but remaining INFO/WARN/DEBUG/ERROR sinks defeat the intended safe observability. No new metric is required for this hardening.
  • Transactions/persistence: The patch does not change transaction outcomes, EditLog behavior, failover semantics, or persisted data.
  • Data writes/crash safety: No data-write or atomicity behavior is modified.
  • FE/BE variables: No new cross-process variable or protocol field is introduced.
  • Performance: The Thrift copies are behind DEBUG/VLOG guards and no unacceptable default-path CPU/memory cost was found.
  • Other issues/security disposition: No additional distinct defect survived the final sweep. BE 8040/heartbeat/bootstrap instances are internal operational-hardening issues under the threat model; FE Arrow Flight 8070 is explicitly client-facing.

User focus: no additional review focus was supplied.

return iequal(header_name, HttpHeaders::AUTHORIZATION) ||
iequal(header_name, HttpHeaders::PROXY_AUTHORIZATION) || iequal(header_name, "token") ||
iequal(header_name, HttpHeaders::AUTH_TOKEN);
iequal(header_name, HttpHeaders::AUTH_TOKEN) || iequal(header_name, "auth_code");

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[P1] Sanitize credential query parameters in debug_string

This predicate is only consulted for _headers. init_from_evhttp() keeps the full query in _uri and copies it into _params, while debug_string() prints both without redaction. BatchDownloadAction uses ?token=... as a real credential and logs req->debug_string() before _check_token(); with all-HTTP auth enabled, the failed-auth warning formats it as well. The token therefore still reaches logs despite this sensitive-name update. Please render the URI/params through the same case-insensitive redaction policy and add a test initialized from a real credential-bearing URI.

import org.apache.doris.common.util.DebugPointUtil;
import org.apache.doris.common.util.DebugPointUtil.DebugPoint;
import org.apache.doris.common.util.PropertyAnalyzer;
import org.apache.doris.common.util.ThriftLogHelper;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[P1] Redact the parallel credential-bearing RPC logs

This shared helper is applied only to the selected load RPCs, while live parallel handlers in this class still stringify the same credential fields. For example, FeServiceClient.beginRemoteTxn/commitRemoteTxn/abortRemoteTxn put the external-catalog password into each request immediately before RPC, but the handlers at lines 2286/2368/2424 log those requests directly. Their invalid-token branches also include request.getToken() in the returned status, which RemoteOlapInsertExecutor logs on failure. The legacy begin/commit/rollback handlers have the same raw-request pattern. Please use the log-only sanitizer for every credential-bearing request log and value-free token errors, with coverage for these production paths.

|| "token".equalsIgnoreCase(headerName)
|| "Auth-Token".equalsIgnoreCase(headerName);
|| "Auth-Token".equalsIgnoreCase(headerName)
|| "auth_code".equalsIgnoreCase(headerName);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[P1] Share redaction across the FE HTTP credential paths

This predicate protects only LoadAction's normal header dump. Other live HTTP paths still expose usable credentials: /copy/upload and /copy/query log every Authorization/Cookie header at INFO before authentication, and a successful cloud group-commit forward places the Basic user:password in RedirectView userinfo that the bounded-drain path logs at INFO. Failure/session paths also bypass this helper: line 134 returns and logs the rejected token, malformed Basic auth is logged verbatim, and addSession logs the newly issued live session ID. Please centralize safe header/URL/error rendering across these paths and add credential-bearing end-to-end log tests (including auth_code).

Status status(Status::create(auth_result.status));
if (!status.ok()) {
LOG(WARNING) << "permission verification failed, request: " << auth_request;
TCheckAuthRequest request_for_log(auth_request);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[P1] Redact the parallel BE token-authentication sinks

This masks the Basic-auth request, but parallel token paths still log usable credentials. DownloadAction::check_token writes both the submitted token and _exec_env->token() and returns the submitted value; clone download helpers embed _cluster_info->token in URLs logged at WARN/INFO; heartbeat handling logs the installed cluster and current/last HTTP auth tokens at INFO. These sinks are independent of HttpRequest::debug_string(), so fixing query rendering alone will not close them. Please use value-free errors/constant masks for raw tokens, mask_token only for token-bearing URLs, and add focused log-capture coverage.

}

// auth_code is omitted because its numeric field cannot hold the string mask.
public static <T extends TBase<T, F>, F extends TFieldIdEnum> T requestForLog(T request) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[P1] Cover the direct FE bearer/token lifecycle logs

This helper addresses selected Thrift request formatting, but direct FE token sinks still expose usable credentials. On the default-enabled Arrow Flight service, FlightTokenManagerImpl.createToken stores a new bearer, returns that same value in Authorization: Bearer, then logs it at INFO; it remains accepted for the default 86400 seconds. Rejected bearer values are also embedded in exceptions that FlightBearerTokenAuthenticator logs and returns. Separately, FE bootstrap logs the helper node's raw cluster token immediately before installing it. Please make creation/validation/eviction/bootstrap messages value-free (or use a non-reversible fingerprint) and add INFO/ERROR log-capture plus client-error tests.

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-H: Total hot run time: 29127 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpch-tools
Tpch sf100 test result on commit f250154ae2f38271098909dd6a0310f18f392d94, data reload: false

------ Round 1 ----------------------------------
============================================
q1	17635	3945	3872	3872
q2	2039	321	199	199
q3	10314	1366	794	794
q4	4681	471	338	338
q5	7483	876	555	555
q6	178	174	137	137
q7	731	788	599	599
q8	9313	1608	1502	1502
q9	5367	4005	4038	4005
q10	6773	1618	1348	1348
q11	500	352	320	320
q12	771	575	449	449
q13	18077	3370	2746	2746
q14	257	259	238	238
q15	q16	733	734	663	663
q17	1046	1005	1045	1005
q18	6581	5638	5582	5582
q19	1330	1296	1100	1100
q20	797	721	611	611
q21	6145	2748	2728	2728
q22	456	382	336	336
Total cold run time: 101207 ms
Total hot run time: 29127 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	4940	4591	4669	4591
q2	291	326	207	207
q3	4879	5228	4623	4623
q4	2171	2252	1415	1415
q5	4751	4456	4423	4423
q6	250	202	143	143
q7	1794	1685	1497	1497
q8	2375	2037	2050	2037
q9	7126	6718	6694	6694
q10	4267	4186	3823	3823
q11	509	366	337	337
q12	701	696	531	531
q13	2981	3262	2770	2770
q14	280	279	258	258
q15	q16	666	676	607	607
q17	1252	1239	1246	1239
q18	12126	11007	11751	11007
q19	1082	1050	1064	1050
q20	2187	2195	1909	1909
q21	5256	4541	4510	4510
q22	515	474	397	397
Total cold run time: 60399 ms
Total hot run time: 54068 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-DS: Total hot run time: 158346 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpcds-tools
TPC-DS sf100 test result on commit f250154ae2f38271098909dd6a0310f18f392d94, data reload: false

query5	4324	598	448	448
query6	473	214	205	205
query7	4897	594	325	325
query8	320	159	148	148
query9	8733	4016	4021	4016
query10	472	346	294	294
query11	5843	2212	2031	2031
query12	150	98	94	94
query13	1299	583	430	430
query14	6075	4305	3985	3985
query14_1	3807	3801	3792	3792
query15	198	194	182	182
query16	985	462	441	441
query17	909	672	527	527
query18	2430	458	350	350
query19	207	184	142	142
query20	99	104	111	104
query21	223	157	134	134
query22	12987	12971	12940	12940
query23	15739	15069	14536	14536
query23_1	14614	14623	14750	14623
query24	7439	1700	1236	1236
query24_1	1245	1190	1226	1190
query25	537	412	351	351
query26	1323	368	209	209
query27	2597	610	389	389
query28	4557	2026	2007	2007
query29	1078	609	456	456
query30	347	260	219	219
query31	1178	1112	1044	1044
query32	114	64	58	58
query33	546	314	254	254
query34	1198	1119	643	643
query35	741	784	655	655
query36	770	782	680	680
query37	158	114	96	96
query38	1840	1770	1673	1673
query39	831	821	803	803
query39_1	776	790	787	787
query40	247	178	152	152
query41	72	72	68	68
query42	99	98	99	98
query43	328	322	292	292
query44	1442	796	789	789
query45	194	175	170	170
query46	1054	1125	722	722
query47	1545	1556	1453	1453
query48	405	411	309	309
query49	596	403	311	311
query50	1162	425	328	328
query51	10543	10660	10479	10479
query52	88	92	75	75
query53	274	278	207	207
query54	298	256	239	239
query55	77	75	71	71
query56	316	311	306	306
query57	1008	1000	946	946
query58	293	274	245	245
query59	1550	1618	1432	1432
query60	336	297	267	267
query61	177	172	175	172
query62	402	317	272	272
query63	244	202	201	201
query64	2975	1140	979	979
query65	3873	3805	3830	3805
query66	1867	488	361	361
query67	20167	19991	19905	19905
query68	3436	1519	1019	1019
query69	410	302	266	266
query70	864	801	748	748
query71	364	327	309	309
query72	3085	2864	2337	2337
query73	835	776	403	403
query74	4634	4518	4290	4290
query75	2373	2351	1984	1984
query76	2319	1142	791	791
query77	337	369	274	274
query78	11146	11062	10507	10507
query79	1335	1202	743	743
query80	654	555	464	464
query81	458	325	291	291
query82	658	175	138	138
query83	410	322	306	306
query84	339	167	130	130
query85	936	608	548	548
query86	325	231	229	229
query87	1998	1954	1839	1839
query88	3713	2796	2780	2780
query89	394	325	275	275
query90	1924	192	189	189
query91	195	201	164	164
query92	61	56	56	56
query93	1543	1539	959	959
query94	551	344	314	314
query95	781	612	476	476
query96	1097	863	364	364
query97	2458	2513	2323	2323
query98	198	190	182	182
query99	738	730	612	612
Total cold run time: 244565 ms
Total hot run time: 158346 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
ClickBench: Total hot run time: 23.86 s
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/clickbench-tools
ClickBench test result on commit f250154ae2f38271098909dd6a0310f18f392d94, data reload: false

query1	0.00	0.00	0.00
query2	0.10	0.04	0.04
query3	0.26	0.13	0.14
query4	1.61	0.14	0.14
query5	0.24	0.21	0.21
query6	1.16	0.83	0.81
query7	0.04	0.01	0.01
query8	0.05	0.04	0.03
query9	0.38	0.33	0.33
query10	0.56	0.58	0.57
query11	0.18	0.13	0.13
query12	0.18	0.14	0.14
query13	0.46	0.46	0.46
query14	1.01	0.99	1.01
query15	0.60	0.60	0.58
query16	0.32	0.31	0.32
query17	1.16	1.10	1.12
query18	0.20	0.20	0.19
query19	2.00	1.97	1.93
query20	0.02	0.01	0.02
query21	15.44	0.22	0.13
query22	4.69	0.06	0.05
query23	16.13	0.33	0.12
query24	2.93	0.42	0.31
query25	0.11	0.06	0.05
query26	0.73	0.20	0.14
query27	0.04	0.03	0.03
query28	3.52	0.81	0.37
query29	12.51	3.98	3.17
query30	0.27	0.15	0.15
query31	2.78	0.57	0.30
query32	3.22	0.58	0.48
query33	3.22	3.25	3.18
query34	15.66	3.93	3.28
query35	3.22	3.21	3.21
query36	0.55	0.44	0.43
query37	0.09	0.07	0.06
query38	0.06	0.04	0.03
query39	0.04	0.03	0.03
query40	0.18	0.15	0.15
query41	0.09	0.03	0.03
query42	0.04	0.02	0.03
query43	0.04	0.04	0.03
Total cold run time: 96.09 s
Total hot run time: 23.86 s

@hello-stephen

Copy link
Copy Markdown
Contributor

FE UT Coverage Report

Increment line coverage 48.39% (15/31) 🎉
Increment coverage report
Complete coverage report

@hello-stephen

Copy link
Copy Markdown
Contributor

FE Regression Coverage Report

Increment line coverage 0.00% (0/31) 🎉
Increment coverage report
Complete coverage report

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.

2 participants