Redshift中配置RLS策略后用户查询出现权限拒绝错误的求助
Redshift中配置RLS策略后用户查询出现权限拒绝错误的求助
最近我在Amazon Redshift里给员工表配置行级安全(RLS),想实现普通用户只能查看自己被授权的数据,权限规则存在单独的access_ctl表中。按照自己的思路配置完后,用户查询时却抛出了权限拒绝的错误,折腾了好一阵才解决,现在把问题和方案整理出来。
我的场景与配置步骤
我创建了两个核心表:rls_demo.ep是员工数据主表,rls_demo.access_ctl是权限控制表,用来定义每个用户能访问的员工数据范围。
1. 管理员创建Schema与基础表
首先创建测试用的Schema和表,插入测试数据:
-- 创建测试Schema CREATE SCHEMA IF NOT EXISTS rls_demo; -- 创建员工数据表 CREATE TABLE rls_demo.ep ( id INT, division VARCHAR(255), region VARCHAR(255), work_location_country VARCHAR(256) ); -- 插入测试员工数据 INSERT INTO rls_demo.ep VALUES (1,'SALES',NULL,'USA'), (2,NULL,'North America','CAN'), (3,'SERVICE','North America','USA'); -- 创建权限控制表 CREATE TABLE rls_demo.access_ctl ( rule_id INT IDENTITY(1,1), username VARCHAR(100), division VARCHAR(255), region VARCHAR(255), work_location_country VARCHAR(256), full_access BOOLEAN DEFAULT FALSE ); -- 给测试用户ta1配置权限:只能访问工作地点为CAN的数据 INSERT INTO rls_demo.access_ctl (username, division, region, work_location_country, full_access) VALUES ('ta1', NULL, NULL, 'CAN', FALSE);
2. 配置RLS策略与角色权限
接下来我尝试创建RLS策略,启用表的RLS,并给用户分配访问角色:
-- 最初写的错误RLS策略(不符合Redshift语法) CREATE RLS POLICY policy_ep_demo WITH (division VARCHAR(255), region VARCHAR(255), work_location_country VARCHAR(256)) AS ep USING ( EXISTS ( SELECT 1 FROM rls_demo.access_ctl ac WHERE ac.username = current_user AND ( ac.full_access = TRUE OR ( (ac.division IS NULL OR ac.division = ep.division) AND (ac.region IS NULL OR ac.region = ep.region) AND (ac.work_location_country IS NULL OR ac.work_location_country = ep.work_location_country) ) ) ) ); -- 启用员工表的行级安全 ALTER TABLE rls_demo.ep ROW LEVEL SECURITY ON; -- 创建访问角色并关联RLS策略 CREATE ROLE rls_demo_role; ATTACH RLS POLICY policy_ep_demo ON rls_demo.ep TO ROLE rls_demo_role; -- 给测试用户ta1分配访问角色 GRANT ROLE rls_demo_role TO ta1; -- 授权角色访问Schema与表 GRANT USAGE ON SCHEMA rls_demo TO role rls_demo_role; GRANT SELECT ON rls_demo.ep TO role rls_demo_role; GRANT SELECT ON rls_demo.access_ctl TO role rls_demo_role;
遇到的问题
当用户ta1执行以下查询时:
SELECT DISTINCT work_location_country FROM rls_demo.ep;
直接抛出了权限错误:
SQL Error [42501]: ERROR: permission denied to rls policy for relation access_ctl
问题分析与解决
1. 首要问题:RLS策略语法不符合Redshift规范
我一开始写的RLS策略用了WITH (...) AS ep的参数定义方式,这是套了其他数据库的RLS语法,Redshift根本不支持这种写法,这是第一个踩的坑。
2. 核心原因:RLS策略无法访问权限控制表
错误的核心是RLS策略在执行时没有权限访问access_ctl表。这里有两种解决思路:
- 推荐思路:使用
SECURITY DEFINER创建RLS策略,让策略以管理员身份访问access_ctl表,避免普通用户直接接触权限控制表,提升安全性 - 备选思路:确保普通用户通过角色拥有
access_ctl的SELECT权限(我虽然做了这一步,但语法错误导致依然报错)
修正后的完整配置
首先删除之前的错误策略:
DROP RLS POLICY IF EXISTS policy_ep_demo ON rls_demo.ep;
然后创建符合Redshift语法的RLS策略,使用SECURITY DEFINER:
CREATE RLS POLICY policy_ep_demo ON rls_demo.ep USING ( EXISTS ( SELECT 1 FROM rls_demo.access_ctl ac WHERE ac.username = current_user AND ( ac.full_access = TRUE OR ( (ac.division IS NULL OR ac.division = ep.division) AND (ac.region IS NULL OR ac.region = ep.region) AND (ac.work_location_country IS NULL OR ac.work_location_country = ep.work_location_country) ) ) ) ) SECURITY DEFINER;
接着重新启用RLS并关联角色(如果之前没配置完成的话):
ALTER TABLE rls_demo.ep ROW LEVEL SECURITY ON; ATTACH RLS POLICY policy_ep_demo ON rls_demo.ep TO ROLE rls_demo_role;
最后可以收回普通用户对access_ctl的直接访问权限(因为用了SECURITY DEFINER,策略会以管理员身份访问该表):
REVOKE SELECT ON rls_demo.access_ctl FROM role rls_demo_role;
验证结果
现在用户ta1再执行之前的查询,就能正常返回预期结果了:
SELECT DISTINCT work_location_country FROM rls_demo.ep; -- 预期返回结果:CAN
额外提醒
SECURITY DEFINER是个很实用的选项,能避免普通用户直接接触权限控制表,大大提升数据安全性- 权限匹配逻辑是没问题的:如果用户有
full_access = TRUE就能查看所有数据,否则按division/region/work_location_country的非空条件匹配数据
内容来源于stack exchange
相关产品推荐
相关产品推荐

