pg_ident.conf 用户映射
pg_ident.conf 是 PostgreSQL 的用户名映射配置文件。它的作用只有一件事:当「操作系统用户名」与「数据库角色名」不一致时,告诉 PostgreSQL 它们之间的对应关系。文件本身很小,但它决定了 peer、ident、gss、sspi、cert 这几种外部认证方式能否真正落到正确的数据库角色上。理解它,是打通「操作系统身份 → 数据库身份」这一步的关键。
前置知识
阅读本节前,建议先了解:pg_hba.conf 客户端认证
基础概念
为什么需要用户映射
很多外部认证方式提供的是外部身份,而不是数据库角色名:
| 认证方式 | 提供的外部身份 | 是否通常需要映射 |
|---|---|---|
peer | Unix 域套接字的内核 UID 对应的 OS 用户名 | 需要(当 OS 用户名 ≠ 角色名) |
ident | 通过 ident 服务查询到的 OS 用户名 | 需要 |
gss / sspi | Kerberos / Windows 域主体名(如 user@REALM) | 几乎总是需要 |
cert | 客户端证书的 Common Name | verify-full 时不需要,verify-ca 时常需要 |
ldap | 通过 LDAP 属性映射的用户名 | 可选 |
客户端 PostgreSQL 数据库角色
┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ OS 用户 alice │──peer──▶│ 取出 "alice" │──映射查表──▶ │ 角色 appuser │
└──────────────┘ └──────────────┘ pg_ident.conf └──────────────┘
│
│ 若 HBA 没用 map= 或映射不匹配
▼
FATAL: Peer authentication failed
for user "alice"不加 map= 时的默认行为
如果没有指定 map=,PostgreSQL 会直接把外部用户名当作数据库角色名去匹配认证。所以:
- OS 用户
alice→ 需要存在角色alice,否则报role "alice" does not exist。 - Kerberos 主体
alice@EXAMPLE.COM→ 需要存在同名角色(含@,几乎不可能),必须用映射。
文件位置
SHOW ident_file;
-- /var/lib/postgresql/18/main/pg_ident.conf默认位于 PGDATA 目录,可通过 ident_file 参数(postmaster 上下文,需重启)改到别处。
三列格式
pg_ident.conf 每行三列,用空白分隔:
| 列 | 名称 | 说明 |
|---|---|---|
| 1 | MAPNAME | 映射名,与 pg_hba.conf 中的 map= 取值对应 |
| 2 | SYSTEM-USERNAME | 外部系统提供的用户名(可使用正则) |
| 3 | DATABASE-USERNAME | 要映射到的数据库角色名(\1 可引用正则捕获组) |
# MAPNAME SYSTEM-USERNAME PG-USERNAME
os_db_map alice alice
os_db_map deploy appuser
krb_map /^(.*)@EXAMPLE\.COM$ \1与 pg_hba.conf 的关系
两者是一对多的引用关系:一个 map= 名可以包含任意多行映射;一个映射名也可以被多条 HBA 规则引用。
pg_hba.conf pg_ident.conf
┌───────────────────────────┐ ┌────────────────────────────────────┐
│ local all postgres peer │ │ admins root postgres │
│ map=admins │───▶│ admins postgres postgres │
│ │ │ │
│ local all +app_users peer │ │ appmap deploy appuser │
│ map=appmap │───▶│ appmap ci appuser │
│ │ │ appmap jenkins appuser │
└───────────────────────────┘ └────────────────────────────────────┘同名映射名在文件中可以分散在多行,不必连续书写。
匹配后是否还需要角色存在
必须存在。 映射只解决「名字对应关系」,不创建角色。如果映射到 appuser 而该角色不存在,认证依然失败:
FATAL: role "appuser" does not exist所以「改 pg_ident.conf 让某人能登录」这个想法是不完整的——你还需要 CREATE ROLE。
语法与用法
基本格式
# 注释以 # 开头
# MAPNAME SYSTEM-USERNAME PG-USERNAME
mymap alice alice
mymap bob alice # 两个 OS 用户映射到同一个角色格式规则:
- 三列必填,用空白(空格或 Tab)分隔。
- 大小写敏感(与
postgresql.conf的参数名不同)。 - 支持
include/include_if_exists/include_dir指令(与postgresql.conf相同的语义)。 - 空行与注释行被忽略。
all 关键字
第三列(PG-USERNAME)支持 all,含义是「映射到与请求的数据库角色同名」:
# MAPNAME SYSTEM-USERNAME PG-USERNAME
mymap alice all # 数据库端请求谁,就以谁的身份认证all 加引号会失去特殊含义
官方文档明确提示:all 必须不加引号才具有关键字含义。写成 "all" 会被当作字面角色名 all。
# 正确:关键字
mymap alice all
# 错误!被当成字面角色名 "all"
mymap alice "all"all 的实用场景:一批外部用户各自对应同名的数据库角色,不需要逐个列举。
# 所有 EXAMPLE.COM 域用户,各自对应同名数据库角色
krb_map /^(.*)@EXAMPLE\.COM$ all注意此时 SYSTEM-USERNAME 是正则、PG-USERNAME 是 all,那么请求的角色名必须与完整的外部用户名匹配——这通常不是想要的。所以更常见的是配合捕获组:
# 把 alice@EXAMPLE.COM 映射到角色 alice
krb_map /^(.*)@EXAMPLE\.COM$ \1+role 前缀
第三列支持 +role 语法,表示「映射到某个角色的成员身份」检查:
# MAPNAME SYSTEM-USERNAME PG-USERNAME
mymap alice +app_users含义:外部用户 alice 被映射为「属于 app_users 角色的用户」。这常用于「外部身份只需属于某角色组即可登录」的场景。
正则与捕获组
第二列(SYSTEM-USERNAME)以 / 开头时按正则解释。第三列(DATABASE-USERNAME)中出现 \1、\2 等时,会替换为第二列正则的捕获组内容。
# 单个捕获组 + \1 引用
krb_map /^(.*)@EXAMPLE\.COM$ \1
# 多捕获组
host_map /^([a-z]+)_([a-z]+)$ \1
# 域后缀固定,只取用户名
mail_map /^([^@]+)@example\.com$ \1官方文档给出的示例(Example 20.2 风格),把 omicron 相关用户映射到不同角色:
# MAPNAME SYSTEM-USERNAME PG-USERNAME
omicron bryan bryan
omicron ann sales
omicron robert sales
omicron zoe sales
omicron /^.*@omicron\.com$ bob第三列用正则时不能引用 \1
官方明确规定:当 DATABASE-USERNAME 本身是正则表达式(以 / 开头)时,不能使用 \1 这类反向引用。 \1 只在第三列是普通角色名时才有捕获组替换语义。
# 合法:第三列是普通名,可引用 \1
good /^(.*)@EXAMPLE\.COM$ \1
# 不合法:第三列同时是正则又想引用 \1,行为不符合预期
bad /^(.*)@EXAMPLE\.COM$ /^db_\1$/include 机制
# 主文件
include 'ident.d/10_os_users.conf'
include_dir 'ident.d'
include_if_exists 'ident.d/99_local.conf'三者的语义与 postgresql.conf 完全一致:include 文件不存在会报错,include_if_exists 静默忽略,include_dir 只读 .conf 结尾、不以 . 开头的文件,按 C locale 排序。
pg_ident_file_mappings 视图
这是核验映射是否被正确解析的核心视图:
SELECT map_number, map_name, sys_name, pg_username, error
FROM pg_ident_file_mappings
ORDER BY map_number; map_number | map_name | sys_name | pg_username | error
------------+----------+-----------------------+-------------+-------
1 | os_db_map| alice | alice |
2 | os_db_map| deploy | appuser |
3 | krb_map | /^(.*)@EXAMPLE\.COM$ | \1 |解析失败的行只有 line_number 与 error 有值(map_number 为 NULL):
SELECT line_number, error FROM pg_ident_file_mappings WHERE error IS NOT NULL;修改后如何生效
pg_ident.conf 属于 sighup 级别,reload 即可:
pg_ctl reload -D /var/lib/postgresql/18/mainSELECT pg_reload_conf();详细说明
一、peer 认证 + 映射的完整链路
这是最常用的组合。假设服务器上有 OS 用户 deploy,但应用要连的数据库角色是 appuser,且要求免密(因为部署脚本以 deploy 用户运行)。
第一步,创建角色并授权:
CREATE ROLE appuser WITH LOGIN;
GRANT CONNECT ON DATABASE myapp TO appuser;
GRANT USAGE ON SCHEMA public TO appuser;
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO appuser;第二步,配置映射:
# pg_ident.conf
appmap deploy appuser第三步,在 HBA 中引用:
# pg_hba.conf
local myapp appuser peer map=appmap第四步,reload 并验证:
sudo -u deploy psql -d myapp -c "SELECT current_user, session_user;" current_user | session_user
--------------+--------------
appuser | appuser
(1 row)如果缺了 map=appmap,会得到:
$ sudo -u deploy psql -d myapp
FATAL: Peer authentication failed for user "deploy"排查 peer 认证失败
报 Peer authentication failed for user "X" 时,含义是「外部身份是 X,但没有匹配到规则/映射」:
- 检查 HBA 中该行的
map=是否指向了正确的映射名。 - 检查映射名在
pg_ident.conf中是否存在(大小写敏感)。 - 检查映射的第一列是否精确等于 X。
- 检查映射到的角色是否真的存在。
二、GSSAPI / Kerberos 场景的映射
Kerberos 主体名通常带 Realm(域),如 alice@EXAMPLE.COM,而数据库角色名只有 alice。这是映射最典型的用途。
# pg_ident.conf:剥离 @REALM
krb_map /^(.*)@EXAMPLE\.COM$ \1# pg_hba.conf
hostgssenc all all 0.0.0.0/0 gss map=krb_map
host all all 0.0.0.0/0 gss map=krb_map如果 Kerberos 主体名就是数据库角色名(无域),则不需要映射:
# 不加 map=,直接同名匹配
hostgssenc all all 0.0.0.0/0 gss检查 Kerberos 下 HBA 规则中的包括名:官方文档提到 include_realm 选项(默认 1),它决定是否在传给映射前保留 Realm 部分:
# include_realm=1(默认):传给映射的是 alice@EXAMPLE.COM
hostgssenc all all 0.0.0.0/0 gss include_realm=1 map=krb_map
# include_realm=0:先剥掉 Realm,传给映射的是 alice
hostgssenc all all 0.0.0.0/0 gss include_realm=0 map=krb_map对应两种映射写法:
# include_realm=1 时的映射
krb_map /^(.*)@EXAMPLE\.COM$ \1# include_realm=0 时的映射(只需处理裸用户名)
krb_map alice aliceGSSAPI 的 krb_realm 选项
把 krb_realm=EXAMPLE.COM 写在 HBA 行里,可以限定只接受该 Realm 的主体,防止其他 Realm 的同名用户冒用。这与映射是互补的两层防护。
三、Windows SSPI 场景
Windows 域环境使用 sspi,映射写法与 GSSAPI 类似:
# pg_ident.conf
sspi_map /^(.*)@EXAMPLE$ \1# pg_hba.conf
host all all 0.0.0.0/0 sspi map=sspi_mapWindows 用户的 SSPI 名字通常是 DOMAIN\user 或 user@DOMAIN 形式。可以用正则统一处理:
# 处理 DOMAIN\user 形式
sspi_map /^EXAMPLE\\(.*)$ \1四、cert 认证下的映射
cert 认证使用客户端证书的 Common Name(CN)作为外部身份。verify-full 时 CN 必须等于角色名(无需映射);verify-ca 时只校验证书由受信 CA 签发,需要用映射把 CN 对应到角色。
# pg_hba.conf
# verify-full:不需要映射
hostssl all all 0.0.0.0/0 cert clientcert=verify-full
# verify-ca:需要映射
hostssl all all 0.0.0.0/0 cert clientcert=verify-ca map=cert_map# pg_ident.conf
# CN 形如 alice@example.com,映射到角色 alice
cert_map /^([^@]+)@example\.com$/ \1verify-ca + 无映射 = 任何人可用任意 CN
verify-ca 只验证「证书由受信 CA 签发」,不验证 CN 与角色名的对应关系。若此时又不加 map=,则任何持有该 CA 签发证书、且证书 CN 恰好是某角色名的人都能登录。
安全做法:要么用 verify-full,要么用 verify-ca + 严格的正则映射。
五、多个外部身份映射到同一个角色
常见于「值班轮换」或「多个 CI runner 都用同一个部署身份」:
# pg_ident.conf
deploy_map deploy_prod appuser
deploy_map deploy_staging appuser
deploy_map jenkins appuser
deploy_map gitlab_runner appuser# pg_hba.conf
local myapp appuser peer map=deploy_map审计时要注意:数据库端看到的都是 appuser,无法区分具体是哪个 OS 用户。若需要区分,可以在 HBA 中加 log_line_prefix 记录外部身份,或改用不同角色。
-- 通过 pg_stat_activity 只能看到最终角色
SELECT usename, client_addr, application_name FROM pg_stat_activity;六、all 与 +role 的联合使用
用 +role 做「外部身份只需属于某组」的粗粒度控制:
# pg_ident.conf
# 任意外部用户映射为 app_users 组成员
app_map /^ci-.*$/ +app_users配合 HBA:
# pg_hba.conf
local myapp +app_users peer map=app_map含义:外部用户名以 ci- 开头的,被认作 app_users 角色的成员,从而通过 HBA 中 +app_users 的匹配。
七、include 组织映射文件
域用户多时,映射文件会变长,用 include_dir 拆分:
PGDATA/pg_ident.d/
├── 10_os_users.conf # 本机 OS 用户
├── 20_kerberos.conf # Kerberos 主体现
├── 30_ci_runners.conf # CI 机器人
└── 99_local.conf # 本机覆盖# pg_ident.conf
include_dir 'pg_ident.d'# pg_ident.d/20_kerberos.conf
krb_map /^(.*)@EXAMPLE\.COM$ \1
krb_map /^(.*)@CORP\.EXAMPLE\.COM$ \1八、预检与核验的固定流程
和 HBA 一样,改完先预检:
-- 1. 检查解析错误
SELECT line_number, error FROM pg_ident_file_mappings WHERE error IS NOT NULL; line_number | error
-------------+-------
(0 rows)-- 2. reload
SELECT pg_reload_conf();
-- 3. 核验映射清单
SELECT map_name, sys_name, pg_username FROM pg_ident_file_mappings ORDER BY map_name, map_number; map_name | sys_name | pg_username
-----------+-----------------------+-------------
krb_map | /^(.*)@EXAMPLE\.COM$ | \1
os_db_map | alice | alice
os_db_map | deploy | appuser
(3 rows)-- 4. 确认被映射的角色真的存在
SELECT rolname FROM pg_roles WHERE rolname IN ('alice', 'appuser') ORDER BY rolname; rolname
---------
alice
appuser
(2 rows)九、用 grep 辅助排查映射名拼写
映射名是普通字符串,拼错不会报错,只会导致「映射不生效」。用文本搜索快速核对:
# 找出 HBA 中所有 map= 引用
grep -o 'map=[A-Za-z0-9_]*' $PGDATA/pg_hba.conf | sort -u
# 列出 ident 文件中所有映射名
awk '!/^#/ && NF>=3 {print $1}' $PGDATA/pg_ident.conf | sort -u两边的输出做 diff,就能发现「HBA 引用了不存在的映射名」或「定义了映射但没人引用」。
十、映射名大小写与引号
若映射名或角色名包含需要引号的字符(如空格、大写),用双引号包裹:
# 需要引号的情形
mymap alice "Alice Admin"但不加引号的标识符会被折叠为原样字符串(不像 SQL 标识符会折叠为小写),所以:
# 下面两行是同一个映射名,不是两个
MyMap alice alice
mymap bob bob角色名中的大写必须加引号
PostgreSQL 的角色名在 SQL 中不加引号会折叠为小写。如果角色真的叫 Alice(含大写),pg_ident.conf 里必须写成 "Alice",否则会去找小写的 alice。
-- 创建了含大写的角色
CREATE ROLE "Alice" LOGIN;# 必须加引号才匹配
mymap alice "Alice"实战示例
场景:为「本地 OS 用户 + Kerberos 域用户 + CI 机器人」统一映射
一家公司有三类登录来源,要求:
- 服务器上 OS 用户
postgres免密管理(peer)。 - OS 用户
deploy以角色appuser免密执行部署(peer)。 - Kerberos 域
EXAMPLE.COM的用户,各自映射到同名数据库角色(gss)。 - CI runner(用户名以
ci-开头)统一映射到角色ci_bot(peer)。
第一步,准备角色:
-- 管理角色
-- postgres 已存在
-- 应用部署角色
CREATE ROLE appuser WITH LOGIN;
-- CI 机器人角色
CREATE ROLE ci_bot WITH LOGIN;
-- Kerberos 用户对应角色
CREATE ROLE alice WITH LOGIN;
CREATE ROLE bob WITH LOGIN;CREATE ROLE appuser WITH LOGIN;
CREATE ROLE
CREATE ROLE ci_bot WITH LOGIN;
CREATE ROLE
CREATE ROLE alice WITH LOGIN;
CREATE ROLE
CREATE ROLE bob WITH LOGIN;
CREATE ROLE第二步,写映射文件:
# =========================================================
# pg_ident.conf 生成日期 2026-09-29
# 三列:MAPNAME SYSTEM-USERNAME PG-USERNAME
# 映射名大小写敏感;系统用户名以 / 开头表示正则
# =========================================================
# ---- 1. 本地管理:postgres 直接同名(也可省略映射) ----
admins postgres postgres
# ---- 2. 部署账号:OS deploy 映射到 appuser ----
deploy_map deploy appuser
deploy_map root postgres
# ---- 3. Kerberos:剥离 @EXAMPLE.COM,映射到同名角色 ----
krb_map /^(.*)@EXAMPLE\.COM$ \1
# ---- 4. CI 机器人:ci-* 统一映射到 ci_bot ----
ci_map /^ci-.*$ ci_bot第三步,HBA 引用这些映射:
# pg_hba.conf
# 本地管理:peer + admins 映射
local all postgres peer map=admins
local all appuser peer map=deploy_map
local all ci_bot peer map=ci_map
# Kerberos:gss + krb_map
hostgssenc all all 0.0.0.0/0 gss include_realm=1 map=krb_map
host all all 0.0.0.0/0 gss include_realm=1 map=krb_map
# 兜底
host all all 0.0.0.0/0 reject第四步,reload 并核对:
pg_ctl reload -D /var/lib/postgresql/18/main-- 核验映射解析结果
SELECT map_name, sys_name, pg_username
FROM pg_ident_file_mappings
ORDER BY map_name, map_number; map_name | sys_name | pg_username
-----------+-----------------------------+-------------
admins | postgres | postgres
ci_map | /^ci-.*$ | ci_bot
deploy_map| deploy | appuser
deploy_map| root | postgres
krb_map | /^(.*)@EXAMPLE\.COM$ | \1
(5 rows)第五步,端到端验证:
# 1) OS deploy 用户 -> appuser
$ sudo -u deploy psql -d myapp -c "SELECT current_user, session_user;"
current_user | session_user
--------------+--------------
appuser | appuser
(1 row)
# 2) CI runner 用户 ci-runner-01 -> ci_bot
$ sudo -u ci-runner-01 psql -d myapp -c "SELECT current_user;"
current_user
--------------
ci_bot
(1 row)
# 3) 未配置映射的 OS 用户 -> 失败
$ sudo -u nobody psql -d myapp
psql: error: connection to server on socket "/var/run/postgresql/.s.PGSQL.5432" failed:
FATAL: no pg_hba.conf entry for host "[local]", user "nobody", database "myapp", no encryption
# 4) Kerberos 用户 alice@EXAMPLE.COM -> alice
$ kinit alice@EXAMPLE.COM
$ psql "host=db.example.com dbname=myapp user=alice"
myapp=> SELECT current_user, session_user;
current_user | session_user
--------------+--------------
alice | alice
(1 row)结果解读:
- 第 2 步证明正则映射
^ci-.*$ → ci_bot生效,多个 CI runner 共用一个数据库角色。 - 第 3 步的报错说明
nobody既没落在deploy_map也没落在ci_map里,HBA 无匹配入口——符合预期(拒绝)。 - 第 4 步证明
krb_map的\1捕获组把alice@EXAMPLE.COM正确裁剪成了alice。
注意事项
不要忘记在 HBA 里写 map=。 只定义了映射而不引用,映射不会生效,登录会去找同名角色。
# pg_ident.conf 定义了,但 HBA 没引用 —— 无效
appmap deploy appuser# 错误!缺少 map=,会去找角色 "deploy"
local myapp appuser peer
# 正确
local myapp appuser peer map=appmap不要把 all 写成 "all"。 加引号后关键字语义丢失,会被当成字面角色名。
# 错误!
mymap alice "all"
# 正确
mymap alice all第三列是正则时不要用 \1。 官方明确不支持这种组合。
# 错误!第三列同时是正则又想引用捕获组
bad /^(.*)@EXAMPLE\.COM$/ /^db_\1$/
# 正确:第三列用普通角色名
good /^(.*)@EXAMPLE\.COM$/ \1映射到的角色必须存在。 映射不是创建角色,只是改名字对应关系。
-- 忘记创建角色时会失败
-- FATAL: role "appuser" does not exist
CREATE ROLE appuser WITH LOGIN; -- 必须不要指望 peer 能映射远程连接。 peer 只对 Unix 域套接字(local 类型)有意义;TCP 连接要用 ident 或 gss 等。
# 错误!host 类型不支持 peer
host all all 10.0.0.0/24 peer大小写一定要核对。 映射名与系统用户名都是大小写敏感的字符串比较。
# 这两行是不同的映射
MyMap alice alice
mymap alice alice角色名含大写时必须加引号。 否则 SQL 层会折叠为小写,导致映射到不存在的角色。
# 正确
mymap alice "Alice"
# 错误!会去找小写 alice
mymap alice Alice不要用 verify-ca + 无映射的 cert 认证。 这等于「任何持有受信 CA 证书的人都能以任意角色登录」。
# 危险
hostssl all all 0.0.0.0/0 cert clientcert=verify-ca
# 安全
hostssl all all 0.0.0.0/0 cert clientcert=verify-fullinclude 的文件路径相对路径解析基准要确认。 与 postgresql.conf 相同,相对路径相对于当前配置文件所在目录,不是 PGDATA。
# 若 pg_ident.conf 在 /etc/postgresql/,则此路径解析为 /etc/postgresql/ident.d/...
include 'ident.d/10_os_users.conf'改完不要忘记 reload。 pg_ident.conf 是 sighup 级别,不 reload 不生效。
pg_ctl reload -D $PGDATA不要用映射来「绕过」角色权限设计。 把大量外部身份都映射到 postgres 超级用户是很常见的错误做法。
# 危险!所有人都是超级用户
wide_map /^.*$/ postgresKerberos 的 Realm 要限定。 不加 krb_realm 时,任何 Realm 中同名主体都可能被接受。
# 推荐:限定 Realm
hostgssenc all all 0.0.0.0/0 gss krb_realm=EXAMPLE.COM map=krb_map排查失败时先看视图,不要猜文件。 pg_ident_file_mappings 才是「系统实际解析到的内容」。
SELECT * FROM pg_ident_file_mappings WHERE error IS NOT NULL;最佳实践
为每个用途起一个语义清晰的映射名。 名字里体现出「谁映射到谁」,避免 map1、map2。
deploy_map deploy appuser
ci_map /^ci-.*$/ ci_bot
krb_map /^(.*)@EXAMPLE\.COM$/ \1正则映射优先用捕获组剥离域后缀。 这样新增域用户不需要改文件。
krb_map /^(.*)@EXAMPLE\.COM$/ \1映射文件拆分到 pg_ident.d/ 并按来源分类。 本机 OS 用户、Kerberos、CI 各自独立,变更互不影响。
include_dir 'pg_ident.d'把「映射清单」和「HBA 引用清单」做交叉核对。 两边不一致是最高频的故障原因。
grep -o 'map=[A-Za-z0-9_]*' $PGDATA/pg_hba.conf | sort -u
awk '!/^#/ && NF>=3 {print $1}' $PGDATA/pg_ident.conf | sort -u预检 + reload + 核验,三步固定执行。
SELECT line_number, error FROM pg_ident_file_mappings WHERE error IS NOT NULL;
SELECT pg_reload_conf();
SELECT map_name, sys_name, pg_username FROM pg_ident_file_mappings ORDER BY map_name, map_number;用 +role 做粗粒度分组,减少逐条维护。 尤其适合角色成员经常变动的场景。
app_map /^ci-.*$/ +app_users对 CI/CD 机器人单独建角色,避免与人类账号混用。 便于审计、便于一次性吊销。
CREATE ROLE ci_bot WITH LOGIN;
REVOKE ALL ON DATABASE myapp FROM ci_bot;
GRANT CONNECT ON DATABASE myapp TO ci_bot;Kerberos / SSPI 场景一律显式限定 Realm/Domain。 防止其他信任域的同名主体冒用。
hostgssenc all all 0.0.0.0/0 gss krb_realm=EXAMPLE.COM map=krb_map证书认证优先 verify-full。 只有在必须用 verify-ca 时才依赖映射,并且映射要用严格正则。
hostssl all all 0.0.0.0/0 cert clientcert=verify-full把映射与 HBA 变更写进同一个变更单。 它们是一体两面,分开改动极易漏掉一半。
变更单字段:
- HBA 新增行:local myapp appuser peer map=deploy_map
- ident 新增行:deploy_map deploy appuser
- 前置:CREATE ROLE appuser WITH LOGIN;
- 验证命令:sudo -u deploy psql -d myapp -c "SELECT current_user;"映射文件纳入版本库。 它是安全配置的一部分,需要评审、需要历史可追溯。
git add pg_ident.conf pg_ident.d/
git commit -m "feat(hba): add kerberos realm mapping and ci bot account"每个映射行都写注释说明业务来源。 半年后没人记得 ci-.* 是哪套流水线。
# GitLab 自建 runner(用户名 ci-runner-*),统一到 ci_bot
ci_map /^ci-.*$/ ci_bot定期清理无引用的映射。 用交叉核对脚本找出「定义了但 HBA 没引用」的映射名,避免配置腐化。
comm -23 <(awk '!/^#/ && NF>=3 {print $1}' $PGDATA/pg_ident.conf | sort -u) \
<(grep -o 'map=[A-Za-z0-9_]*' $PGDATA/pg_hba.conf | cut -d= -f2 | sort -u)下一节
继续学习:配置参数生效方式
参考链接
- PostgreSQL 官方文档:User Name Maps(auth-username-maps)
- PostgreSQL 官方文档:The pg_ident_file_mappings View(view-pg-ident-file-mappings)
- PostgreSQL 官方文档:The pg_hba.conf File(auth-pg-hba-conf)
- PostgreSQL 官方文档:Peer Authentication(auth-peer)
- PostgreSQL 官方文档:GSSAPI Authentication(gssapi-auth)
- PostgreSQL 官方文档:SSPI Authentication(sspi-auth)
- PostgreSQL 官方文档:Certificate Authentication(auth-cert)
- PostgreSQL 官方文档:File Locations(runtime-config-file-locations)