一个权限配置错误引发的“血案”:数据库访问控制手记

0 阅读7分钟

一个权限配置错误引发的“血案”:金仓数据库访问控制手记

深夜的那通电话

凌晨两点,手机响了。

值班同事声音发紧:“大哥,金仓核心交易库连不上了,应用那边在报‘no sys_hba.conf entry’,这是什么意思?”

我一边穿衣服一边让他把详细报错发过来。截图上的信息很明确:

FATAL: no sys_hba.conf entry for host "10.207.88.101"

这是个典型的访问控制配置遗漏问题。新上线的应用服务器IP没加到白名单里,金仓数据库直接把连接请求拒了。

加一行配置、重载、业务恢复,前后不到五分钟。但这件事让我意识到,很多DBA对金仓这套访问控制机制的理解,还停留在“照着文档配一下”的阶段。

一、用户和角色:别把这两个概念搞混了

先从一个常见的认知误区说起。

刚接触金仓数据库的时候,我一直没搞明白USER和ROLE到底有什么区别。后来才弄懂:在金仓里,用户就是能登录的角色

-- 这两条语句干的是同一件事
CREATE USER fin_app WITH PASSWORD 'app123';
CREATE ROLE fin_app WITH LOGIN PASSWORD 'app123';

区别只有一个:USER默认带LOGIN权限,ROLE默认不带。

这个设计其实挺巧妙的。你可以用ROLE定义一组权限(比如“只读组”、“读写组”),然后用USER创建具体的人,再把权限组赋给用户。这样改权限的时候,只需要改ROLE,所有继承这个角色的用户自动跟着变。

一个真实的权限设计案例

去年做的一个金融系统,权限结构是这么搭的:

-- 先建三个基础角色
CREATE ROLE read_only;      -- 只能查
CREATE ROLE read_write;     -- 能查能改
CREATE ROLE app_admin;      -- 管理员

-- 给角色授权
GRANT SELECT ON ALL TABLES IN SCHEMA public TO read_only;
GRANT INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO read_write;
GRANT CREATE, DROP ON ALL TABLES IN SCHEMA public TO app_admin;

-- 创建用户并分配角色
CREATE USER fin_app WITH PASSWORD 'app123';
GRANT read_write TO fin_app;

CREATE USER report_user WITH PASSWORD 'report456';
GRANT read_only TO report_user;

CREATE USER dba_zhang WITH PASSWORD 'dba789' CREATEDB;
GRANT app_admin TO dba_zhang;

这样做的好处很明显:后来报表系统需要增加一个临时账号,直接CREATE USER然后GRANT read_only就行,不用再重新授权。权限收回来也方便,一条REVOKE就完事。

金仓特有的权限查看命令

-- 看用户属于哪些角色组
SELECT r.rolname, m.rolname as member_of
FROM sys_roles r
JOIN sys_auth_members am ON r.oid = am.member
JOIN sys_roles m ON am.roleid = m.oid;

-- 看某个表上谁有什么权限
SELECT grantee, privilege_type 
FROM information_schema.role_table_grants 
WHERE table_name = 'accounts';

-- 列级权限:只给特定字段(金仓支持到列级别的精细控制)
GRANT SELECT (id, name) ON hr.employees TO report_user;
-- salary字段没给,报表用户查不到工资信息

关于金仓超级用户的提醒

金仓数据库的默认超级用户是system,这个账号能绕过所有权限检查。有几个原则建议遵守:

  • 应用程序连接绝对不能用超级用户
  • 日常运维也尽量使用普通管理员账户
  • 超级用户的密码要定期更换、严格保管

二、连接控制:谁才能进门

说完“进来后能干什么”,再说“谁才能进来”。金仓通过s alt="sys_hba.conf文件来控制客户端访问权限。

2.1 文件格式长什么样

# TYPE  DATABASE  USER    ADDRESS       METHOD
host    all       all     192.168.1.0/24  scram-sha-256

每行五个字段:连接类型、数据库名、用户名、来源地址、认证方式。

金仓支持的认证方式

方式说明什么时候用
trust不需要密码本地维护用,生产环境千万别开
scram-sha-256SCRAM加密认证生产环境首选,金仓默认推荐
md5MD5加密老系统兼容
sm3国密SM3认证国密合规场景
reject直接拒绝封IP用的

2.2 那次差点出事的配置遗漏

回到开头的那个案例。新上线的报销系统连不上金仓数据库,报错说找不到对应的sys_hba.conf记录。

登录服务器一看,配置文件里只有老系统的IP:

host    all    all    10.207.88.50/32    scram-sha-256
host    all    all    10.207.88.51/32    scram-sha-256

新服务器10.207.88.101不在列表里。

加上就好了:

host    all    all    10.207.88.101/32   scram-sha-256

然后执行重载让金仓重新读取配置:

SELECT sys_reload_conf();

业务恢复。事后我补了个检查清单:每次新服务器上线,必须确认DBA知道、网络通了、白名单加了。

改了配置为什么不生效?

金仓的sys_hba.conf改了之后必须重载。两种方式:

-- SQL里执行
SELECT sys_reload_conf();
# 命令行执行
sys_ctl reload -D $KINGBASE_DATA

重载不会中断现有连接,只对新连接生效。

三、会话监控:看看连接都在干什么

连接进来了,怎么知道它们在干什么?金仓的sys_stat_activity视图就是干这个的。

3.1 常用监控查询

-- 看当前所有活跃的查询
SELECT pid, usename, client_addr, state, query
FROM sys_stat_activity
WHERE state = 'active';

state字段很关键:

  • active:正在执行SQL
  • idle:闲着,等新命令
  • idle in transaction:事务开了没提交——这个状态要警惕

3.2 那次连接池被占满的事故

