身份认证

HBA 规则、密码策略、证书认证详解。

身份认证是安全的第一道防线,确保只有合法用户才能访问数据库。Pigsty 支持多种认证方式,并通过 HBA(Host-Based Authentication)规则进行精细控制。


HBA 规则

HBA 规则决定了"谁可以从哪里用什么方式连接"。

规则结构

pg_hba_rules:
  - user: '<用户>'       # 用户名或角色,支持 + 前缀表示角色成员
    db: '<数据库>'       # 数据库名,all 表示所有
    addr: '<地址>'       # 来源地址,支持别名
    auth: '<方法>'       # 认证方法
    title: '<说明>'      # 规则说明(可选)

地址别名

别名 含义
local 本地 Unix Socket
localhost 127.0.0.1/32
intra 内网 CIDR(由 pg_intranet 定义)
infra 基础设施节点 IP
world 0.0.0.0/0(所有地址)

认证方法别名

别名 实际方法 说明
deny reject 拒绝连接
pwd scram-sha-256 密码认证
ssl scram-sha-256 + hostssl SSL + 密码
cert cert 客户端证书
trust trust 无条件信任(不推荐)
ident/peer ident/peer OS 用户映射

默认规则

pg_default_hba_rules:
  # dbsu 本地免密访问
  - {user: '${dbsu}', db: all, addr: local, auth: ident}
  - {user: '${dbsu}', db: replication, addr: local, auth: ident}

  # 复制用户
  - {user: '${repl}', db: replication, addr: localhost, auth: pwd}
  - {user: '${repl}', db: replication, addr: intra, auth: pwd}

  # 监控用户
  - {user: '${monitor}', db: all, addr: localhost, auth: pwd}
  - {user: '${monitor}', db: all, addr: infra, auth: pwd}

  # 管理员(强制 SSL)
  - {user: '${admin}', db: all, addr: infra, auth: ssl}
  - {user: '${admin}', db: all, addr: world, auth: ssl}

  # 业务用户
  - {user: '+dbrole_readonly', db: all, addr: localhost, auth: pwd}
  - {user: '+dbrole_readonly', db: all, addr: intra, auth: pwd}
  - {user: '+dbrole_offline', db: all, addr: intra, auth: pwd}

密码策略

密码加密

Pigsty 默认使用 SCRAM-SHA-256,这是 PostgreSQL 支持的最安全的密码哈希算法:

pg_pwd_enc: scram-sha-256

密码存储

密码可以在配置中使用明文或哈希值:

pg_users:
  # 明文密码(部署时自动加密)
  - name: dbuser_app
    password: 'MySecurePassword123!'

  # 已加密的哈希值
  - name: dbuser_app
    password: 'SCRAM-SHA-256$4096:xxx...'

密码强度检查

启用 passwordcheck 扩展强制密码复杂度:

pg_libs: 'passwordcheck, pg_stat_statements, auto_explain'

或使用功能更丰富的 credcheck 扩展:

pg_extensions:
  - credcheck

密码有效期

设置用户密码过期时间:

pg_users:
  - name: temp_user
    password: 'xxx'
    expire_in: 30      # 30 天后过期

  - name: contract_user
    password: 'xxx'
    expire_at: '2024-12-31'  # 指定日期过期

证书认证

证书认证提供比密码更强的安全性,可实现双因素认证。

工作原理

  1. 客户端持有由 CA 签发的证书
  2. 证书的 CN(Common Name)字段对应数据库用户名
  3. 服务器验证证书有效性并提取用户名

配置步骤

第一步:签发客户端证书

# 使用 Pigsty 提供的脚本签发证书
./cert.yml -e cn=dbuser_app

证书生成在 files/pki/misc/dbuser_app.{key,crt}

第二步:配置 HBA 规则

pg_hba_rules:
  - user: dbuser_app
    db: all
    addr: world
    auth: cert
    title: 'App user with certificate'

第三步:客户端使用证书连接

psql "host=pg-test port=5432 dbname=app \
  sslmode=verify-full \
  sslcert=dbuser_app.crt \
  sslkey=dbuser_app.key \
  sslrootcert=ca.crt"

双因素认证

结合密码和证书实现双因素认证:

pg_hba_rules:
  # 需要证书 + 密码
  - user: secure_user
    db: all
    addr: world
    auth: cert
    # 在 PostgreSQL 中还需要配置 clientcert=verify-full

客户端需要同时提供:

  1. 有效的客户端证书
  2. 正确的密码

登录失败处理

日志记录

PostgreSQL 默认记录认证失败:

LOG:  connection received: host=192.168.1.100 port=45678
FATAL:  password authentication failed for user "hacker"

告警配置

配置 VictoriaMetrics 告警规则监控认证失败。

自动封禁(可选)

可配合 fail2ban 自动封禁频繁失败的 IP:

# /etc/fail2ban/jail.local
[postgresql]
enabled = true
filter = postgresql
action = iptables[name=PostgreSQL, port=5432, protocol=tcp]
logpath = /pg/log/postgres/postgresql-*.log
maxretry = 5
bantime = 3600

认证故障排查

常见问题

问题:FATAL: no pg_hba.conf entry for host

原因:没有匹配的 HBA 规则

解决:检查 pg_hba.conf 并添加适当的规则

问题:FATAL: password authentication failed

原因:密码错误或用户不存在

解决:验证用户名和密码

问题:FATAL: certificate authentication failed

原因:证书无效或 CN 不匹配

解决:检查证书有效期和 CN 字段

调试命令

# 查看当前 HBA 规则
psql -c "SELECT * FROM pg_hba_file_rules;"

# 查看用户信息
psql -c "SELECT usename, valuntil FROM pg_user;"

# 测试连接
psql "host=xxx port=5432 dbname=xxx user=xxx" -c "SELECT 1;"