1. 环境
本地开发把 PostgreSQL、FastAPI 和数据放在一台电脑上,生产环境则需要分别考虑应用实例、数据库服务、网络、权限、备份和监控。
生产连接信息只通过部署环境或密钥服务提供:
1DATABASE_URL=postgresql+psycopg://task_app_runtime:REPLACE_WITH_SECRET@db.example.internal:5432/task_app?sslmode=verify-full&sslrootcert=/run/secrets/postgresql-ca.pem&connect_timeout=5
真实密码由部署平台的密钥服务注入,不能提交到代码仓库。日志也不能完整打印 URL,因为 URL 中通常包含用户名和密码。手动拼接 URL 时,密码中的 @、:、/ 等保留字符还需要进行百分号编码;条件允许时,优先使用结构化配置创建连接参数。
数据库地址应该位于受控私有网络,不要为了连接方便直接把 5432 端口向整个互联网开放。示例中的 sslmode=verify-full 会同时验证证书链和数据库主机名,sslrootcert 指向部署环境中受信任的根证书;如果数据库使用公共 CA,也可以按平台说明使用系统信任库。只写 verify-full 却没有提供可用的信任根,连接仍然无法建立。
connect_timeout=5 限制建立新数据库连接时的等待时间,它与后文的 pool_timeout 不是同一件事:前者等待网络连接建立,后者等待应用从连接池中取得一个连接。
开发、测试、预发布和生产使用不同数据库与账号。环境隔离不仅防止测试脚本清空生产数据,也让权限、迁移和容量问题能在发布前被发现。
应用启动时不自动执行 create_all(),也不让每个 worker 同时运行 Alembic。数据库结构升级应该是发布流程中的独立步骤。
2. 权限
生产应用使用最小权限账号。运行接口通常只需要连接、使用 Schema、读取和修改业务表:
01REVOKE CONNECT ON DATABASE task_app FROM PUBLIC;02GRANT CONNECT ON DATABASE task_app03TO task_app_runtime, task_app_migrator;0405REVOKE CREATE ON SCHEMA public FROM PUBLIC;06GRANT USAGE ON SCHEMA public TO task_app_runtime;07GRANT USAGE, CREATE ON SCHEMA public TO task_app_migrator;0809GRANT SELECT, INSERT, UPDATE, DELETE10ON ALL TABLES IN SCHEMA public11TO task_app_runtime;12GRANT USAGE, SELECT13ON ALL SEQUENCES IN SCHEMA public14TO task_app_runtime;
PUBLIC 表示所有数据库角色。先撤销数据库的公共连接权限和 public Schema 的公共创建权限,再对所需角色逐项授权,才能让后续的 GRANT 真正形成边界。实际项目还要为管理员、监控和备份账号单独授权。
创建和修改表的迁移账号应与运行账号分开。接口被攻击时,运行账号不应该拥有创建表、DROP TABLE、创建角色或修改数据库配置的能力。
为了让未来迁移创建的表自动获得运行权限,需要由对象所有者设置默认权限:
1ALTER DEFAULT PRIVILEGES FOR ROLE task_app_migrator2IN SCHEMA public3GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO task_app_runtime;45ALTER DEFAULT PRIVILEGES FOR ROLE task_app_migrator6IN SCHEMA public7GRANT USAGE, SELECT ON SEQUENCES TO task_app_runtime;
ALTER DEFAULT PRIVILEGES 只影响以后由 task_app_migrator 创建的对象,不会自动补授权已有表,而且必须由该角色本身、该角色的成员或管理员执行。若迁移实际使用了另一个对象创建者,这组默认权限不会生效。权限脚本需要在目标环境验证,不能只在拥有超级用户权限的本地数据库中测试。