有天下午业务高峰,金仓数据库监控突然告警:大量支付请求失败。

DBA试着登录,竟然连上了——因为金仓为超级用户保留了专用通道。这是superuser_reserved_connections参数的作用,默认留了几个槽位给超级用户,就是为了这种紧急情况。

先看连接数:

SELECT count(*) FROM sys_stat_activity;
-- 300,达到了金仓max_connections的上限

再看会话状态分布:

SELECT state, count(*) FROM sys_stat_activity GROUP BY state;

结果:

state数量
idle in transaction285
active12
idle3

285个连接挂着事务不提交也不回滚。这比单纯连接满更麻烦——它们可能还拿着锁,会堵住别人的操作。

查一下这些连接是谁的、挂了多久:

SELECT pid, usename, application_name, 
       now() - xact_start as duration, query
FROM sys_stat_activity 
WHERE state = 'idle in transaction' 
ORDER BY duration DESC;

发现都来自一个第三方支付模块,大部分事务已经挂起超过30分钟。联系开发排查,发现那个模块在某个异常分支里忘了关闭事务。

怎么处理

先杀僵尸会话恢复业务:

SELECT sys_terminate_backend(pid)
FROM sys_stat_activity
WHERE state = 'idle in transaction'
AND now() - state_change > interval '3 minutes';

然后设置金仓的自动清理参数,防止以后再发生:

ALTER SYSTEM SET idle_in_transaction_session_timeout = '10min';
SELECT sys_reload_conf();

这个参数的意思是:事务空闲超过10分钟,金仓自动把它终止掉。

3.3 金仓杀会话的两种方式

-- 温和版:取消当前查询,但不断开连接
SELECT sys_cancel_backend(pid);

-- 暴力版:直接断开连接
SELECT sys_terminate_backend(pid);

一般先试温和版,不行再用暴力版。

四、max_connections:这个参数在金仓里怎么调

4.1 先看当前值

-- 最常用
SHOW max_connections;

-- 想看详细信息
SELECT name, setting, context, pending_restart 
FROM sys_settings 
WHERE name = 'max_connections';

context字段告诉你改完要不要重启:

  • postmaster:必须重启
  • sighup:重载就行
  • user:会话里直接set

金仓的max_connectionspostmaster级别,改完必须重启数据库。

4.2 改之前先算算内存

根据金仓官方文档,每个连接大概消耗的内存:

  • 连接本身:约400字节
  • 锁空间:每个连接默认64个锁,每个锁约270字节

加起来每个连接约17.3KB。

500个连接就是8.6MB,2000个连接约34.6MB。这个数字其实不大,真正的内存大户是金仓的shared_bufferswork_mem

4.3 改的正确姿势

-- 方法一:ALTER SYSTEM(金仓推荐)
ALTER SYSTEM SET max_connections = 500;

-- 方法二:改配置文件
-- vi $KINGBASE_DATA/kingbase.conf
-- max_connections = 500

-- 改完必须重启金仓数据库
sys_ctl restart -D $KINGBASE_DATA

-- 验证
SHOW max_connections;

一个金仓特有的坑ALTER SYSTEM会把配置写进kingbase.auto.conf,这个文件的优先级比kingbase.conf高。如果你改了kingbase.conf发现不生效,检查一下auto.conf是不是有相同的参数。

4.4 什么时候该改,什么时候不该改

该改的情况

  • 业务增长,连接数确实不够了
  • 压测验证过,服务器资源扛得住

不该改的情况

  • 连接被僵尸会话占满了——先清理会话,别急着扩
  • 偶尔的并发峰值——应该用连接池缓冲,不是无限扩容
  • 内存本来就不够——加了参数可能导致金仓起不来

那次连接池占满的事故,事后我们评估了一下:300的连接数其实够用,问题是285个被无效占用了。加了金仓的idle_in_transaction_session_timeout自动清理之后,再也没出过问题。

五、金仓运维中积累的几个小工具

5.1 快速查看权限配置

-- 所有可登录用户及其权限
SELECT rolname, rolcanlogin, rolsuper, rolcreatedb
FROM sys_authid 
WHERE rolcanlogin = true 
ORDER BY rolname;

5.2 查看当前HBA规则

SELECT type, user_name, address, auth_method
FROM sys_hba_file_rules
ORDER BY user_name;

5.3 监控连接数变化

-- 每分钟记录一次连接数
SELECT now(), count(*) FROM sys_stat_activity;

六、金仓数据库访问控制踩坑总结

这些年用金仓数据库,在这些方面踩过的坑,总结几条:

1. 权限设计要从一开始就做

等项目上线了再补权限,开发已经把所有代码写成用超级用户连接,改起来代价极大。接手新项目第一件事,先把金仓的权限结构搭好。

2. sys_hba.conf改了要重载

这条看着简单,但每次故障复盘都会发现有人忘了这步。金仓的SELECT sys_reload_conf()是常用命令,建议写在配置文件的注释里。

3. 监控idle in transaction

这个状态是金仓连接池的隐形杀手。设置idle_in_transaction_session_timeout是性价比最高的防御手段。

4. 超级用户的保留通道不能丢

金仓的superuser_reserved_connections默认值通常是3,别把它改成0。关键时刻能不能登录进去,就靠这个参数了。

5. 参数改之前先看context

金仓的max_connections是postmaster级别的参数,改了要重启。生产环境调整这类参数,需要提前申请变更窗口。

6. 优先级问题

金仓的ALTER SYSTEM写的kingbase.auto.conf优先级高于kingbase.conf。改完不生效,先检查这里。


金仓数据库的访问控制体系说复杂也复杂,说简单也简单。无非就是三件事:谁可以进来、进来后能干什么、出了问题怎么处理。把这三点理清楚,大部分问题都能迎刃而解。