OneUptime Monitor Secrets 实战指南:加密密钥的创建、注入与访问控制
2026/9/20 1:19:00 网站建设 项目流程

OneUptime Monitor Secrets 实战指南:加密密钥的创建、注入与访问控制

【免费下载链接】oneuptimeComplete open-source monitoring and observability platform.项目地址: https://gitcode.com/GitHub_Trending/on/oneuptime

Monitor Secrets 是 OneUptime 内置的敏感信息管理能力,用于在 API、网站、SNMP、Synthetic 脚本等各类监控检查中安全地存放 API Key、密码、令牌等凭据,替代把明文写死在监控配置里的做法。本文以官方文档为主体,结合仓库内数据模型、加密实现与注入管线源码,完整讲解 Monitor Secret 的创建、授权、引用、轮换与权限管控,读完你可以在自托管或云端 OneUptime 中为监控检查接入一套「加密存储、按监控器授权、模板语法注入」的密钥体系。

Monitor Secrets 是什么

Monitor Secret 是一个可以被监控器使用的加密密钥变量。仓库中数据模型的官方描述(见 MonitorSecret.ts)定义得很清楚:

Monitor Secret is a secret variable that can be used in monitors. For example you can store auth tokens, passwords, etc. in Monitor Secret and use them in your monitors. Monitor Secret is encrypted and only accessible by the probe.

它解决的是监控场景下最典型的两个痛点:

  • 避免凭据散落:API 的Authorization头、SNMP 的 community string、Synthetic 脚本里的令牌等敏感值不必再以明文形式保存在监控步骤配置中,而是集中存放于一处;
  • 安全可审计:密钥值加密落库、保存后永不可回读,且每个密钥可以精确控制「哪些监控器有权限使用」,从存储到消费全程可控。

创建与管理 Monitor Secret

操作入口

在 OneUptime Dashboard 中按以下路径进入 Monitor Secrets 管理页:

Monitors -> Settings -> Secrets -> Create Monitor Secret

对应的前端页面实现位于 MonitorSecrets.tsx,是一个基于ModelTable<MonitorSecret>的标准 CRUD 表格页,支持创建、编辑、删除以及行级操作「Update Secret Value」。

表单字段说明

创建表单由四个字段组成,其中三个与密钥本身相关:

字段是否必填说明
Name密钥的名称,是项目内唯一的标识符。源码校验规则为:最短 2 个字符、不含空格、不含特殊字符,只能使用字母、数字、连字符(-)和下划线(_)(见 MonitorSecrets.tsx)
Description便于记忆的友好描述,例如「Api Key for GitHub」
Secret Value密钥本体,例如sk_test_...这样的真实凭据
Monitors which have access to this secret多选下拉,指定哪些监控器可以使用该密钥

其中 Name 字段的名称就是后续在监控配置中引用的名字。例如你在上图中创建了一个名为ApiKey的密钥并勾选了APIRequest这个监控器,那么在APIRequest的配置里就可以用{{monitorSecrets.ApiKey}}来引用它。

三个必须知道的安全行为

官方文档特别强调,密钥保存后有以下行为,这直接决定了密钥的运维方式:

  1. 值永不回显:Secret Value 一旦保存,就不会再出现在列表中、不会出现在编辑表单里,也不会通过 API 返回。前端实现中该字段使用doNotShowWhenEditing: true(见 MonitorSecrets.tsx),编辑时表单根本不渲染该字段;
  2. 丢失只能重设:由于值不可回读,如果你遗失了密钥原文,只能回到其来源系统(如第三方服务后台)重新获取,然后在 OneUptime 中重新设置;
  3. 轮换不需要删除重建:对需要更换的密钥,直接点击该行上的Update Secret Value按钮更新值即可,无需先删除再创建。这样密钥与监控器的授权关系、引用点都保持不变,只是底层的明文凭据被替换。

存储模型与加密实现

数据模型

MonitorSecret是一个标准的 OneUptime 数据库模型(定义见 MonitorSecret.ts),其核心字段如下:

字段类型说明
projectIdObjectID租户列(@TenantColumn),密钥归属于某个项目
nameShortText密钥名称,通过@UniqueColumnBy("projectId")保证同一项目内唯一
descriptionLongText可选描述
secretValueVeryLongText密钥值,标注encrypted: true,即加密后落库
monitorsEntityArrayMonitor多对多关系,即授权列表
createdByUserId/deletedByUserIdObjectID创建人 / 删除人审计字段

其中monitors关系由 TypeORM 的@ManyToMany实现,通过名为MonitorSecretMonitor的中间表连接monitorSecretIdmonitorId两列(见 MonitorSecret.ts)。该表在数据库迁移中也有对应的建表与外键定义(见 InitialMigration),外键ON DELETE CASCADE——删除密钥或监控器时,关联关系自动清理。

