应用账号最小权限实践:读写账号、报表账号、运维账号分层

应用账号最小权限实践:读写账号、报表账号、运维账号分层

应用能连上数据库之后,很多团队为了省事,直接给应用用高权限账号。短期看问题少,长期风险很大:误删表、越权查询、测试代码写入生产、报表任务拖慢核心交易、审计时无法区分谁做了什么。

本文围绕金仓数据库应用接入,设计一套简单但实用的账号分层方案:应用读写账号、报表只读账号、运维管理账号分开使用,并通过最小权限控制降低风险。

@toc


一、为什么应用不能用高权限账号

其实啊。高权限账号的问题。不在于它"能做更多事"。那问题在哪呢?问题在于它让应用有了不该有的能力。咱们来看看:

  • 应用有漏洞的话。可能就被放大成数据库层级里的风险了。
  • 代码有 Bug。可能不小心把表给删了。
  • 报表 SQL 可能去访问一些敏感表。
  • 审计日志没法区分。哪个是业务访问。哪个是人工操作的。
  • 密码一旦泄漏。影响范围就太大了。

那么生产环境的应用账号。通常来说。应该只拥有业务跑起来需要的最小权限就行了。

二、账号分层设计

咱们来看个示例分层:

账号 用途 权限特点
app_user 业务应用读写 只访问业务 Schema 下必要表
report_user 报表和查询 只读权限
ops_user 运维检查 只允许查看必要状态和执行受控维护
管理员账号 建库、建用户、授权 不给应用配置使用

这篇咱们继续用第一篇已经建好的 kb_app。还有 shop。以及 app_user 和 report_user。如果你是直接看这篇的话。那你先回到第一篇。把基础库、账号还有测试表都弄好再说。

三、准备业务 Schema

连到业务库 kb_app 之后。咱们先看看业务 Schema 在不在:

sql 复制代码
SELECT schema_name
FROM information_schema.schemata
WHERE schema_name = 'shop';

要是没返回结果。那你就再执行这个:

sql 复制代码
CREATE SCHEMA shop;

接着咱们建一张商品表。专门用来演示权限的:

