Skip to content

Commit 28662a5

Browse files
committed
sql: honour RLS policies during query-based backfill
Previously, schema changes that performed backfill operations from a query—such as those for materialized views (MQTs) or CREATE TABLE ... AS (CTAS)—executed the query as the node user. This user has administrative privileges and bypasses all Row-Level Security (RLS) policies, unintentionally exposing rows the originator of the change should not have been able to access. This change ensures that such query-based backfills run under the privileges of the user who initiated the schema change. As a result, RLS policies are correctly enforced, and only the rows visible to the initiating user are included in the result. Fixes #144816 Fixes #144776 Epic: CRDB-11724 Release note: none
1 parent 77ff853 commit 28662a5

File tree

2 files changed

+132
-1
lines changed

2 files changed

+132
-1
lines changed

pkg/sql/logictest/testdata/logic_test/row_level_security

Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2594,6 +2594,133 @@ DROP TABLE multip;
25942594
statement ok
25952595
DROP USER multi_user;
25962596

2597+
subtest ctas_and_mqt
2598+
2599+
# Test that RLS is enforced, even when users create CTAS and materialized views
2600+
2601+
statement ok
2602+
CREATE ROLE alice LOGIN;
2603+
2604+
statement ok
2605+
CREATE ROLE bob LOGIN;
2606+
2607+
statement ok
2608+
CREATE TABLE documents (
2609+
id INT PRIMARY KEY,
2610+
owner TEXT NOT NULL,
2611+
content TEXT NOT NULL
2612+
);
2613+
2614+
statement ok
2615+
INSERT INTO documents (id, owner, content) VALUES
2616+
(1, 'alice', 'Alice’s first document'),
2617+
(2, 'alice', 'Alice’s second document'),
2618+
(3, 'bob', 'Bob’s only document so far'),
2619+
(4, 'admin', 'Admin’s secret doc');
2620+
2621+
statement ok
2622+
GRANT ALL ON documents TO alice;
2623+
2624+
statement ok
2625+
GRANT ALL ON documents TO bob;
2626+
2627+
statement ok
2628+
GRANT CREATE ON SCHEMA public TO alice;
2629+
2630+
statement ok
2631+
GRANT CREATE ON SCHEMA public TO bob;
2632+
2633+
statement ok
2634+
ALTER TABLE documents ENABLE ROW LEVEL SECURITY;
2635+
2636+
statement ok
2637+
CREATE POLICY alice ON documents TO alice USING (owner = 'alice');
2638+
2639+
statement ok
2640+
CREATE POLICY bob ON documents TO bob USING (owner = 'bob');
2641+
2642+
statement ok
2643+
SET ROLE alice;
2644+
2645+
query ITT
2646+
SELECT * FROM documents ORDER BY ID;
2647+
----
2648+
1 alice Alice’s first document
2649+
2 alice Alice’s second document
2650+
2651+
statement ok
2652+
CREATE TABLE ctas1 AS SELECT * FROM documents;
2653+
2654+
query ITT
2655+
SELECT * FROM ctas1 ORDER BY ID;
2656+
----
2657+
1 alice Alice’s first document
2658+
2 alice Alice’s second document
2659+
2660+
statement ok
2661+
CREATE MATERIALIZED VIEW mqt_doc AS SELECT * FROM documents;
2662+
2663+
query ITT
2664+
SELECT * FROM mqt_doc ORDER BY ID;
2665+
----
2666+
1 alice Alice’s first document
2667+
2 alice Alice’s second document
2668+
2669+
statement ok
2670+
GRANT ALL ON ctas1 TO bob;
2671+
2672+
statement ok
2673+
RESET ROLE;
2674+
2675+
statement ok
2676+
ALTER TABLE mqt_doc OWNER TO bob;
2677+
2678+
statement ok
2679+
SET ROLE bob;
2680+
2681+
query ITT
2682+
SELECT * FROM documents ORDER BY ID;
2683+
----
2684+
3 bob Bob’s only document so far
2685+
2686+
query ITT
2687+
SELECT * FROM ctas1 ORDER BY ID;
2688+
----
2689+
1 alice Alice’s first document
2690+
2 alice Alice’s second document
2691+
2692+
query ITT
2693+
SELECT * FROM mqt_doc ORDER BY ID;
2694+
----
2695+
1 alice Alice’s first document
2696+
2 alice Alice’s second document
2697+
2698+
statement ok
2699+
REFRESH MATERIALIZED VIEW mqt_doc;
2700+
2701+
query ITT
2702+
SELECT * FROM mqt_doc ORDER BY ID;
2703+
----
2704+
3 bob Bob’s only document so far
2705+
2706+
statement ok
2707+
RESET ROLE;
2708+
2709+
statement ok
2710+
DROP TABLE ctas1;
2711+
2712+
statement ok
2713+
DROP MATERIALIZED VIEW mqt_doc;
2714+
2715+
statement ok
2716+
DROP TABLE documents;
2717+
2718+
statement ok
2719+
REVOKE CREATE ON SCHEMA public FROM bob, alice;
2720+
2721+
statement ok
2722+
DROP ROLE alice, bob;
2723+
25972724
subtest show_policies_edge_cases
25982725

25992726
statement error pq: relation "nonexistent_table" does not exist

pkg/sql/schema_changer.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -346,10 +346,14 @@ func (sc *SchemaChanger) backfillQueryIntoTable(
346346
sd.SessionData = *sc.sessionData
347347
// Create an internal planner as the planner used to serve the user query
348348
// would have committed by this point.
349+
//
350+
// Note: the planner is created using the session’s user. This is important
351+
// for row-level security (RLS), ensuring that the backfill query runs with
352+
// the same visibility and access restrictions as the user who initiated it.
349353
p, cleanup := NewInternalPlanner(
350354
opName,
351355
txn.KV(),
352-
username.NodeUserName(),
356+
sc.sessionData.User(),
353357
&MemoryMetrics{},
354358
sc.execCfg,
355359
sd,

0 commit comments

Comments
 (0)