Skip to content

[Enhance](resource) Restrict AI resource creation by user identity - #68147

Merged
starocean999 merged 2 commits into
apache:masterfrom
linrrzqqq:restrict-creator
Sep 18, 2026
Merged

starocean999 merged 2 commits into
apache:masterfrom
linrrzqqq:restrict-creator

Conversation

@linrrzqqq

Copy link
Copy Markdown
Collaborator

What problem does this PR solve?

Issue Number: close #xxx

Related PR: #xxx

Problem Summary:

Release note

Rstrict AI resource creation by user identity

@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?

@linrrzqqq

Copy link
Copy Markdown
Collaborator Author

/review

@linrrzqqq

Copy link
Copy Markdown
Collaborator Author

run buildall

@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	17590	4093	4104	4093
q2	2278	363	286	286
q3	10035	1427	809	809
q4	4680	485	354	354
q5	7469	819	556	556
q6	189	186	142	142
q7	766	829	603	603
q8	9383	1603	1534	1534
q9	5458	4175	4212	4175
q10	6750	1629	1369	1369
q11	429	272	246	246
q12	648	448	317	317
q13	18075	2745	2171	2171
q14	274	260	249	249
q15	q16	730	725	664	664
q17	1767	1083	1020	1020
q18	6632	5660	5559	5559
q19	1226	1310	1102	1102
q20	485	399	283	283
q21	5712	2519	2313	2313
q22	426	353	302	302
Total cold run time: 101002 ms
Total hot run time: 28147 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	4331	4230	4239	4230
q2	750	605	589	589
q3	4627	4948	4442	4442
q4	2277	2367	1496	1496
q5	4363	4282	4283	4282
q6	244	188	136	136
q7	1741	1672	1538	1538
q8	2818	2280	2301	2280
q9	7536	7556	7560	7556
q10	4329	4358	3984	3984
q11	597	427	376	376
q12	760	750	530	530
q13	2643	2972	2294	2294
q14	297	328	409	328
q15	q16	729	714	635	635
q17	7881	7293	7141	7141
q18	11951	11071	11950	11071
q19	1200	1079	1062	1062
q20	2253	2233	1988	1988
q21	6055	4750	4710	4710
q22	522	461	432	432
Total cold run time: 67904 ms
Total hot run time: 61100 ms

@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 for three client-visible gaps in the new AI-resource authorization contract: malformed configuration is accepted and later misdiagnosed, supported external/JIT administrator identities are not always representable, and a configured-user denial is returned with the generic 1105/HY000 error classification.

Checkpoint conclusions:

  • Goal and scope: the default wildcard preserves the prior ADMIN-only behavior, and valid stored native/domain identities take the intended AI-only exact-identity path. The three-file change is otherwise focused.
  • Authorization and configuration: every supported current-version SQL creation path reaches validation on the active master, and no fail-open bypass was found. The malformed-value and JIT identity cases below make the opt-in policy unusable for supported configurations or identities.
  • Lifecycle and concurrency: the immutable process-local string introduces no thread, lock, or hot-path concern; one parse on rare DDL is negligible. Ordinary failover/config deployment behavior did not establish a separate defect.
  • Compatibility and persistence: forwarding preserves the exact user identity; resource construction, journaling, replay, and restore remain symmetric. There is no FE-BE protocol, storage-format, transaction, or data-write change.
  • Tests and observability: the added tests cover exact allow/deny, wildcard, and non-AI branches and restore their globals, but they do not detect the protocol code, malformed value, or external/JIT cases reported inline. Standard config visibility exists, but malformed syntax has no actionable diagnosis.
  • Security model: ADMIN holders are trusted by the repository threat model, so these are functional/API policy defects rather than claimed Doris vulnerabilities.

Validation was static-only under the review contract: I did not build, run tests, or edit repository source. At submission time, live CI reports CheckStyle and compile successful while FE UT and regression suites remain pending; those external results are separate from this review. No additional user focus was supplied.

analyzeResourceType();

