#2618·runtipi

将核心秘密(`JWT_SECRET`、`POSTGRES_PASSWORD`)保持在每个应用的环境范围之外(加固)

作者: etvt创建于 2026年7月6日更新于 2026年7月6日

对 #2617 的后续处理 — 一个单独的相关硬化想法(不同的根本原因,单独提交)。 **我注意到的事情:** 每个应用程序生成的 `app.env` 都是从全局 Runtipi `.env` 中提取的,然后将应用程序变量合并在一起 — 因此每个应用程序的 `app.env` 中都包含了核心基础设施的秘密(`JWT_SECRET`、`POSTGRES_PASSWORD`、`RABBITMQ_PASSWORD`),而不仅仅是其自身。 - `packages/backend/src/modules/apps/app.helpers.ts` — `generateEnvFile` 以全局环境作为基础,将合并后的结果写入 `app.env`。 - `packages/backend/src/core/config/configuration.service.ts` — 这些秘密存储在全局环境中。 - `app.env` 会被写入应用程序数据的根目录(`{app-data}/{store}/{app}/app.env`),这是 `data/` 文件夹模板安装的一个兄弟目录。 **核心秘密可以通过两种方式进入应用程序容器:** 1. `Docker compose --env-file app.env` 将它们全部放入插值范围中,因此模板可以直接引用它们。这不是理论上的 — `apps/calcom/Docker-compose.yml` 解析了 `${POSTGRES_PASSWORD}` / `${POSTGRES_USERNAME`(calcom 没有此类表单字段,因此这些是核心凭据),将它们注入到其容器中,并将其捆绑的数据库设置为核心密码。 2. 卷配置错误 — 将 `${APP_DATA_DIR}` 而不是 `${APP_DATA_DIR}/data` 挂载到容器中,将整个 `app.env` 交给容器。 **为什么它与 #2617 结合在一起:** 拥有 `POSTGRES_PASSWORD` 后,`runtipi-db` 可以通过共享的 `tipi_main_network` 访问 — 受到攻击的应用程序可以访问核心数据库。并且 FWIW **没有任何官方应用程序实际重用核心数据库**(没有 `runtipi-db` 任何地方的引用;每个数据库应用程序都运行自己的 Postgres),因此没有效率原因让应用程序保留核心凭据 — calcom 案例看起来像是一个意外的脚枪,而不是有意的重用。 **建议 — 两个小的、独立的更改:** 1. **将 `app.env` 限制为应用程序专用变量**(不要从全局 `.env` 中提取)。核心秘密保存在 Runtipi 自己的环境中。额外优势:依赖 `${POSTGRES_PASSWORD}` 的模板将显示出来,而不是默默获取核心秘密。 2. **将 `app.env` 移出可挂载的数据目录** — 它是 Runtipi 的元数据,而不是应用程序数据,因此我认为它更适合安装目录中生成的 compose 旁边,而不是在 `app-data/` 中,用户绑定挂载。这解决了错误挂载的暴露问题,没有新的变量。 *(备份安全:`backupApp` 已经归档了数据目录和安装目录 — `backup.manager.ts:70-77` / 恢复 `:169-170` — 因此环境仍然在恢复中随同着。)* (calcom 的模板可能也需要自己的随机 `CALCOM_DB_PASSWORD` 无论。) 了解可能存在历史原因支持当前布局 — 只是在可能值得加强的情况下标记一下。 *(同一提醒:由 AI 帮助组成 — Claude Opus 4.8 — 因此请对代码引用进行合理检查。)*

内容来源: runtipi/runtipi