一、为什么表权限还不够#
普通权限控制的是:
例如:
1
| GRANT SELECT ON sales.orders TO report_user;
|
这表示 report_user 可以查询 sales.orders。
但很多企业场景需要更细的控制:
1
2
3
4
5
| 销售只能看自己区域的订单
医生只能看本科室病人的记录
租户只能访问自己的数据
分公司只能看本公司的财务数据
客服只能看被分配给自己的工单
|
这些不是“能不能访问表”的问题,而是:
这就需要 PostgreSQL 的 RLS。
二、RLS 是什么#
RLS 是 Row Level Security,行级安全。
表级权限控制:
RLS 控制:
例如 orders 表中有字段:
1
2
3
| tenant_id
department_id
owner_user
|
RLS 可以根据当前会话、当前用户或应用设置的上下文,只返回符合条件的行。
三、RLS 基本示例#
示例表:
1
2
3
4
5
6
| CREATE TABLE sales.orders (
id bigint PRIMARY KEY,
tenant_id text NOT NULL,
order_no text NOT NULL,
amount numeric(12,2) NOT NULL
);
|
启用 RLS:
1
| ALTER TABLE sales.orders ENABLE ROW LEVEL SECURITY;
|
创建策略:
1
2
3
4
5
6
| CREATE POLICY tenant_select_policy
ON sales.orders
FOR SELECT
USING (
tenant_id = current_setting('app.current_tenant')
);
|
这表示查询 sales.orders 时,只能看到:
1
| tenant_id = 当前会话 app.current_tenant
|
应用连接数据库后设置:
1
| SET app.current_tenant = 'tenant_001';
|
再查询:
1
| SELECT * FROM sales.orders;
|
只能看到 tenant_001 的数据。
四、RLS 的 USING 和 WITH CHECK#
RLS 策略中常见两个条件:
1
2
| USING:控制哪些已有行可见或可操作
WITH CHECK:控制新写入或更新后的行是否允许存在
|
查询策略:
1
2
3
4
| CREATE POLICY tenant_select_policy
ON sales.orders
FOR SELECT
USING (tenant_id = current_setting('app.current_tenant'));
|
插入策略:
1
2
3
4
| CREATE POLICY tenant_insert_policy
ON sales.orders
FOR INSERT
WITH CHECK (tenant_id = current_setting('app.current_tenant'));
|
更新策略:
1
2
3
4
5
| CREATE POLICY tenant_update_policy
ON sales.orders
FOR UPDATE
USING (tenant_id = current_setting('app.current_tenant'))
WITH CHECK (tenant_id = current_setting('app.current_tenant'));
|
含义:
1
2
| USING:只能更新自己租户原本可见的行
WITH CHECK:更新后 tenant_id 仍然必须是自己的租户
|
否则用户可能把自己的行改成别的租户,或插入不属于自己的数据。
五、RLS 和普通权限的关系#
RLS 不是替代表权限,而是叠加在表权限之上。
用户必须先有表权限:
1
| GRANT SELECT ON sales.orders TO app_user;
|
然后 RLS 再决定:
如果没有表权限,RLS 不会让用户凭空获得访问能力。
因此访问控制顺序可以理解为:
1
2
3
4
| 1. 是否能连接数据库
2. 是否能使用 schema
3. 是否有表权限
4. 是否通过 RLS 策略
|
六、RLS 注意事项#
RLS 很强,但使用时要注意:
1
2
3
4
5
| 1. 超级用户通常可以绕过 RLS
2. 表 owner 默认可能绕过 RLS,必要时使用 FORCE ROW LEVEL SECURITY
3. 策略条件要简单、稳定、可理解
4. 应用必须可靠设置会话上下文
5. 要避免连接池复用导致上下文串租户
|
强制 owner 也遵守 RLS:
1
| ALTER TABLE sales.orders FORCE ROW LEVEL SECURITY;
|
查看策略:
1
2
3
4
| SELECT *
FROM pg_policies
WHERE schemaname = 'sales'
AND tablename = 'orders';
|
关闭 RLS:
1
| ALTER TABLE sales.orders DISABLE ROW LEVEL SECURITY;
|
删除策略:
1
| DROP POLICY tenant_select_policy ON sales.orders;
|
如果使用连接池,必须确保每次请求都正确设置并清理上下文,例如:
1
| SET app.current_tenant = 'tenant_001';
|
或者在事务内使用:
1
| SET LOCAL app.current_tenant = 'tenant_001';
|
SET LOCAL 只在当前事务内有效,更适合连接池场景。
七、审计为什么重要#
权限设计解决的是:
审计解决的是:
企业环境中,以下操作通常需要审计:
- 创建、修改、删除表
- 创建、修改、删除用户
- 授权和回收权限
- 大批量更新和删除
- 访问敏感表
- 执行高危函数
- 登录失败
- 异常来源 IP 连接
没有审计,出问题后很难定位责任和影响范围。
八、pgAudit 基本思路#
PostgreSQL 常用审计扩展是 pgaudit。
通常需要在配置中加载:
1
| ALTER SYSTEM SET shared_preload_libraries = 'pgaudit';
|
然后重启 PostgreSQL。
创建扩展:
1
| CREATE EXTENSION pgaudit;
|
配置审计类型:
1
2
| ALTER SYSTEM SET pgaudit.log = 'ddl, write, role';
ALTER SYSTEM SET pgaudit.log_relation = on;
|
重新加载配置:
1
| SELECT pg_reload_conf();
|
常见审计类别:
1
2
3
4
5
6
| read:读操作
write:写操作
function:函数调用
role:角色和权限相关操作
ddl:DDL 操作
misc:其他杂项
|
实际生产中不要盲目打开所有审计,否则日志量可能非常大。
更推荐按系统重要性、合规要求和日志容量进行配置。
九、查看连接与活跃会话#
查看当前连接:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| SELECT
pid,
usename,
datname,
client_addr,
state,
application_name,
backend_start,
query_start,
wait_event_type,
wait_event,
query
FROM pg_stat_activity
ORDER BY query_start NULLS LAST;
|
排查异常连接时重点看:
1
2
3
4
5
6
| usename:用户
client_addr:客户端地址
application_name:应用名
state:连接状态
query_start:SQL 开始时间
query:正在执行的 SQL
|
可以要求应用配置明确的 application_name,方便定位来源。
十、密码安全#
建议使用 SCRAM-SHA-256:
1
2
| ALTER SYSTEM SET password_encryption = 'scram-sha-256';
SELECT pg_reload_conf();
|
之后新设置的密码会使用更安全的加密方式:
1
| ALTER ROLE app_user PASSWORD 'NewStrongPassword';
|
创建用户时设置有效期:
1
2
3
| CREATE USER report_user
WITH PASSWORD 'StrongPassword'
VALID UNTIL '2026-12-31';
|
临时禁用账号:
1
| ALTER ROLE report_user NOLOGIN;
|
恢复登录:
1
| ALTER ROLE report_user LOGIN;
|
十一、pg_hba.conf 认证控制#
PostgreSQL 的连接认证主要由 pg_hba.conf 控制。
典型格式:
1
| host database user address auth-method
|
示例:
1
| host sales_db app_user 10.0.0.0/8 scram-sha-256
|
表示:
1
| 允许 10.0.0.0/8 网段的 app_user 连接 sales_db,使用 scram-sha-256 认证。
|
更严格的 SSL 示例:
1
| hostssl all all 10.0.0.0/8 scram-sha-256
|
表示只允许 SSL 连接。
修改 pg_hba.conf 后需要 reload:
1
| SELECT pg_reload_conf();
|
或者使用系统命令 reload PostgreSQL 服务。
十二、证书认证#
安全要求更高的场景,可以使用客户端证书认证。
示例:
1
| hostssl all all 10.0.0.0/8 cert clientcert=verify-ca
|
含义:
1
2
3
| hostssl:必须使用 SSL
cert:使用客户端证书认证
clientcert=verify-ca:验证客户端证书由可信 CA 签发
|
证书认证适合:
- 企业内网服务间访问
- 金融、医疗等高合规场景
- 不希望只依赖密码的系统
- 固定服务身份认证
实际落地时需要配合服务端证书、客户端证书、CA、证书吊销和更新流程。
十三、权限问题排查清单#
当遇到:
可以按下面顺序排查。
确认角色:
1
2
3
| SELECT rolname, rolcanlogin, rolinherit
FROM pg_roles
WHERE rolname = 'app_user';
|
确认数据库连接权限:
1
| SELECT has_database_privilege('app_user', 'sales_db', 'CONNECT');
|
确认 schema 权限:
1
2
| SELECT has_schema_privilege('app_user', 'sales', 'USAGE');
SELECT has_schema_privilege('app_user', 'sales', 'CREATE');
|
确认表权限:
1
2
3
4
| SELECT has_table_privilege('app_user', 'sales.orders', 'SELECT');
SELECT has_table_privilege('app_user', 'sales.orders', 'INSERT');
SELECT has_table_privilege('app_user', 'sales.orders', 'UPDATE');
SELECT has_table_privilege('app_user', 'sales.orders', 'DELETE');
|
确认序列权限:
1
| SELECT has_sequence_privilege('app_user', 'sales.orders_id_seq', 'USAGE');
|
确认 RLS:
1
2
3
4
| SELECT *
FROM pg_policies
WHERE schemaname = 'sales'
AND tablename = 'orders';
|
确认当前会话上下文:
1
2
3
| SHOW search_path;
SELECT current_user;
SELECT session_user;
|
如果使用自定义上下文:
1
| SELECT current_setting('app.current_tenant', true);
|
十四、安全基线建议#
生产环境建议至少做到:
1
2
3
4
5
6
7
8
9
10
| 1. 应用不使用超级用户
2. 回收 public schema 对 PUBLIC 的 CREATE 权限
3. 按 schema 和角色组授权
4. 只读、读写、DDL、备份、监控账号分离
5. 高危权限定期审计
6. 使用 scram-sha-256
7. 合理配置 pg_hba.conf 来源网段
8. 重要系统启用审计
9. 多租户或敏感数据场景考虑 RLS
10. 连接池场景谨慎处理 SET/SET LOCAL 上下文
|
常用安全初始化:
1
2
3
| REVOKE CREATE ON SCHEMA public FROM PUBLIC;
ALTER SYSTEM SET password_encryption = 'scram-sha-256';
SELECT pg_reload_conf();
|
十五、总结#
PostgreSQL 的权限体系不仅包含普通的 GRANT 和 REVOKE,还可以进一步扩展到:
1
2
3
4
5
6
| RLS:控制行级数据可见性
pgAudit:记录关键操作
pg_hba.conf:控制连接来源和认证方式
密码策略:提高账号安全性
证书认证:增强服务身份可信度
权限审计:发现异常授权和高危账号
|
企业实践中,建议先建立清晰的角色和 schema 权限体系,再根据业务敏感度补充 RLS、审计和连接安全。
权限管理的最终目标不是“权限越多越方便”,而是:
1
2
3
4
| 该访问的人能访问
不该访问的人访问不了
做过什么操作能追溯
账号泄露或误操作时影响范围可控
|