if (resourceType == ResourceType.AI && !"*".equals(Config.ai_resource_allowed_user)) {
UserIdentity allowedUser = UserIdentity.fromString(Config.ai_resource_allowed_user);

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.

[P2] Reject malformed configured identities explicitly. UserIdentity.fromString returns null for values such as root@%, so this FE starts normally and every AI CREATE later falls through to the generic caller-denied error. Because this field is not mutable, the operator cannot correct the typo without another restart. Please validate the value at configuration load, or at least detect null here and report ai_resource_allowed_user and its required syntax; add a malformed-value test.


if (resourceType == ResourceType.AI && !"*".equals(Config.ai_resource_allowed_user)) {
UserIdentity allowedUser = UserIdentity.fromString(Config.ai_resource_allowed_user);
if (!ConnectContext.get().getCurrentUserIdentity().equals(allowedUser)) {

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.

[P2] Support the external/JIT identities admitted by the preceding privilege check. JIT authentication builds the current identity as principal@remoteIp, but UserIdentity.fromString splits on every @. An email-style principal such as alice@example.com is therefore impossible to configure even with an exact host; principals without @ are still pinned to one client IP because equals does not apply host-pattern semantics. Please define this setting against a stable authenticated principal or use a validated quote-aware selector, or explicitly reject/document JIT identities and cover that contract in tests.

if (resourceType == ResourceType.AI && !"*".equals(Config.ai_resource_allowed_user)) {
UserIdentity allowedUser = UserIdentity.fromString(Config.ai_resource_allowed_user);
if (!ConnectContext.get().getCurrentUserIdentity().equals(allowedUser)) {
throw new AnalysisException("Current user does not have permission to create AI resources");

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.

[P2] Preserve an access-denied SQL error here. The string-only AnalysisException constructor leaves mysqlErrorCode at ERR_UNKNOWN_ERROR, so this deliberate authorization rejection is returned as 1105/HY000, unlike the adjacent ADMIN check (1227/42000). Clients that classify permission failures will treat this as an internal error. Please use an appropriate access-denied ErrorCode (or a dedicated 5000-series code) and assert the protocol error code in the test.

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.

Confirmed against 182fc371e38e: if ai_resource_allowed_user is set to 'root'@'%' and another ADMIN user tries to create an AI resource, this check throws the string-only AnalysisException. That constructor defaults to ERR_UNKNOWN_ERROR, and the StmtExecutor / MysqlErrPacket path preserves it as 1105 / HY000. The existing ADMIN check in the same method reports 1227 / 42000, so clients classifying failures by error code cannot recognize this new rejection as an authorization failure.

Could we use an appropriate access-denied ErrorCode while retaining a message that explains the configured identity restriction? The caller has already passed the ADMIN check, so the message should not suggest that granting ADMIN will fix it.

Please also assert getMysqlErrorCode() in the unit test. The current assertion on the message's errCode = 2 checks Doris's internal error code, not the MySQL protocol error code. I ran CreateResourceCommandTest locally: all five tests pass, but this distinction is currently untested.

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-DS: Total hot run time: 154078 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 182fc371e38eecf9ddb4bec9b9794e46ad11849c, data reload: false

query5	4323	606	472	472
query6	435	196	180	180
query7	4806	506	290	290
query8	316	187	171	171
query9	8766	3987	3997	3987
query10	443	305	260	260
query11	5697	2211	2003	2003
query12	156	99	93	93
query13	1241	577	363	363
query14	6516	4617	4282	4282
query14_1	4081	4063	4038	4038
query15	206	207	182	182
query16	972	491	448	448
query17	921	698	559	559
query18	2446	448	342	342
query19	193	183	139	139
query20	108	104	107	104
query21	223	147	122	122
query22	13064	13008	12830	12830
query23	15471	14490	14002	14002
query23_1	14099	14062	14106	14062
query24	7409	1720	1256	1256
query24_1	1264	1248	1232	1232
query25	543	429	370	370
query26	1258	347	168	168
query27	2688	573	361	361
query28	4634	1974	1990	1974
query29	1056	611	473	473
query30	324	240	200	200
query31	898	762	651	651
query32	147	100	96	96
query33	519	319	241	241
query34	1216	1180	672	672
query35	737	786	657	657
query36	783	790	730	730
query37	155	110	93	93
query38	1858	1776	1714	1714
query39	716	687	657	657
query39_1	662	646	656	646
query40	228	124	99	99
query41	71	68	68	68
query42	93	90	92	90
query43	361	365	320	320
query44	1405	709	698	698
query45	189	181	211	181
query46	1025	1197	713	713
query47	1500	1519	1390	1390
query48	384	383	272	272
query49	589	403	289	289
query50	1030	338	248	248
query51	10474	10460	10325	10325
query52	85	86	73	73
query53	235	253	177	177
query54	241	220	188	188
query55	76	73	70	70
query56	231	219	213	213
query57	1521	1389	1380	1380
query58	232	221	206	206
query59	1985	2070	1813	1813
query60	272	253	217	217
query61	142	141	145	141
query62	398	331	261	261
query63	222	174	172	172
query64	2839	992	811	811
query65	4014	4007	3999	3999
query66	1781	431	300	300
query67	19981	20045	19834	19834
query68	3648	1431	927	927
query69	400	305	260	260
query70	968	918	890	890
query71	292	231	218	218
query72	2846	2508	2177	2177
query73	804	765	417	417
query74	4656	4491	4291	4291
query75	2298	2292	1937	1937
query76	2331	1131	728	728
query77	369	400	315	315
query78	8951	9143	8448	8448
query79	1393	1242	744	744
query80	582	440	362	362
query81	483	283	235	235
query82	616	171	123	123
query83	367	278	244	244
query84	322	140	115	115
query85	846	461	375	375
query86	331	238	224	224
query87	2004	1971	1857	1857
query88	3704	2736	2732	2732
query89	389	296	260	260
query90	1874	184	182	182
query91	173	156	121	121
query92	99	91	80	80
query93	1525	1504	918	918
query94	523	324	292	292
query95	667	453	328	328
query96	1072	757	329	329
query97	2461	2439	2307	2307
query98	200	196	185	185
query99	749	709	603	603
Total cold run time: 240922 ms
Total hot run time: 154078 ms

@hello-stephen

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

query1	0.01	0.01	0.01
query2	0.10	0.05	0.04
query3	0.25	0.14	0.14
query4	1.61	0.14	0.15
query5	0.25	0.22	0.23
query6	1.16	0.96	0.94
query7	0.04	0.01	0.00
query8	0.05	0.03	0.04
query9	0.39	0.34	0.35
query10	0.57	0.55	0.57
query11	0.20	0.15	0.16
query12	0.19	0.15	0.15
query13	0.46	0.48	0.48
query14	0.97	0.96	0.93
query15	0.61	0.59	0.60
query16	0.31	0.33	0.33
query17	1.11	1.13	1.07
query18	0.21	0.21	0.21
query19	2.05	1.92	1.98
query20	0.02	0.01	0.01
query21	15.45	0.22	0.14
query22	4.86	0.05	0.05
query23	16.13	0.31	0.12
query24	2.90	0.40	0.34
query25	0.10	0.05	0.05
query26	0.73	0.20	0.15
query27	0.05	0.03	0.03
query28	3.54	0.77	0.37
query29	12.53	4.01	3.20
query30	0.28	0.15	0.15
query31	2.77	0.57	0.32
query32	3.22	0.59	0.49
query33	3.17	3.11	3.17
query34	15.53	3.91	3.29
query35	3.27	3.23	3.27
query36	0.56	0.44	0.43
query37	0.09	0.07	0.06
query38	0.05	0.04	0.04
query39	0.04	0.03	0.03
query40	0.18	0.15	0.14
query41	0.08	0.04	0.03
query42	0.04	0.03	0.03
query43	0.04	0.04	0.04
Total cold run time: 96.17 s
Total hot run time: 24.09 s

@hello-stephen

Copy link
Copy Markdown
Contributor

FE UT Coverage Report

Increment line coverage 100.00% (4/4) 🎉
Increment coverage report
Complete coverage report

@linrrzqqq

Copy link
Copy Markdown
Collaborator Author

run buildall

@hello-stephen

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

------ Round 1 ----------------------------------
============================================
q1	17694	3917	3831	3831
q2	2307	348	288	288
q3	9996	1433	792	792
q4	4678	475	355	355
q5	7501	833	555	555
q6	184	176	139	139
q7	747	820	596	596
q8	9329	1626	1609	1609
q9	5500	4196	4202	4196
q10	6738	1647	1348	1348
q11	438	277	243	243
q12	631	419	292	292
q13	18046	2617	1982	1982
q14	260	260	237	237
q15	q16	721	716	658	658
q17	1745	1131	1095	1095
q18	6528	5626	5527	5527
q19	1364	1211	1076	1076
q20	507	390	265	265
q21	5950	2520	2451	2451
q22	431	349	295	295
Total cold run time: 101295 ms
Total hot run time: 27830 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	4213	4131	4098	4098
q2	748	571	565	565
q3	4534	4890	4356	4356
q4	2255	2298	1424	1424
q5	4254	4146	4104	4104
q6	233	179	131	131
q7	1709	1607	1416	1416
q8	2474	2218	2187	2187
q9	7531	7512	7685	7512
q10	4307	4253	3876	3876
q11	551	443	361	361
q12	739	748	499	499
q13	2511	2778	2190	2190
q14	284	320	273	273
q15	q16	691	720	637	637
q17	7818	7159	7004	7004
q18	11907	11142	11749	11142
q19	1161	1052	1072	1052
q20	2231	2207	1936	1936
q21	5737	4705	4908	4705
q22	531	497	410	410
Total cold run time: 66419 ms
Total hot run time: 59878 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-DS: Total hot run time: 153711 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 1997c423a77fef766b7cdc05a939d3d8b37c707a, data reload: false

query5	4319	613	453	453
query6	422	199	176	176
query7	4878	546	299	299
query8	318	175	166	166
query9	8814	3977	3944	3944
query10	474	314	251	251
query11	5786	2198	1971	1971
query12	151	102	100	100
query13	1245	568	400	400
query14	6530	4570	4216	4216
query14_1	3989	4001	3966	3966
query15	205	198	179	179
query16	1010	458	459	458
query17	936	675	547	547
query18	2424	458	344	344
query19	202	188	150	150
query20	109	103	106	103
query21	218	134	117	117
query22	13056	12963	12843	12843
query23	15524	14689	13983	13983
query23_1	14763	14507	14445	14445
query24	7780	1743	1225	1225
query24_1	1230	1236	1206	1206
query25	533	424	376	376
query26	1242	291	162	162
query27	2733	551	325	325
query28	4575	1960	1923	1923
query29	1048	565	436	436
query30	310	234	192	192
query31	877	743	625	625
query32	135	87	87	87
query33	500	307	236	236
query34	1205	1122	629	629
query35	705	722	652	652
query36	786	802	720	720
query37	148	95	84	84
query38	1839	1759	1693	1693
query39	691	692	666	666
query39_1	645	657	656	656
query40	220	113	93	93
query41	63	63	60	60
query42	90	85	86	85
query43	334	338	292	292
query44	1336	682	689	682
query45	182	172	164	164
query46	1048	1131	681	681
query47	1479	1490	1389	1389
query48	379	420	292	292
query49	585	397	286	286
query50	926	335	244	244
query51	10475	10392	10477	10392
query52	94	86	77	77
query53	241	256	182	182
query54	240	203	199	199
query55	76	77	68	68
query56	233	231	201	201
query57	1394	1471	1454	1454
query58	253	212	201	201
query59	1983	2036	1800	1800
query60	277	237	222	222
query61	133	149	180	149
query62	406	322	267	267
query63	217	180	175	175
query64	2882	983	844	844
query65	4020	3928	3966	3928
query66	1799	420	320	320
query67	19972	20145	19863	19863
query68	3174	1469	912	912
query69	399	294	268	268
query70	912	858	861	858
query71	302	236	213	213
query72	2915	2492	2148	2148
query73	826	765	410	410
query74	4609	4468	4303	4303
query75	2287	2280	1957	1957
query76	2309	1089	704	704
query77	359	389	297	297
query78	9136	9019	8448	8448
query79	1450	1221	716	716
query80	598	445	354	354
query81	467	276	232	232
query82	631	167	120	120
query83	356	270	244	244
query84	317	142	109	109
query85	843	472	399	399
query86	332	237	235	235
query87	1990	1987	1817	1817
query88	3613	2729	2693	2693
query89	345	288	248	248
query90	1930	176	179	176
query91	226	156	123	123
query92	99	90	88	88
query93	1505	1400	897	897
query94	538	333	297	297
query95	678	474	344	344
query96	1109	746	352	352
query97	2457	2437	2301	2301
query98	215	185	180	180
query99	728	721	611	611
Total cold run time: 241581 ms
Total hot run time: 153711 ms

@hello-stephen

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

query1	0.01	0.01	0.00
query2	0.09	0.05	0.04
query3	0.27	0.14	0.14
query4	1.61	0.14	0.14
query5	0.24	0.23	0.21
query6	1.15	0.96	0.91
query7	0.03	0.01	0.01
query8	0.05	0.03	0.04
query9	0.39	0.33	0.34
query10	0.55	0.52	0.54
query11	0.20	0.14	0.14
query12	0.18	0.14	0.14
query13	0.48	0.48	0.48
query14	0.95	0.95	0.94
query15	0.61	0.60	0.58
query16	0.32	0.30	0.30
query17	1.05	1.08	1.07
query18	0.21	0.20	0.20
query19	1.99	1.94	1.84
query20	0.02	0.01	0.02
query21	15.43	0.20	0.13
query22	4.87	0.06	0.05
query23	16.12	0.31	0.12
query24	2.97	0.44	0.33
query25	0.12	0.04	0.04
query26	0.73	0.20	0.14
query27	0.04	0.04	0.04
query28	3.54	0.77	0.36
query29	12.49	4.07	3.19
query30	0.28	0.16	0.16
query31	2.76	0.56	0.31
query32	3.22	0.60	0.49
query33	3.28	3.16	3.19
query34	15.48	3.94	3.28
query35	3.23	3.21	3.24
query36	0.57	0.43	0.43
query37	0.09	0.07	0.07
query38	0.06	0.04	0.04
query39	0.04	0.02	0.02
query40	0.18	0.15	0.14
query41	0.09	0.03	0.03
query42	0.04	0.03	0.03
query43	0.04	0.03	0.03
Total cold run time: 96.07 s
Total hot run time: 23.83 s

@hello-stephen

Copy link
Copy Markdown
Contributor

FE UT Coverage Report

Increment line coverage 100.00% (4/4) 🎉
Increment coverage report
Complete coverage report

@linrrzqqq

Copy link
Copy Markdown
Collaborator Author

/review

@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.

Automated review round completed against the verified exact head 1997c42 (base 04aa5a1).

No new materially distinct finding survived the complete changed-file review, two normal full-coverage scans, the dedicated risk scan, and the final sweep. I am not duplicating the existing inline findings: the malformed configured identity and external/JIT/email/exact-host matching concerns remain the applicable threads at CreateResourceInfo.java lines 82-83. The earlier access-denied MySQL error-code concern is addressed in this head with ERR_SPECIFIC_ACCESS_DENIED_ERROR, and the added test now asserts getMysqlErrorCode().

Critical checkpoint conclusions:

  • Goal and call chain: the AI-only gate runs after resource-type analysis and before ResourceMgr allocation/edit-log journaling; all user SQL creation and observer-to-master forwarding paths were traced. Non-AI, Azure-guess, storage-vault, replay, and internal paths are unaffected or intentionally outside the SQL gate.
  • Configuration and lifecycle: the new startup-only @ConfField follows ConfigBase loading; forwarded DDL executes on the master with the authenticated identity. No new concurrency, lifecycle, lock, persistence, FE-BE protocol, or compatibility defect was found.
  • Error handling and performance: the denial preserves an access-denied protocol code; no status is silently discarded, and the extra check is limited to AI resource validation.
  • Tests and isolation: the new tests restore Config and ConnectContext state in finally blocks, while TestWithFeService restores Env.accessManager per test. Coverage is validation-level; no builds or tests were run because this invocation is review-only, so conclusions are static-analysis evidence.
  • User focus: no additional user-provided focus points were supplied.

@HappenLee HappenLee 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.

LGTM

@HappenLee
HappenLee dismissed github-actions[bot]’s stale review September 18, 2026 09:54

Dismissing this blocking automated review at the maintainer request after reviewing the remaining findings and approving the current PR head. This dismissal does not mark the remaining findings as fixed.

@starocean999
starocean999 merged commit 979e053 into apache:master Sep 18, 2026
37 of 38 checks passed
@github-actions

Copy link
Copy Markdown
Contributor

PR approved by anyone and no changes requested.

@github-actions github-actions Bot added the approved Indicates a PR has been approved by one committer. label Sep 18, 2026
@github-actions

Copy link
Copy Markdown
Contributor

PR approved by at least one committer and no changes requested.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by one committer. dev/4.1.5-merged reviewed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants