2. 数据库身份与账号体系
在数据库访问控制中,“谁在访问”是所有权限判断的起点。数据库身份体系并不是简单地在数据库里建几个用户,而是要把人的身份、程序的运行身份、数据库内部的登录身份、以及权限集合这四层关系理清楚。很多权限失控的根因,不是授权给多了,而是身份从一开始就没有分层:应用直连用超级用户、运维共用一个账号、离职人员账号未回收、服务账号密码写死在配置文件里。本节围绕数据库用户、角色、服务账号、应用账号四类对象,讲清它们的定位、创建方式、映射关系与生命周期管理。
四类身份对象的定位
先明确四类对象的边界,避免混用:
- 数据库用户(User):数据库实例内真实存在的登录主体,拥有独立的认证凭据(密码、证书、外部认证映射等)。它是权限的最终承载者,所有授权最终都落到某个用户或它所属的角色上。
- 角色(Role):权限的集合容器,本身通常不直接用于登录(部分数据库允许角色登录,但治理上应避免)。角色分为功能角色(按职责打包权限,如只读角色、报表角色)和业务角色(按业务域划分,如订单库读写角色)。
- 服务账号(Service Account):代表某个系统组件或后台任务运行的身份,如备份程序、数据同步工具、监控采集器。它应具备最小权限、可审计、凭据可轮换。
- 应用账号(Application Account):代表业务应用连接数据库的身份,通常由应用通过连接池使用。它对应的是“应用”这一逻辑主体,而非某个自然人。
关键原则是:人用个人账号,程序用专用账号,权限通过角色授予,禁止共享账号。个人账号用于运维和排障,可追溯到具体人;应用和服务账号用于程序,凭据集中管理、定期轮换。
创建与映射关系
以常见的 PostgreSQL 为例,创建过程可以这样组织。先建角色,再建用户,最后把用户加入角色:
-- 1. 创建功能角色(不登录)
CREATE ROLE app_readonly NOLOGIN;
GRANT CONNECT ON DATABASE orderdb TO app_readonly;
GRANT USAGE ON SCHEMA public TO app_readonly;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO app_readonly;
-- 2. 创建应用账号并映射到角色
CREATE USER app_order_svc WITH PASSWORD '由密钥管理系统注入';
GRANT app_readonly TO app_order_svc;
-- 3. 创建服务账号(备份专用)
CREATE USER svc_backup WITH PASSWORD '由密钥管理系统注入';
GRANT pg_read_all_data TO svc_backup;
这里体现了“用户—角色—权限”的映射链:权限授予角色,角色授予用户,用户用于登录。应用账号 app_order_svc 不直接持有表级权限,而是通过 app_readonly 角色间接获得,这样调整权限时只需改角色,不必逐个改用户。
在 MySQL 中,用户与角色是分离的,需要显式激活角色:
CREATE ROLE 'app_readonly';
GRANT SELECT ON orderdb.* TO 'app_readonly';
CREATE USER 'app_order_svc'@'10.20.%' IDENTIFIED BY '...';
GRANT 'app_readonly' TO 'app_order_svc'@'10.20.%';
SET DEFAULT ROLE 'app_readonly' TO 'app_order_svc'@'10.20.%';
注意 'app_order_svc'@'10.20.%' 中的主机限制,这是把“应用账号”绑定到特定网段的重要手段,能显著缩小凭据泄露后的可利用范围。
生命周期管理的关键动作
身份不是建完就结束,生命周期管理才是治理的核心。可以按以下阶段组织:
申请与审批:任何账号创建都应有工单记录,明确申请人、用途、所需角色、有效期。应用账号和服务账号由系统负责人申请,个人账号由本人申请并经主管审批。
创建与映射:按“先角色后用户”的顺序创建,用户只授予角色,不直接授予对象权限。外部身份源(LDAP/OIDC)映射时,应把外部组映射到数据库角色,而不是逐个映射用户,减少维护量。
凭据管理:应用和服务账号的密码不应写在代码或配置文件中,应通过密钥管理系统(如 Vault、KMS)动态注入,并设置轮换周期。个人账号应启用强密码策略或多因素认证。
定期复核:每季度或每半年对账号和角色成员关系做一次复核,重点检查:长期未登录的账号、权限过大的角色、离职人员账号、共享账号。复核结果应记录并留痕。
停用与回收:人员离职或应用下线时,应在规定时限内锁定或删除账号,并回收其角色成员关系。删除前先确认没有其他依赖,避免影响正常业务。
一个可参考的账号登记表
为了让生命周期管理可执行,建议维护一份账号登记表,字段如下:
| 字段 | 说明 | 示例 |
|---|---|---|
| 账号名 | 数据库内唯一标识 | app_order_svc |
| 类型 | 个人/应用/服务 | 应用账号 |
| 归属系统 | 所属应用或组件 | 订单服务 |
| 绑定角色 | 授予的角色列表 | role_app_readonly |
| 来源主机 | 允许连接的网段 | 10.20.% |
| 凭据方式 | 密码/证书/外部认证 | Vault 动态密码 |
| 有效期 | 账号或凭据的有效期 | 2025-12-31 |
| 复核周期 | 下次复核时间 | 每季度 |
| 状态 | 启用/停用/待回收 | 启用 |
这张表既是运维台账,也是审计依据。每次创建、变更、回收都更新它,就能把身份体系从“建了就不管”变成“全程可追踪”。
总结来看,数据库身份体系的核心是分层与映射:自然人、应用、服务组件对应不同的账号类型,账号通过角色获得权限,角色按职责打包。创建时遵循“先角色后用户、只授角色不授对象”,运行中做好凭据轮换与定期复核,结束时及时停用回收。把这条链路管住,后续的权限治理才有稳定的基础。