Kirmi13/pg-hba-lock
GitHub: Kirmi13/pg-hba-lock
通过动态重写 pg_hba.conf 实现单个 PostgreSQL 数据库的临时连接锁定,带自动备份与语法错误回滚,适用于维护窗口期间的安全隔离。
Stars: 0 | Forks: 0
# pg-hba-lock
通过动态重写 `pg_hba.conf`,临时锁定单个 PostgreSQL 数据库,而无需影响集群的其余部分。包含自动备份和回滚功能,以防新配置无法正常解析。
典型用例:
- 需要独占访问数据库的 schema 迁移
- 维护操作(`VACUUM FULL`、重建索引、大版本升级等)
- 应急响应(隔离受损的应用程序账号)
- 时间点恢复 / 还原操作
- 在将读取流量切换到 replica 之前冻结数据库
## 功能说明
- 阻止所有与目标数据库的新连接,专用的 `migrator` 角色除外。
- 集群上的所有其他数据库保持与之前一样的可达状态。
- 在进行任何更改之前,备份当前的 `pg_hba.conf`。
- 通过 `pg_hba_file_rules` 验证新配置,如果包含语法错误会自动回滚——集群绝不会因为错误的配置而被锁死。
- 只需调用一次 `unlock_db()` 即可还原原始配置。
## 使用前须知
- **需要 superuser 权限。** 这使得 SQL 会话能够直接在磁盘上重写服务器的身份验证配置。在运行之前,请务必了解这对您的环境意味着什么。
- **仅限自托管的 PostgreSQL。** 它直接写入支撑 `hba_file` 的文件中。托管服务(RDS、Cloud SQL 等)不公开该文件,因此无法在其中使用。
- **密码可能会被记录。** `create_migrator()` 将密码作为普通的 SQL 参数接收。根据您的 `log_statement` 设置,它可能会出现在服务器日志、`pg_stat_activity` 或您的 shell 历史记录中。请使用仅在维护窗口生效的一次性密码。
- **对象所有权。** 如果 `migrator` 角色在维护窗口期间创建或拥有对象,则在这些对象被重新分配或删除之前,`drop_migrator()` 将会失败。
- 同一时间只能有一个锁处于活动状态(通过备份表上的 partial unique index 强制执行)。在锁定其他数据库之前,请调用 `unlock_db()`。
## 安装说明
```
psql -d your_database -f db_lock.sql
```
这将创建一个 `maintenance` schema,其中包含备份表以及下文所有的存储过程。要使用不同的 schema 名称,请在运行之前在 `db_lock.sql` 中查找并替换 `maintenance`——在纯 SQL/DDL 中,schema 名称无法参数化。
## 用法
```
-- 1. Create a role that stays reachable while everyone else is locked out
CALL maintenance.create_migrator('temporary-password');
-- 2. Lock the target database
CALL maintenance.lock_db('my_database');
-- ... connect as migrator and do your maintenance work ...
-- 3. Restore normal access
CALL maintenance.unlock_db();
-- 4. Clean up the temporary role
CALL maintenance.drop_migrator();
```
### 自定义角色名称或身份验证方法
```
CALL maintenance.create_migrator('temporary-password', 'svc_migrator');
CALL maintenance.lock_db('my_database', 'svc_migrator', 'scram-sha-256');
CALL maintenance.drop_migrator('svc_migrator');
```
## 工作原理
1. `lock_db(target_db)` 读取当前的 `pg_hba.conf`,将其保存到 `maintenance.pg_hba_backup` 中,然后在开头添加新规则:
- migrator 角色获得对所有数据库的访问权限(必须放在第一位——`pg_hba.conf` 规则是自上而下评估的,匹配到第一个即生效),
- 所有其他角色在 `target_db` 上被拒绝访问,
- 所有其他角色保持对其他所有数据库的正常密码访问权限。
2. `target_db` 上的现有会话将被终止,migrator 角色除外。
3. `pg_reload_conf()` 应用更改,并检查 `pg_hba_file_rules` 是否存在解析错误。如果发现任何错误,会立即还原之前的配置,并将备份标记为已使用。
4. `unlock_db()` 还原最近的备份,重新加载配置,并在将备份标记为已还原之前再次进行验证。
## 参考
| 存储过程 | 参数 | 描述 |
|---|---|---|
| `create_migrator` | `p_password`, `p_role_name = 'migrator'` | 创建一个 superuser 登录角色(如果已存在则不执行操作) |
| `drop_migrator` | `p_role_name = 'migrator'` | 终止会话并删除该角色 |
| `lock_db` | `p_target_db`, `p_migrator_role = 'migrator'`, `p_auth_method = 'scram-sha-256'` | 锁定数据库,同时保持 migrator 的访问权限处于开放状态 |
| `unlock_db` | — | 还原最近未还原的备份 |
标签:PostgreSQL, Streamlit, 多线程, 数据库运维, 测试用例, 系统维护, 访问控制