尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Memos 如何用 /etc/secrets 部署配置保护 SMTP、S3 与 AI 密钥不落库?

Memos 如何用 /etc/secrets 部署配置保护 SMTP、S3 与 AI 密钥不落库? Memos 如何用 /etc/secrets 部署配置保护 SMTP、S3 与 AI 密钥不落库【免费下载链接】memosOpen-source, self-hosted note-taking tool built for quick capture. Markdown-native, lightweight, and fully yours.项目地址: https://gitcode.com/GitHub_Trending/me/memos当 Memos 的 SMTP 密码、S3 凭据和 AI API Key 通过 UI/API 配置时它们会写进数据库的system_setting表。如果你的部署不想让这些密钥出现在数据库里Memos 支持把这些设置改由挂载文件提供Memos 在启动时扫描/etc/secrets目录把匹配文件名模式的 JSON 文件校验后加载为进程内的不可变配置快照密钥只存在于该目录的明文文件和进程内存中不写入idp、system_setting或任何状态文件。这篇文章给出 SMTPNOTIFICATION、S3 附件存储STORAGE和 AI 提供商AI三类密钥文件的完整写法、启动校验规则以及如何验证加载成功。工作机制文件如何变成生效配置依据设计文档 docs/configuration-provisioning.mdMemos 的文件加载遵循以下规则只扫描/etc/secrets的直接子文件不递归子目录也不创建、修改或删除该目录中的任何内容。目录中可以混放平台的其他密钥文件无关文件名会被静默忽略。文件名必须匹配小写 kebab-case 模式[a-z0-9](?:-[a-z0-9])*扩展名为小写.json。两个受支持的模式文件名模式消息类型稳定键memos-idp-label.jsonmemos.store.IdentityProvideruidmemos-instance-setting-label.jsonmemos.store.InstanceSettingkey每个匹配文件必须是一个合法的 protobuf JSON 消息、不含未知字段、不超过 1 MiB、只包含一个资源。这些约束在 store/deployment_config.go 中实现。文件内容可以含明文密钥——该目录被整体视为敏感目录。快照在启动时一次性构建数据库迁移和 demo seed 之后、HTTP 与后台服务启动之前加载。任何一个匹配文件无效快照不发布启动直接失败。启动日志按资源类型输出匹配数量但不打印文件内容。文件是进程内配置的权威来源文件声明的稳定键key或uid遮蔽数据库中同键的行UI 和 API 对文件背书的资源发起的创建、更新、删除会返回codes.FailedPrecondition。修改文件后必须重启进程才生效第一版不支持文件监听。删除文件并重启只是移除运行时覆盖数据库中被遮蔽的行原样保留并重新生效不会被删除或修改。文件名的label只是描述性标签资源身份由消息内部的key决定重命名文件不影响生效配置。准备 /etc/secrets 目录把三类设置文件按建议的规范文件名放入/etc/secrets/etc/secrets/ ├── memos-instance-setting-notification.json ├── memos-instance-setting-storage.json └── memos-instance-setting-ai.json建议文件名与资源键一一对应如NOTIFICATION对应memos-instance-setting-notification.json便于排查。目录本身可以不存在——缺失的目录或没有匹配文件的目录是正常 no-op。注意目录和文件必须对 Memos 进程可读文档建议对该目录使用 owner-only 或应用组可读的文件系统权限因为文件是敏感明文。一个关键约束同一设置键只允许一个文件声明例如不能有两个key都是STORAGE的文件重复会直接导致启动失败。编写 NOTIFICATION 文件SMTP 密钥不落库memos-instance-setting-notification.json包含一个key为NOTIFICATION的memos.store.InstanceSetting其中的smtpPassword只存在于文件中不会写入system_setting。下面的值全部来自 docs/configuration-provisioning.md 的文档示例实际部署时替换为你自己的 SMTP 信息{ key: NOTIFICATION, notificationSetting: { email: { enabled: true, smtpHost: smtp.example.com, smtpPort: 587, smtpUsername: memos, smtpPassword: smtp-secret, fromEmail: memosexample.com, fromName: Memos, replyTo: supportexample.com, useTls: true, useSsl: false } } }字段含义与 proto/store/instance_setting.proto 中的EmailSetting一一对应smtpHost/smtpPort指定 SMTP 服务器smtpUsername/smtpPassword是凭据fromEmail/fromName/replyTo控制发件人useTls/useSsl选择加密方式。启动校验规则由 store/deployment_config.go 的validateAndNormalizeDeploymentInstanceSetting执行key为NOTIFICATION时notificationSetting必须已填充否则报notificationSetting must be populated for key NOTIFICATION。email.enabled为 true 时smtpHost、正的smtpPort和fromEmail缺一不可否则报enabled notification email requires smtpHost, a positive smtpPort, and fromEmail。useTls与useSsl不能同时为 true否则报notification email cannot enable both useTls and useSsl。编写 STORAGE 文件S3 凭据不落库memos-instance-setting-storage.json承载附件存储配置。Memos 的存储模型见 proto/store/instance_setting.proto中storages列表存放存储实例defaultStorageId指定新附件写入哪一个STORAGE组的默认读取行为是存储类型、上传上限30 MiB、路径模板在对应字段未指定时回落到本地存储默认值。S3 的最小生效写法值以文档已有示例为模板access-key-id等为占位说明替换为你自己的凭据{ key: STORAGE, storageSetting: { storages: [ { id: s3-primary, name: Primary S3, type: STORAGE_TYPE_S3, s3Config: { accessKeyId: access-key-id, accessKeySecret: access-key-secret, endpoint: s3.example.com, region: us-east-1, bucket: memos } } ], defaultStorageId: s3-primary } }StorageS3Config的可用字段为accessKeyId、accessKeySecret、endpoint、region、bucket、usePathStyle、insecureSkipTlsVerify。其中insecureSkipTlsVerify会禁用对 S3 端点的 TLS 证书校验仅在内网使用自签名证书的可信端点才应开启——proto 注释明确说明它会移除对中间人攻击的保护。启动校验会拒绝以下配置默认存储是 S3 但缺accessKeyId、accessKeySecret、endpoint、region、bucket中任何一项报错形如storageSetting default S3 config.field is required。声明了 S3 但s3Config与storages均为空报错storageSetting.s3Config is required for S3注释说明这是为了大声失败而不是静默自愈成 LOCAL。uploadSizeLimitMb为负数。编写 AI 文件API Key 不落库memos-instance-setting-ai.json承载key为AI的设置。AI 部署配置走的是确定性的自包含归一化而不是 UI 更新路径规则是每个 provider 必须显式给出稳定的idloader 从不自动生成、title、受支持的typeOPENAI或GEMINI和非空apiKey缺一即报错。空端点会被归一化OpenAI 为https://api.openai.com/v1Gemini 为https://generativelanguage.googleapis.com/v1beta。providerid重复会被拒绝transcription.providerId必须引用同一配置中存在的 provider。任何 provider、API Key 或转写值都不会从被遮蔽的数据库设置中复制——文件是完整替换。示例模型名取自 proto 注释中的官方示例api-key为占位说明替换为你自己的密钥{ key: AI, aiSetting: { providers: [ { id: openai-main, title: OpenAI, type: OPENAI, apiKey: api-key }, { id: gemini-main, title: Gemini, type: GEMINI, apiKey: api-key } ], transcription: { providerId: openai-main, model: gpt-4o-transcribe, language: en } } }transcription.model可留空回落到引擎默认OpenAI 侧文档给出的示例有whisper-1、gpt-4o-transcribe、gpt-4o-mini-transcribeGemini 侧有gemini-2.5-flash默认、gemini-2.5-pro。transcription整个省略或providerId为空时语音转写功能保持禁用。启动并验证加载结果三类文件都放好或只放你需要的部分后正常启动 Memos。配置在数据库迁移和 demo seed 之后、服务对外提供之前加载验证分三步启动日志确认加载数量。加载成功后会输出INFO loaded deployment configuration identityProvidersn instanceSettingsn日志带的是匹配数量而不是文件内容用来确认文件名拼写正确——一个拼错的文件名不会静默生效只会使数量对不上。失败时看启动报错。无效文件会让启动直接失败错误信息定位到具体文件名和字段例如invalid instance setting deployment file memos-instance-setting-storage.json或字段级错误如config.oauth2Config.scopes[0] must not be empty。未知字段拼错的字段名会报unknown field ...——这是刻意保留的行为用于拦截为更新版本写的配置。运行期确认 UI/API 改不动。在管理界面尝试修改被文件覆盖的STORAGE/NOTIFICATION/AI分组或经 API 更新同一资源都会收到FailedPrecondition。这说明生效值确实来自文件而不是数据库同时 API 响应继续对 client secret、SMTP 密码、S3 secret 和 AI API Key 做脱敏密钥不会从任何接口回显。生效规则、边界与清理几个直接影响运维行为的规定整组替换不做字段合并。一个设置文件替换整个生效分组protobuf JSON 中省略的标量按 protobuf 默认值解码——省略不等于保留数据库里的旧值。同理文件中的空字符串密钥就是空值UI 更新那种空串保留原凭据的语义不适用于部署配置。修改文件必须重启。快照只加载一次运行中改动文件无效果Kubernetes Secret 卷这类平台管理的符号链接是受支持的文件形态。多副本要求挂载同一份文件。每个副本独立在启动时加载同一部署的所有副本必须挂载相同的文件改动认证或存储配置时使用不会把流量路由到不同文件代际副本的发布策略。BASIC和TAGS键被拒绝。BASIC包含实例密钥与数据库 schema 版本文件覆盖会破坏会话与迁移状态TAGS保留作兼容活动标签元数据按用户存储。SSO-only 部署需要两个文件。同时挂载身份提供方文件和memos-instance-setting-general.jsondisallowPasswordAuth为 true才能启用纯 SSO 行为——文件侧的GENERAL声明若禁用普通用户密码登录而没有任何生效的 IdP启动会直接报错。老版本数据库写入 bootstrap 的遗留清理。早期版本曾把memos-idp-*.json中的 IdP含 client secret拷进idp表新 loader 不会自动清理这些行。当文件遮蔽了同 UID 的存储 provider 时启动会打出不含密钥的告警deployment identity provider shadows a stored provider; the stored configuration remains in the database。文档给出的清理顺序是备份数据库并保留管理员密码 → 临时移除 IdP 文件并重启使存储 provider 不再被遮蔽 → 经管理员 UI/API 删除或更新该存储 provider或做等价的离线数据库维护→ 恢复文件并重启。在完成清理前旧的存储 provider 和密钥仍在数据库里文件被移除时会重新出现。不落库保证的适用范围。该保证针对新 loader文件内容不写入数据库。它不声称抹除早期版本已写入数据库的密钥。如果三类文件加载数量与预期一致、UI/API 对覆盖分组返回FailedPreconditionSMTP、S3 与 AI 密钥就只存在于/etc/secrets的挂载文件中——此后密钥的变更路径是改文件加重启而不是数据库更新。【免费下载链接】memosOpen-source, self-hosted note-taking tool built for quick capture. Markdown-native, lightweight, and fully yours.项目地址: https://gitcode.com/GitHub_Trending/me/memos创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表