23.6 Pigsty 安全基线
Pigsty 能把角色、HBA、服务入口、证书和日志参数声明化,但“声明化”不等于 “使用默认值即可满足任何生产 threat model”。官方安全说明明确指出,默认 配置面向可信内网中的开发、测试和演示;生产环境要按自身威胁模型配置凭据、 网络边界、认证、证书、备份和审计。
本节建立四层对账:
只有最下面一层能证明客户端实际经历了什么;只有最上面一层能解释为什么这样 设计。
23.6.1 角色、HBA、证书与服务入口声明
角色声明
Pigsty 用:
用户按数组顺序创建,因此被引用的 group role 应先定义。下面是结构示例, 不是可直接投产的 secret 文件:
示例标记必须由私密交付机制替换,不能把真实明文或 verifier 提交到本书、Git、 工单或聊天记录。Pigsty 支持 plaintext 或 SCRAM verifier,但官方也把 plaintext inventory 标为不推荐。角色字段与 membership object 格式见 Pigsty:User/Role。
这里还要注意:
roles管理是 additive;未声明的历史 membership 不会自动消失;- 要撤销旧 membership,应显式使用
state: absent; - PostgreSQL 16+ 才支持 membership 的
set/inherit细分; pgbouncer: true会把 login 纳入 PgBouncer 认证面;NOLOGINowner/runtime/readonly 不应加入池用户列表;connlimit与 PgBouncer pool limit 是不同层的限制。
已存在集群修改角色:
它是声明式、可重复入口。删除角色的 state: absent 会涉及断开连接、转移
ownership 和 DROP ROLE,属于破坏性变更;必须先 dry-run/依赖审查和审批,
不能把“脚本支持安全删除”理解为无需变更控制。官方管理流程见
Pigsty:用户管理。
membership 与对象 ACL 分开
Pigsty pg_users 可声明 cluster role 和 membership;schema/table/function
ACL、owner、default privilege 与 RLS policy 仍应由经过版本控制的 migration
完成:
不要在多个无序启动脚本里同时管理同一份 grant。平台和应用必须明确各自 owner 和收敛时点。
PostgreSQL 与 PgBouncer HBA
Pigsty 有四组参数:
| 参数 | 范围 | 作用 |
|---|---|---|
pg_default_hba_rules |
global | PostgreSQL 环境默认规则 |
pg_hba_rules |
global/cluster/instance | PostgreSQL 增量规则 |
pgb_default_hba_rules |
global | PgBouncer 环境默认规则 |
pgb_hba_rules |
global/cluster/instance | PgBouncer 增量规则 |
规则会按 order 排序,数值越小越靠前。未显式指定通常进入 1000+ 区域;
如果前面已有宽泛默认 allow,它可能永远匹配不到。
生产应用入口的概念示例:
auth: ssl 的当前 Pigsty alias 会渲染为 hostssl ... scram-sha-256;生产变更
仍应检查目标版本的渲染结果,不能永久依赖书中的 alias 解释。HBA 字段、
alias、role filter 和 order 规则见
Pigsty:HBA Rules。
若应用只允许经 pool/service 入口访问,可进一步在网络与 PostgreSQL HBA
中拒绝应用子网直连 5432,只允许本机 PgBouncer 或指定代理身份访问后端。
这能避免客户端绕过 PgBouncer 的连接限制、认证面与事务池合同。
intra 只是地址别名
Pigsty 的 intra/intranet 通常展开为 RFC 1918:
这些地址不是天然可信。企业办公网、VPN、容器网、其他租户 VPC 和开发环境都 可能落在其中。生产规则应尽量使用准确的应用 subnet/security group,而不是 把整个 RFC 1918 视为一个 trust zone。
刷新而非手工改文件
修改 inventory 后:
会重新渲染并 reload PostgreSQL/PgBouncer 相关 HBA。不要直接编辑:
下次 playbook 会覆盖手工改动,而且 inventory 与运行事实从此分叉。紧急手工 变更若无法避免,也必须同步回声明源、记录例外并尽快恢复收敛。
证书声明和使用
Pigsty 默认基础设施 CA 会为 PostgreSQL、Patroni、etcd、MinIO、Nginx 等 内部服务签发证书。生产评审要区分:
这六件事不能合并成“开启 SSL”。
证书 SAN 应覆盖客户端实际使用的:
- HAProxy/VIP DNS name;
- PostgreSQL direct service name;
- 节点名/IP(若允许直连);
- planned disaster-recovery endpoint。
不要让应用用 hostaddr 绕过期望的 DNS name verification,除非同时提供可
校验的 host 语义并完成测试。
CA private key 所在目录是根信任资产。需要离线/受限备份、读取审计和恢复演练。 证书签发与客户端安装流程见 Pigsty:CA and Certificates。
两段 TLS 分别声明
若应用经 PgBouncer:
Pigsty 的 PostgreSQL server TLS 默认开启,不表示 HBA 默认要求 TLS; PgBouncer client TLS 默认也不是开启状态。当前官方安全说明明确列出:
生产要逐入口决定:
| 链路 | 加密 | 对端验证 | 允许来源 | 认证主体 |
|---|---|---|---|---|
| app → HAProxy/PgBouncer | required | service name | app subnet | app login |
| PgBouncer → PostgreSQL | TLS 或受控 local socket | node/service | proxy nodes | server login |
| admin → PostgreSQL | required | admin endpoint | bastion/infra | named admin |
| replica → primary | required or isolated equivalent | node identity | cluster only | replication role |
service entrypoint
第 22 章区分了 direct PostgreSQL、PgBouncer、HAProxy primary/replica/offline 等入口。安全基线要为每个入口建立:
未使用入口应关闭或从网络上不可达。保留一个“以后可能调试”的公网 5432
会变成长期旁路。
23.6.2 管理面、监控面和数据库面的网络边界
先画流量矩阵
至少区分:
| 平面 | 典型组件 | 主要主体 | 失陷后风险 |
|---|---|---|---|
| 管理面 | meta/Ansible、SSH、sudo、secret store | 平台管理员/自动化 | 改写全部配置与密钥 |
| 控制面 | Patroni REST、etcd | cluster agent | 错误选主、拓扑控制 |
| 数据面 | HAProxy、PgBouncer、PostgreSQL | 应用/分析/迁移 | 数据读写与租户越权 |
| 监控面 | exporter、Prometheus、Grafana、日志 | monitoring identities | 查询/拓扑/日志泄露 |
| 备份面 | pgBackRest repo、WAL/archive | backup identities | 全量数据泄露或恢复破坏 |
“都是内网服务”不是边界设计。每条 flow 应记录:
管理面
管理节点通常能:
- 通过 SSH 到所有节点;
- sudo/root;
- 读取 inventory 或 vault integration;
- 运行 Ansible/playbook;
- 访问 CA material;
- 变更防火墙、HBA 和 service。
因此它不是普通“运维跳板”。应:
把数据库 superuser 密码从 inventory 移走,却允许所有工程师无审计地
sudo -iu postgres,并没有实现职责分离。
控制面
Patroni REST 和 etcd 决定 cluster topology。它们不应暴露给业务 subnet。 控制面规则通常只允许:
health check 入口与管理 API 要区分。HAProxy 为角色判断访问 Patroni health endpoint,不表示应用客户端也应访问完整 Patroni API。
控制面 TLS、认证和 ACL 必须按目标 Pigsty 版本验证。不能因为 etcd 使用 TLS, 就推断 Patroni REST 也已经使用 TLS。
数据面
建议把应用路径收敛为:
然后按实际需要开放 direct path:
网络控制至少三层:
HBA 不是防 DDoS 的边界:连接已经到达 PostgreSQL 才会检查。安全组/防火墙也 不理解 database/user。二者互补。
Pigsty node_firewall_mode=zone 的默认可信 intranet 必须与真实边界对账。
官方建议也明确提醒 RFC 1918 范围可能过宽,生产 demo 配置通常应移除无必要
的 5432 暴露。参见
Pigsty:Security Recommendations。
监控面
monitor role 看起来只读,但往往能访问:
pg_stat_activity查询文本;- replication/topology;
- database/object names;
- slow-query samples;
- connection source/user;
- logs and dashboards。
因此:
- monitor 不应使用 superuser;
- exporter query 必须受版本控制;
- dashboard 与 Prometheus API 要认证;
- label 不能含 password/token/高基数 PII;
- 跨环境 metrics/logs 要隔离;
- support snapshot 要脱敏;
- 监控不可用不能使数据库认证 fail-open。
备份面
backup repository 持有跨 RLS、跨租户的完整数据与 WAL。网络上只允许备份 主体和恢复路径;读取、删除、retention 改动应分权。数据库 RLS/HBA 无法保护 一份已被复制到对象存储的备份。
恢复环境同样要隔离:把生产备份恢复到宽松开发网,常比攻击生产数据库更容易 造成泄露。第 21、32、33 章会继续处理备份与恢复的控制。
egress 也要控制
数据库节点出站能力可能被:
- extension/FDW;
COPY PROGRAM高权能力;- untrusted language;
- backup/archive command;
- 运维脚本;
- 被攻陷进程
用于外带数据。仅做 inbound firewall 不够。生产需要明确允许的软件源、 backup endpoint、DNS/NTP/monitoring 等 egress,并监控异常。
23.6.3 从配置渲染到运行事实的差异检查
四份状态
对同一项控制记录:
示例:
| 控制 | desired | rendered | runtime | observed |
|---|---|---|---|---|
| app TLS | auth: ssl |
hostssl |
pg_hba_file_rules |
disable fails, verify-full succeeds |
| role | NOINHERIT |
generated SQL | pg_roles |
raw login SELECT fails |
| membership | SET true |
grant statement | pg_auth_members |
SET LOCAL succeeds |
| RLS | migration | table/policy DDL | pg_class/pg_policies |
cross-tenant writes fail |
| pool identity | pgbouncer: true |
userlist presence | SHOW USERS projection |
pool auth succeeds |
任何一列缺失都不能宣告闭环。
inventory 评审
先检查:
- 是否把 secret 直接写入 Git;
- role 高权 flag;
inherit和 membershipadmin/set/inherit;pgbouncer暴露范围;- HBA order 与宽规则;
host/hostssl;world/intraalias 展开;- primary/replica/offline role filter;
- listener/service port;
- PostgreSQL/PgBouncer/Patroni TLS;
- logging/audit;
- firewall intranet。
inventory diff 应显示结构,不应把 password/verifier 展开到 PR。
渲染检查
变更前先生成/审查候选,应用后检查节点:
不要把 /etc/pgbouncer/userlist.txt 原文放进证据;它可能含 verifier。
HBA 应验证:
并确认 error IS NULL、顺序与 inventory 相符。
runtime 检查
角色:
membership:
对象与 RLS:
TLS:
日志:
observed 检查
必须从与真实 workload 相同的网络和 driver 路径执行:
只在 database node 上用 Unix socket psql,无法验收远程网络、proxy HBA、
TLS name 或客户端 CA distribution。
本章沙箱差异
在 Pigsty v4.5.0 nonproduction sandbox 中,正式捕获发现:
| 控制 | 期望/能力 | 运行事实 | 判定 |
|---|---|---|---|
| PostgreSQL TLS | server 可加密 | on,最低 TLS 1.2 | 能力通过 |
| cert identity | SAN + verify-full | 正例成功,错名失败 | 通过 |
| direct channel binding | SCRAM over TLS | 成功 | 通过 |
| business direct HBA | 生产应强制 TLS | +dbrole_readonly 内网为 host |
待整改 |
| PgBouncer client TLS | 生产应按 threat model 启用 | disabled | 待整改 |
| pool → PostgreSQL | 受控链路 | local Unix socket | 事实符合设计 |
| CRL | 撤销路径 | file/dir unset | 待整改 |
| pgAudit | 目标要求对象审计 | absent/not preloaded | 待整改 |
| bind logging | secret-minimized | 非错误参数上限 -1 |
待整改 |
它诚实地同时证明:
第一条不能抵消第二条。
分阶段整改
安全变更也会造成可用性风险,应分阶段:
一次性把所有 host 改成 hostssl,如果客户端尚未安装 CA 或仍用 IP 不匹配
证书,会把安全整改变成全站故障。
例外不是口头备注
暂时保留非 TLS/旧客户端时,例外记录至少包含:
无到期日的例外就是新默认。
生产判定
最终报告只允许:
| 判定 | 含义 |
|---|---|
pass |
所有必须项有运行与负例证据 |
pass-with-exception |
明确、批准、限时、受补偿控制的差距 |
pending |
机制可用,但必需控制尚未实施/证明 |
reject |
存在不可接受暴露或证据冲突 |
本章沙箱是 pending。它完全适合教学实验,却不能被包装成生产审批。这种区分
正是安全工程成熟度的一部分。Pigsty 当前生产注意事项见
Pigsty:Security Considerations。
上一节:密钥、审计与敏感信息 · 返回本章目录 · 下一节:实战:隔离两个租户 · 查看全书目录 · 查看索引中心