Ubuntu+Docker环境下如何防止PostgreSQL数据库被意外删除?
问题背景
服务器基于Ubuntu系统,采用Nginx、Docker部署,Django应用通过Gunicorn运行。网站运行正常,但PostgreSQL数据库多次被意外删除,查看/var/log/postgresql/postgresql-14-main.log日志发现关键记录:
2023-10-28 12:12:17.689 UTC [3752923] postgres@postgres DETAIL: Connection matched pg_hba.conf line 102: "host all all 0.0.0.0/0 >
2023-10-28 12:12:21.050 UTC [3753069] postgres@template0 FATAL: database "template0" is not currently accepting connections
2023-10-28 12:12:43.319 UTC [3706001] postgres@aeraeg_db FATAL: terminating connection due to administrator command
2023-10-28 12:12:44.912 UTC [3753497] postgres@postgres ERROR: cannot drop the currently open database
2023-10-28 12:12:44.912 UTC [3753497] postgres@postgres STATEMENT: DROP DATABASE postgres;
2023-10-28 12:14:11.702 UTC [3755239] postgres@aeraeg_db FATAL: database "aeraeg_db" does not exist
核心防护措施
1. 严格限制数据库访问范围
- 修改
pg_hba.conf文件,删除或注释掉允许0.0.0.0/0全局访问的规则(日志中line102的条目),仅开放可信IP段连接,比如应用服务器IP、运维固定IP:host all all 192.168.1.0/24 md5 # 替换为你的内部服务IP段 host all all 10.0.0.5/32 md5 # 单个运维人员固定IP - 重启PostgreSQL服务生效:
sudo systemctl restart postgresql
2. 最小化业务用户权限
- 禁止给Django应用使用的数据库用户授予
DROP DATABASE、DROP TABLE等危险权限,仅分配业务必需的操作权限:-- 先回收所有权限 REVOKE ALL ON DATABASE aeraeg_db FROM django_user; -- 授予连接权限 GRANT CONNECT ON DATABASE aeraeg_db TO django_user; -- 授予表的增删改查权限 GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO django_user; -- 授予序列使用权限(适配Django自增字段) GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO django_user; - 绝对禁止应用使用
postgres超级用户连接数据库,必须创建独立的业务专用用户。
3. 启用定时自动备份
- 编写备份脚本并设置定时任务,确保数据有恢复兜底:
- 创建备份脚本
/var/backups/postgres_backup.sh:#!/bin/bash BACKUP_DIR="/var/backups/postgresql" DATE=$(date +%Y%m%d_%H%M%S) # 执行备份 pg_dump -U postgres aeraeg_db > "${BACKUP_DIR}/aeraeg_db_${DATE}.sql" # 清理7天前的旧备份 find "${BACKUP_DIR}" -name "*.sql" -mtime +7 -delete - 给脚本添加执行权限:
chmod +x /var/backups/postgres_backup.sh - 通过
crontab -e添加每日凌晨2点的定时任务:0 2 * * * /var/backups/postgres_backup.sh
- 创建备份脚本
4. Docker环境额外防护
- 如果PostgreSQL是Docker部署,禁止将数据库端口映射到公网,仅在Docker内部网络暴露,应用容器通过容器名/服务名访问:
services: db: image: postgres:14 # 注释掉公网映射端口 # ports: # - "5432:5432" networks: - app-internal web: build: . networks: - app-internal networks: app-internal: driver: bridge - 给PostgreSQL容器设置强密码,避免弱口令被暴力破解。
内容的提问来源于stack exchange,提问作者Youssri Abo Elseod

