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

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

深夜的那通电话

凌晨两点,手机响了。

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

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

perl 复制代码
FATAL: no sys_hba.conf entry for host "10.207.88.101"

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

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

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

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

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

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

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

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

一个真实的权限设计案例

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

sql 复制代码
-- 先建三个基础角色
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就完事。

金仓特有的权限查看命令

sql 复制代码
-- 看用户属于哪些角色组
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 文件格式长什么样

sql 复制代码
# TYPE  DATABASE  USER    ADDRESS       METHOD
host    all       all     192.168.1.0/24  scram-sha-256

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

金仓支持的认证方式

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

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

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

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

css 复制代码
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不在列表里。

加上就好了:

css 复制代码
host    all    all    10.207.88.101/32   scram-sha-256

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

sql 复制代码
SELECT sys_reload_conf();

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

改了配置为什么不生效?

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

sql 复制代码
-- SQL里执行
SELECT sys_reload_conf();
bash 复制代码
# 命令行执行
sys_ctl reload -D $KINGBASE_DATA

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

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

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

3.1 常用监控查询

sql 复制代码
-- 看当前所有活跃的查询
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参数的作用,默认留了几个槽位给超级用户,就是为了这种紧急情况。

先看连接数:

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

再看会话状态分布:

sql 复制代码
SELECT state, count(*) FROM sys_stat_activity GROUP BY state;

结果:

state 数量
idle in transaction 285
active 12
idle 3

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

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

sql 复制代码
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分钟。联系开发排查,发现那个模块在某个异常分支里忘了关闭事务。

怎么处理

先杀僵尸会话恢复业务:

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

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

sql 复制代码
ALTER SYSTEM SET idle_in_transaction_session_timeout = '10min';
SELECT sys_reload_conf();

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

3.3 金仓杀会话的两种方式

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

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

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

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

4.1 先看当前值

sql 复制代码
-- 最常用
SHOW max_connections;

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

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

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

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

4.2 改之前先算算内存

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

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

加起来每个连接约17.3KB。

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

4.3 改的正确姿势

sql 复制代码
-- 方法一: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 快速查看权限配置

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

5.2 查看当前HBA规则

sql 复制代码
SELECT type, user_name, address, auth_method
FROM sys_hba_file_rules
ORDER BY user_name;

5.3 监控连接数变化

sql 复制代码
-- 每分钟记录一次连接数
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。改完不生效,先检查这里。


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

相关推荐
金銀銅鐵7 小时前
[Java] 用 GUI 展示 EnumSet 增减元素时的内部变化(上)
java·后端·ai编程
念何架构之路8 小时前
go-grpc设计思想
开发语言·后端·golang
system_error_x8 小时前
SpringBoot 集成 Thymeleaf 简洁入门
java·spring boot·后端
步行cgn10 小时前
Spring MVC 视图机制的核心接口与类
java·开发语言·后端·spring·mvc
码事漫谈11 小时前
AI 读你的提示词,其实很没耐心
后端
用户83562907805111 小时前
如何使用 Python 格式化 Excel 单元格中的长文本
后端·python
我命由我1234512 小时前
Python 开发 - Python 的 pathlib
java·开发语言·后端·python·学习·java-ee·学习方法
IT_陈寒12 小时前
Java性能优化完全指南
前端·人工智能·后端
电子IT笔记12 小时前
对接群晖NAS,上传和删除踩坑记录
前端·后端
Mk5987812 小时前
P4:把 Agent 的记忆搬进 Redis —— AgentScope-Java 工程化实战
后端