模型对外暴露的 CRUD API 路径为/monitor-secret@CrudApiEndpoint),服务层实现位于 MonitorSecretService.ts,继承自通用DatabaseService<MonitorSecret>。此外模型还开启了@EnableWorkflow,意味着密钥资源本身可以接入 OneUptime 的工作流自动化(创建 / 删除 / 更新 / 读取事件均可作为工作流触发点)。

加密实现

secretValue列标记为encrypted: true(见 MonitorSecret.ts),它归属于 OneUptime 的通用列加密机制。根据 EnvironmentConfig.ts 中的说明,所有@TableColumn({ encrypted: true })的列值——包括 OAuth 令牌、SMTP 密码、告警日历 feed token 以及 Monitor Secret——都会使用环境变量ENCRYPTION_SECRET进行AES 加密后再写入数据库。

这一点对自托管用户尤其重要:代码里专门提供了IsEncryptionSecretInsecure检查,如果ENCRYPTION_SECRET未设置、为空或仍使用仓库自带的占位符(以please-change-this前缀开头),启动日志会发出高音量警告——因为任何人拿到数据库导出,都可以用公开在仓库中的占位密钥解密所有加密列。因此自托管部署时,务必设置一个足够随机的ENCRYPTION_SECRET,这是 Monitor Secret 加密存储真正生效的前提。

另一个值得注意的细节是secretValue列级读取权限为空read: [],见 MonitorSecret.ts),意味着除了项目 Owner / Admin(表级read权限),任何角色都无法通过查询读取到密钥值——这正是「保存后永不可回读」在数据访问层的落地。

权限与计费门槛

MonitorSecret模型上同时声明了两类访问控制:

  • 表级计费控制@TableBillingAccessControl):create / read / update / delete均要求Growth 及以上计划,即 Monitor Secrets 属于 Growth 计划才开放的能力;
  • 表级权限控制@TableAccessControl):创建需ProjectOwner/ProjectAdmin/CreateMonitorSecret,读取需ReadMonitorSecret,更新需EditMonitorSecret,删除需DeleteMonitorSecret(见 MonitorSecret.ts)。四个动作均有对应的独立权限点,便于按角色精细授权。

在监控中使用 Secrets

引用语法

在监控配置中需要用到密钥的任意字段里,写入模板引用即可:

{{monitorSecrets.SECRET_NAME}}

例如官方文档的场景:在 API 监控的 Request Headers 中添加一个键APIKEY,值为{{monitorSecrets.ApiKey}},探针发起请求时就会携带解析后的真实密钥值。

支持的监控类型与可注入位置

官方文档明确列出四类,而仓库源码进一步证实了更多类型和字段位置。完整清单如下:

