INSERT语句返回策略违规(USING表达式)。

huangapple go评论52阅读模式
英文:

INSERT statement returns a policy violation (USING expression)

问题

我正在使用AWS Aurora Postgres 14(14.5),并创建了以下表格(借助Rust中的Diesel) ->

create table contacts (
    email TEXT NOT NULL,
    user_id TEXT NOT NULL,
    contact_data JSONB,
    user_groups TEXT[],
    tenant_groups TEXT[],
    tags TEXT[],
    PRIMARY KEY (email, user_id)
);

附带的策略 ->

ALTER TABLE contacts FORCE ROW LEVEL SECURITY;
CREATE POLICY select_contacts_policy ON contacts 
FOR SELECT
USING (user_id = current_setting('myapp.user_id'));
ALTER TABLE contacts ENABLE ROW LEVEL SECURITY;

CREATE POLICY insert_contacts_policy ON contacts 
FOR INSERT
WITH CHECK (true);
ALTER TABLE contacts ENABLE ROW LEVEL SECURITY;

在向此表插入新数据时,首先设置一个名为user_id的会话参数(一个字符串)(使用Diesel的sql_query函数) ->

sql_query(format!("SET SESSION myapp.user_id = '{}';", user_id)).execute(pg_conn)?;

然后,使用Diesel进行插入 ->

diesel::insert_into(contacts::table)
    .values(&contacts) // 一个自定义结构体
    .on_conflict((contacts::email, contacts::user_id))
    .do_update()
    .set(&contacts)
    .execute(pg_conn)?;

在这个查询之后,user_id会被恢复为默认值 ->

sql_query("SET SESSION myapp.user_id = -1;").execute(pg_conn)?;

Diesel函数调用转换为以下SQL查询(从postgres日志中获取) ->

INSERT INTO "contacts" ("email", "user_id", "contact_data", "user_groups", "tenant_groups", "tags") VALUES ($1, $2, $3, $4, $5, $6) ON CONFLICT ("email", "user_id") DO UPDATE SET "email" = $7, "user_id" = $8, "contact_data" = $9, "user_groups" = $10, "tenant_groups" = $11, "tags" = $12

运行此查询时,如果发生冲突并触发了更新分支,将会收到以下错误消息 ->

new row violates row-level security policy (USING expression) for table "contacts"

我在本地也有一个类似的Postgres安装(v 14.8),它能够正常进行插入操作,尽管没有多用户但模式相同。

额外的信息 ->

正在使用名为backend的不同用户进行此操作

访问权限 -> contacts表的访问权限快照

我尝试运行一个EXPLAIN ANALYZE查询并记录它,以查看错误发生在何处,但该查询在完成之前导致策略违规。如果我不使用ANALYZE标志运行它,它只会打印查询计划(但我想知道是什么导致了该违规)。

英文:

I am using AWS Aurora Postgres 14 (14.5) and have this table set-up (with the help of Diesel in Rust) ->

create table contacts (
    email TEXT NOT NULL,
    user_id TEXT NOT NULL,
    contact_data JSONB,
    user_groups TEXT[],
    tenant_groups TEXT[],
    tags TEXT[],
    PRIMARY KEY (email, user_id)
);

With policies ->

ALTER TABLE contacts FORCE ROW LEVEL SECURITY;
CREATE POLICY select_contacts_policy ON contacts 
FOR SELECT
USING (user_id = current_setting('myapp.user_id'));
ALTER TABLE contacts ENABLE ROW LEVEL SECURITY;

CREATE POLICY insert_contacts_policy ON contacts 
FOR INSERT
WITH CHECK (true);
ALTER TABLE contacts ENABLE ROW LEVEL SECURITY;

While inserting new data to this table, I first set a session parameter called user_id (a string) (using Diesel's sql_query function)->

sql_query(format!("SET SESSION myapp.user_id = '{user_id}';")).execute(pg_conn)?;

Then I insert using diesel ->

diesel::insert_into(contacts::table)
    .values(&contacts) # a custom struct
    .on_conflict((contacts::email, contacts::user_id))
    .do_update()
    .set(&contacts)
    .execute(pg_conn)?;

After this query, the user_id is reverted to a default ->

sql_query("SET SESSION myapp.user_id = -1;").execute(pg_conn)?;

The diesel function call translates to this SQL Query (got it from postgres logs) ->

INSERT INTO "contacts" ("email", "user_id", "contact_data", "user_groups", "tenant_groups", "tags") VALUES ($1, $2, $3, $4, $5, $6) ON CONFLICT ("email", "user_id") DO UPDATE SET "email" = $7, "user_id" = $8, "contact_data" = $9, "user_groups" = $10, "tenant_groups" = $11, "tags" = $12

Upon running this query, I get this error message when there is a conflict and the update branch is triggered ->

new row violates row-level security policy (USING expression) for table "contacts"

I have a somewhat similar (without multiple users but the same schema) postgres installation (v 14.8) on my local which is able to upsert without any issues.

Additional information ->

The user working on this is a different one called backend user

The access privileges -> Snapshot of access privileges for the contacts table

I tried to run an EXPLAIN ANALYZE query and log it to see where the error occurs but that query results in policy violation before completion. If I run without the ANALYZE flag, it just prints the query plan (but I want to know where and what is resulting in that violation)

答案1

得分: 2

问题出在 ON CONFLICT ... DO UPDATE 部分。一个简单的 INSERT 或者 INSERT ... ON CONFLICT DO NOTHING 将会成功。

你只能更新你能看到的行,也就是你具有 FOR SELECT 策略的行,正如文档所描述:

> [...] 需要 SELECT 权限的查询,比如 UPDATE,只能看到被 SELECT 策略允许的记录。

所以是 FOR SELECT 策略和(缺失的)FOR UPDATE 策略在这里引发了问题。这有点令人吃惊,因为可以争论只有在 INSERT 过程中出现冲突时才应该收到该错误。然而,要确定是否存在冲突,你已经需要能够从表中进行 SELECT。添加一个 FOR SELECT 策略将使语句在没有冲突时成功执行。如果确实存在冲突,你需要额外的 FOR UPDATE 策略。

你需要添加允许插入角色无条件更新和选择的策略:

CREATE POLICY inserter_may_select ON contacts FOR SELECT TO inserter
   USING (TRUE);
CREATE POLICY inserter_may_update ON contacts FOR UPDATE TO inserter
   USING (TRUE);
英文:

The problem here is the ON CONFLICT ... DO UPDATE. A plain INSERT or an INSERT ... ON CONFLICT DO NOTHING would succeed.

You can only update rows that you can see, that is, rows for which you have a FOR SELECT policy, as the documentation describes:

> [...] queries that require SELECT permissions, such as UPDATE, will also only see those records that are allowed by the SELECT policy.

So it is the FOR SELECT policy and the (missing) FOR UPDATE policy that give you trouble here. This is somewhat surprising, since one could argue that you should only get that error if there is a conflict during the INSERT. However, to determine whether there is a conflict or not, you already need to be able to SELECT from the table. Adding a FOR SELECT policy would make the statement succeed if there is no conflict. If there is a conflict, you need an additional FOR UPDATE policy.

You'll have to add policies that allow the inserting role unconditional updates and selects:

CREATE POLICY inserter_may_select ON contacts FOR SELECT TO inserter
   USING (TRUE);
CREATE POLICY inserter_may_update ON contacts FOR UPDATE TO inserter
   USING (TRUE);

huangapple
  • 本文由 发表于 2023年6月6日 02:35:22
  • 转载请务必保留本文链接:https://go.coder-hub.com/76409149.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定