sql 复制代码
CREATE TABLE shop.t_product (
    product_id   INT PRIMARY KEY,
    product_name VARCHAR(100) NOT NULL,
    price        NUMERIC(12,2) NOT NULL,
    status       VARCHAR(20) NOT NULL,
    created_at   TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

插几条测试数据进去:

sql 复制代码
INSERT INTO shop.t_product(product_id, product_name, price, status)
VALUES
(1, 'keyboard', 199.00, 'ON_SALE'),
(2, 'mouse', 99.00, 'ON_SALE');

四、确认应用账号和报表账号

app_user 和 report_user 这俩。咱们在第一篇已经建过了。通常来说。在生产环境的情况里。建账号啊。密码多复杂啊。还有密码多久过期啊。这些都应该按企业层级里的安全规范来弄。我不建议每篇文章都去重复建同名账号。

五、授予 Schema 使用权限

你光给表权限其实还不够。账号还得能进到目标 Schema 里面去才行:

sql 复制代码
GRANT USAGE ON SCHEMA shop TO app_user;
GRANT USAGE ON SCHEMA shop TO report_user;

要是少了这个 Schema 使用权限的话。应用可能就会报对象不存在啊。或者权限不足这类的错。

六、给应用账号授予读写权限

sql 复制代码
GRANT SELECT, INSERT, UPDATE, DELETE
ON shop.t_product
TO app_user;

要是应用需要建点临时对象。或者要写更多表的话。那你应该一个表一个表地去评估。我不建议直接把整个数据库的高权限都给它。

咱们来验证一下:

sql 复制代码
-- 使用 app_user 连接后执行
SELECT * FROM shop.t_product;

INSERT INTO shop.t_product(product_id, product_name, price, status)
VALUES (3, 'monitor', 899.00, 'ON_SALE');

七、给报表账号授予只读权限

sql 复制代码
GRANT SELECT
ON shop.t_product
TO report_user;

验证一下:

sql 复制代码
-- 使用 report_user 连接后执行
SELECT * FROM shop.t_product;

接着咱们再试试往里写数据:

sql 复制代码
INSERT INTO shop.t_product(product_id, product_name, price, status)
VALUES (4, 'speaker', 299.00, 'ON_SALE');

这里它应该报权限错误。报错了才是正确的结果。这就说明只读的边界已经管用了。

八、新表权限怎么处理

很多团队都遇到过这个情况。应用账号对老表是有权限的。但是建了新表之后。应用一访问就失败了。那为什么会这样呢?原因在于啊。权限往往仅仅只授给了已经存在的对象。新对象它是不会自动继承权限的。

处理这个情况一般有两类办法。

第一类就是每次建完表。你手动去授权:

sql 复制代码
GRANT SELECT, INSERT, UPDATE, DELETE ON shop.新表名 TO app_user;
GRANT SELECT ON shop.新表名 TO report_user;

第二类是用 ALTER DEFAULT PRIVILEGES 这个东西。也就是让当前管理账号。在这个 Schema 下面。以后建的表。都自动授上指定的权限:

sql 复制代码
-- 以 system 账号连接 kb_app 后执行
ALTER DEFAULT PRIVILEGES IN SCHEMA shop
    GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO app_user;

ALTER DEFAULT PRIVILEGES IN SCHEMA shop
    GRANT SELECT ON TABLES TO report_user;

这里要注意一下哈。ALTER DEFAULT PRIVILEGES 这个命令。它只对执行这个命令的用户后面建的对象管用。对已经存在的表是没用的。也不影响别的账号建的表。通常来说。新环境初始化的时候跑一次就行了。后面建表就不用每次手动去授权了。

那么不管你用哪种方式。都要把"建表后授权"这个事。放到发布流程里去。在测试环境里。记得用应用的真实账号去验证一下权限到底生效没。

九、应用配置中使用低权限账号

开发环境里你可以这么配:

yaml 复制代码
spring:
  datasource:
    url: jdbc:kingbase8://192.168.10.101:54321/kb_app
    username: app_user
    password: App_user_123

报表系统呢。你就用这个:

yaml 复制代码
spring:
  datasource:
    url: jdbc:kingbase8://192.168.10.101:54321/kb_app
    username: report_user
    password: Report_user_123

千万别让报表系统去复用业务的写账号。这样的话。就算报表 SQL 写错了。它至少也不会直接把业务数据给改了。

十、权限排查常用 SQL

当应用提示权限不足的时候。你先确认一下当前的连接身份是谁:

sql 复制代码
SELECT current_database(), current_user;

接着确认一下对象在不在:

sql 复制代码
SELECT * FROM shop.t_product WHERE product_id = 1;

要是报错了。你就检查这几个方面:

  • 是不是连错数据库了。
  • SQL 里的 Schema 名写对了没。
  • 当前用户有没有 Schema 的使用权限。
  • 当前用户对目标表有没有权限。

权限这个问题啊。不要拿管理员账号测一下通了就算完事。你必须用应用的真实账号去验证。那才算数。

十一、账号安全建议

我建议大家这么来弄:

  • 不同的系统用不同的账号。
  • 不同的环境也用不同的账号。
  • 读写的账号和只读的账号一定要分开。
  • 给应用的账号。别给它建库、删库、还有超级权限这些。
  • 密码千万别写到代码仓库里去。
  • 有人离职了。或者项目下线了。系统迁移了。那账号要及时回收掉。
  • 定期去看看。有没有那种长期不用的账号。

十二、小结

其实搞最小权限。真不是为了给开发找麻烦。那是为了啥呢?是为了把事故的影响。控制在一个合理的范围里。应用读写账号。报表只读账号。运维账号。还有管理员账号。咱们分层来用。这样不管哪一层出了问题。损害都不会蔓延到别的层去。每次上线之前啊。用真实的应用账号去连一下。查一下。写一下。再测一下权限失败的情况。这都是必须要做的验收动作。

那么下一篇呢。咱们来整理个连接异常排障手册。把拒连啊。超时啊。认证失败啊。空闲断开这些问题。集中起来处理一下。

相关推荐
苦瓜打怪兽1 小时前
PostgreSQL 报错“字段 datlastsysoid 不存在”排查与解决
数据库·postgresql
XLYcmy1 小时前
PDF 论文处理器 — 技术报告文档
数据库·python·网络安全·pdf·embedding·dify·rag
ShineWinsu2 小时前
对于Redis:RDB持久化的解析
linux·数据库·redis·缓存·面试·持久化·rdb
做运维的阿瑞2 小时前
MYSQL从语义到执行计划:UNION、EXISTS、IN 的深度辨析
数据库·sql·mysql
Elastic 中国社区官方博客11 小时前
将你自己的密钥用于现有 Elastic Cloud 部署
大数据·数据库·elasticsearch·全文检索
红海云11 小时前
Jev:给智能系统做判断的模型
大数据·数据库·人工智能
wjkjpcba12 小时前
PCBA烧录程序是什么:PCBA包工包料厂家解析烧录与测试
linux·数据库·人工智能·smt贴片加工·pcba贴片加工厂
꯭自꯭闭꯭12 小时前
达梦事物特性及MVCC
linux·运维·数据库
小马同学-12 小时前
MySQL主从复制和读写分离
数据库·mysql