监控类型可注入位置
API请求头(request headers)、请求体(request body)、URL
Website / IP / Port / Ping / SSL Certificate监控目标 URL
Synthetic Monitor / Custom Code Monitor自定义脚本代码(customCode)
SNMP Monitor(Network Device)community string(SNMPv2 团体名)、SNMPv3 auth key、SNMPv3 priv key
SQL Query Monitor连接 password / username / host / databaseName,甚至查询语句本身
Database Health Monitor连接 password / username / host / databaseName
DNS Monitor自定义 DNS 服务器 hostname、查询名(query name)
Domain / DNSSEC Monitor域名
External Status Page Monitor状态页 URL
API / Website(mTLS 场景)TLS 客户端证书、客户端密钥、密钥口令(tlsClientCertificate/tlsClientKey/tlsClientKeyPassphrase

其中 API、Website、IP、Port、Ping、SSLCertificate 类监控注入的是monitorDestination(监控目标地址),API / Website 还支持 mTLS 证书与私钥的注入(见 MonitorStep.ts 的说明:Values can be raw PEM strings or {{monitorSecrets.name}} references)。SQL / Database 监控的字段则直接支持用{{monitorSecrets.name}}引用密码、用户名、主机名等敏感连接信息(见 MonitorStepSqlMonitor.ts 与 SqlConnectionConfig.ts)。

注入管线:占位符如何变成真实凭据

官方文档描述为「Secrets are injected on the probe before Synthetic or Custom Code monitor scripts execute」,即脚本执行前引用已解析为明文。从源码看,这一过程实际由后端 Telemetry 服务在向探针下发监控配置之前完成。核心实现在 Telemetry/Utils/Monitor.ts,主要分四步:

  1. 检测monitorStepsReferenceSecrets()检查监控步骤序列化的 JSON 字符串中是否包含子串monitorSecrets.,只有确实存在引用时才触发后续加载,避免对每个监控器都做一次多余的数据库查询;
  2. 加载loadMonitorSecrets(monitorId)通过MonitorSecretService.findBy查询「关联了该监控器」的密钥,且只selectnamesecretValue两个字段,使用isRoot: true的根级权限执行(见 Monitor.ts)。另有批量变体loadMonitorSecretsForMonitors,一次查询即可为一批监控器加载各自的密钥,并严格按monitors关系分组——某个监控器永远拿不到没有授予它的密钥(见 Monitor.ts);
  3. 填充populateSecretsInMonitorSteps()按监控类型遍历所有监控步骤,对匹配的字段(请求头、URL、脚本、SNMP 字段等)逐一执行替换(见 Monitor.ts);
  4. 替换fillSecretsInStringOrJSON()把密钥集合构造成{ monitorSecrets: { ApiKey: "真实值" } }这样的映射,再交给VMUtil.replaceValueInPlace完成{{monitorSecrets.ApiKey}}→ 真实值的文本替换(见 Monitor.ts)。

替换完成后,解析好的监控步骤随配置一起派发给探针。对 Synthetic / Custom Code 监控而言,探针执行脚本时拿到的customCode中已是解密后的明文,且该明文只存在于探针进程的内存执行上下文中,不会随探针回传的检查数据落库——这也是「密钥只对探针可见」的语义所在。此外,populateSecretsOnMonitorTest()说明 Monitor Test(监控测试运行)同样会执行这一套密钥解析,让你在正式上线前就能验证引用是否正确(见 Monitor.ts)。探针侧的 MonitorUtil.test.ts 亦覆盖了 URL 中{{monitorSecrets.ApiKey}}占位符的传递与解析行为。

访问控制与最小授权

Monitor Secret 的授权模型非常直接:monitors多对多关系本身就是授权。创建或编辑密钥时勾选的监控器列表,决定了哪些监控器在注入阶段能通过关系查询拿到该密钥;而这个授权是随时可更新的——想给新监控器授权,或回收某监控器的使用权,直接编辑该密钥的「Monitors which have access to this secret」字段即可,无需改动任何监控配置。

这套「按监控器授权」的机制与 OneUptime 对监控器自身凭据的最小权限设计是一脉相承的。仓库中 MonitorSecretKeyColumnAccessControl.test.ts 专门验证了监控器上三个 bearer 凭据列(serverMonitorSecretKeyincomingRequestSecretKeyincomingEmailSecretKey)的读取权限——只有具备轮换该密钥能力(ProjectOwner / ProjectAdmin / ProjectMember / MonitorAdmin / MonitorMember / EditProjectMonitor)的角色才能读取,纯粹的 Viewer / MonitorViewer 只读角色一律被拒绝,其原则是「能读到凭据的人必须同时具备吊销(轮换)它的能力」。Monitor Secret 的设计同样贯彻了这一原则:密钥的创建与授权由具备管理权限的人掌控,而普通只读用户既看不到密钥值,也无法把密钥授权给新的监控器。

最佳实践建议

综合文档与源码,以下是使用 Monitor Secrets 的几条建议:

  • 自托管务必先配置强随机的ENCRYPTION_SECRET:这是所有加密列(包括 Monitor Secret 值)AES 加密的根密钥,使用仓库默认占位符会让加密形同虚设;
  • 一个密钥只授权给必要的监控器:借由monitors关系实现最小授权,避免某个密钥在项目内被过多监控器共享;
  • 优先用Update Secret Value轮换而非删除重建:轮换保持引用与授权关系不变,操作成本最低;怀疑泄露时应立即轮换;
  • 明文只保留在来源系统:OneUptime 保存后不会回显密钥值,请在自己的密码管理器或来源系统中留存原文,以免遗失后无法恢复;
  • 上线前用 Monitor Test 验证引用:通过监控测试运行提前确认{{monitorSecrets.*}}引用解析正确,避免正式监控因密钥名拼写错误而失败;
  • 利用独立权限点做角色隔离CreateMonitorSecret/ReadMonitorSecret/EditMonitorSecret/DeleteMonitorSecret四个权限点可以按团队角色拆分,例如只给运维角色分配创建与授权能力,给监控维护角色分配使用能力。

Monitor Secrets 把「敏感凭据」从监控配置中剥离出来,统一收口到加密存储与按监控器授权的密钥体系中,配合模板语法注入,是 OneUptime 监控配置中处理 API Key、数据库口令、SNMP 凭据等敏感信息的标准姿势。

【免费下载链接】oneuptimeComplete open-source monitoring and observability platform.项目地址: https://gitcode.com/GitHub_Trending/on/oneuptime

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询