Telegraf JOSE 密钥存储插件(secretstores.jose)完整指南:基于 JOSE 加密的文件型密钥管理方案
2026/9/14 23:26:41 网站建设 项目流程

Telegraf JOSE 密钥存储插件(secretstores.jose)完整指南:基于 JOSE 加密的文件型密钥管理方案

【免费下载链接】telegrafAgent for collecting, processing, aggregating, and writing metrics, logs, and other arbitrary data.项目地址: https://gitcode.com/GitHub_Trending/te/telegraf

导读

secretstores.jose是 Telegraf 在 v1.25.0 版本引入的密钥存储(Secret Store)插件,它利用 JavaScript Object Signing and Encryption(JOSE)算法族,将本地敏感信息以加密文件的形式保存在磁盘上,供 Telegraf 配置中需要密文的地方按需引用。读完本文,你将掌握该插件的配置项语义、@{<store-id>:<secret_key>}引用语法、telegraf secrets命令行的增删改查操作,以及它在仓库源码中的底层实现机制(keyring 文件后端、密码提示链路与接口注册方式),可以直接在真实环境中落地一套"配置文件不落明文"的密钥管理方案。

插件定位:为什么需要 JOSE 密钥存储

Telegraf 的配置中不可避免地要写入各类敏感信息:数据库口令、Token、API Key、证书私钥等。如果直接明文写在.conf文件中,一旦配置文件泄露或进入版本库,敏感数据就会随之暴露。Telegraf 的 Secret Store 机制正是为这一场景设计——插件只保存对密钥的"引用"(reference),真正的密钥值存放在独立的、受保护的密钥存储中,运行时才被解析出来

secretstores.jose是 Telegraf 内置的十余种密钥存储之一(仓库中同级的还有dockergooglecloudhttpoauth2ossystemdvault等,见 plugins/secretstores 目录)。它的特点是:

  • 纯本地:密钥以文件形式存放在指定的目录中,不依赖外部密钥管理服务;
  • 加密保护:每个密钥文件受 JOSE(JavaScript Object Signing and Encryption)算法保护,必须提供正确口令才能读取;
  • 静态引用:从源码看,它返回的解析函数是静态的(详见下文GetResolver实现),适合内容不会随时间轮换的长期凭证。

配置详解:sample.conf 全参数拆解

插件的官方示例配置位于 plugins/secretstores/jose/sample.conf,与其 README.md 中toml @sample.conf注入的内容一致。完整配置如下:

# Read secrets from Javascript Object Signing and Encryption file [[secretstores.jose]] ## Unique identifier for the secret store. ## This id can later be used in plugins to reference the secrets ## in this secret store via @{<id>:<secret_key>} (mandatory) id = "secretstore" ## Directory for storing the secrets path = "/etc/telegraf/secrets" ## Password to access the secrets. ## If no password is specified here, Telegraf will prompt for it at startup time. # password = ""

各参数语义如下:

参数必填类型说明
idstring密钥存储的唯一标识符,用于在插件配置中通过@{<id>:<secret_key>}引用本存储内的密钥
pathstring存放密钥文件的目录,每个密钥单独存储在一个文件中
passwordstring / 环境变量 / 另一密钥存储的引用访问密钥文件所需的口令;不配置时 Telegraf 启动时会交互式提示输入

对应到源码结构,三个配置项被直接映射为Jose结构体的字段(见 plugins/secretstores/jose/jose.go):

type Jose struct { ID string `toml:"id"` Path string `toml:"path"` Password config.Secret `toml:"password"` ... }

口令的三种提供方式

根据 README 与源码Init()实现(jose.go),password参数的取值优先级与形态十分灵活:

  1. 配置字面量:直接在password中写入字符串;
  2. 环境变量:利用 Telegraf 的环境变量替换机制引用$VAR形式的环境变量;
  3. 跨存储引用:写成@{other-store:key},引用另一个密钥存储中的密钥作为本存储的口令(此时口令本身也不落明文)。

如果以上都未提供,Init()会使用keyring.TerminalPrompt作为口令提示函数,在 Telegraf 启动时于终端交互式询问口令。此外源码还保留了一个兜底分支:若插件级password为空,会尝试使用全局配置口令config.Password(见 jose.go)。

[!NOTE] 该存储中所有密钥都使用同一个口令加密。若你需要为每个密钥单独设置口令,请创建多个[[secretstores.jose]]实例,各自指定不同的pathpassword

初始化失败时的校验逻辑

Init()中的校验顺序清晰反映了必填约束:

  • id为空 → 报错id missing
  • path为空 → 报错path missing
  • 口令解析失败(例如引用了一个不存在的密钥)→ 报错getting password failed

这三条错误分支在 jose_test.go 的TestInitFail表驱动测试中被逐一验证。

密钥引用语法:@{store-id:secret-key}

密钥存储与插件之间的接线方式采用统一的引用语法(定义见 docs/includes/secret_usage.md):

@{<store-id>:<secret_key>}

其中store-id对应当前[[secretstores.jose]]配置块中的id参数,secret_key是该存储中某个密钥文件的名称(即写入密钥时的 key)。

该引用语法的正则校验在 config/secret.go 中定义:

// secretStorePattern is a regex to validate secret store IDs var secretStorePattern = regexp.MustCompile(`^\w+$`) // secretPattern is a regex to extract references to secrets store in a secret store var secretPattern = regexp.MustCompile(`@\{(\w+:\w+)\}`)

可见 store-id 与 secret_key 都要求为单词字符(\w),因此命名时应避免使用空格、连字符等特殊字符。

并非所有插件、所有选项都支持密钥存储。判断某个插件是否支持,需要查看该插件 README 中是否存在Secret store support章节,里面会列出支持密钥引用的具体选项。例如plugins/outputs/influxdb/README.md中就包含此类说明,其余插件同理。在支持密钥的选项(如 password、token 等字段)中直接写入@{store-id:key}即可,Telegraf 会在配置加载阶段解析并链接到对应密钥存储。

实战操作:用 telegraf secrets 命令管理密钥

Telegraf 提供了专门的 CLI 子命令来管理所有已注册密钥存储中的密钥,实现在 cmd/telegraf/cmd_secretstore.go。命令均需要传入包含密钥存储定义(即[[secretstores.jose]]配置块)的配置文件,默认从配置文件位置自动加载。

列出密钥

# 列出所有已知存储中的全部密钥 key telegraf secrets list # 仅列出指定存储(按 id 指定)中的密钥 telegraf secrets list secretstore # 同时展示密钥值(慎用,会输出明文) telegraf secrets list --reveal-secret

查看单个密钥

telegraf secrets get secretstore mysecretkey

输出格式为secretstore:mysecretkey = <value>。从源码看(cmd_secretstore.go),该命令接受两个位置参数:<secret store ID><secret key>

写入 / 修改密钥

# 直接指定值 telegraf secrets set secretstore mysecretkey mysecretvalue # 省略值时交互式输入(终端不回显) telegraf secrets set secretstore mysecretkey

若指定 key 已存在则覆盖其值。注意setremove命令要求存储实现telegraf.SecretStoreEditor接口(即支持写入/删除的存储),只读型存储会被拒绝,提示secret store "..." does not support setting secrets

删除密钥

telegraf secrets remove secretstore mysecretkey

删除一个不存在的 key 会返回错误——这与Remove的测试行为一致(jose_test.go,对不存在的 key 返回fs.ErrNotExist)。

源码剖析:从 keyring 文件后端到接口实现

该插件的核心实现非常精简(单个 jose.go 文件,约 115 行),其底层依赖开源库github.com/99designs/keyring,选用其中的FileBackend作为加密文件后端:

// Setup the actual keyring cfg := keyring.Config{ AllowedBackends: []keyring.BackendType{keyring.FileBackend}, FileDir: j.Path, FilePasswordFunc: promptFunc, } kr, err := keyring.Open(cfg)

这里FileDir即配置中的pathFilePasswordFunc则是根据口令提供方式构造的提示函数。也就是说,"JOSE 算法保护"这一能力实际由 keyring 的文件后端实现——它以配置目录为根,每个密钥一个文件,并使用口令对文件内容进行 JOSE(JavaScript Object Signing and Encryption,涵盖 JWS/JWE 等标准的加密格式)加密。这也是"所有密钥共用一个口令"约束的直接来源。

实现的接口与注册机制

从源码可确认该插件实现了两层接口:

  1. telegraf.SecretStore接口(secretstore.go),包含GetListGetResolver三个核心方法:

    • Get(key):从 keyring 中取出密钥的字节内容;
    • List():列出所有已知的密钥 key(对应 keyring 的Keys());
    • GetResolver(key):返回一个解析函数,供配置在运行时惰性取值,其中第二个返回值固定为false,表示该解析器是静态的(密钥不会随时间变化,区别于 TOTP 等动态场景)。
  2. telegraf.SecretStoreEditor可选接口(secretstore.go),提供Set(创建或修改)与Remove(删除),这也是secrets set/secrets remove命令能作用于该存储的原因。文件型存储天然可写,因此该插件同时实现了这两组接口。

插件通过init()完成注册(jose.go):

func init() { secretstores.Add("jose", func(id string) telegraf.SecretStore { return &Jose{ID: id} }) }

注册表定义在 plugins/secretstores/registry.go,而插件要真正进入 Telegraf 二进制,还需要在 plugins/secretstores/all/jose.go 中以带 build-tag 的形式 import 注册。该 build tag 机制(!custom || secretstores || secretstores.jose)配合tools/custom_builder,可以在定制构建时选择性裁剪插件体积。

测试与行为验证

仓库为插件提供了覆盖较全的单元测试(plugins/secretstores/jose/jose_test.go),可作为理解其行为边界的权威依据:

测试函数验证行为
TestInitFailid/path缺失、口令引用不可解析时的初始化错误
TestSetListGet写入多个密钥后,目录中出现同名文件(且为普通文件而非目录),List/Get可完整还原
TestRemove删除某个 key 后其余密钥不受影响,被删密钥不可再读取
TestRemoveNonExistent删除不存在的 key 返回fs.ErrNotExist
TestResolver/TestResolverInvalid解析函数对存在的 key 返回静态值(dynamic=false),对不存在的 key 返回错误
TestGetNonExistent读取不存在的 key 报错The specified item could not be found in the keyring
TestGetInvalidPassword用错误口令读取已有密钥时报integrity check failed,印证了密钥文件的加密完整性校验机制

其中TestGetInvalidPassword是理解安全模型的关键:密钥文件带有完整性校验,口令错误时不会返回乱码,而是直接失败,避免在配置层静默使用错误值。

典型落地示例:结合 InfluxDB 输出插件

下面给出一个最小可运行的完整场景(展示文件型 JOSE 密钥存储的典型用法):

  1. 编写密钥存储配置(例如secrets.conf):
[[secretstores.jose]] id = "secretstore" path = "/etc/telegraf/secrets" # 口令也可以来自环境变量:password = "${TELEGRAF_SECRETS_PASSWORD}"
  1. 写入并验证密钥
telegraf secrets set --config secrets.conf secretstore influxdb-token 'my-super-secret-token' telegraf secrets list --config secrets.conf secretstore
  1. 在支持密钥存储的插件选项中引用(例如在 InfluxDB 输出插件配置中,将原本明文写入的 token 替换为):
[[outputs.influxdb]] urls = ["http://localhost:8086"] token = "@{secretstore:influxdb-token}"

之后正常启动 Telegraf,配置加载阶段会解析@{...}引用,从 JOSE 加密文件中解密出真实 token。注意运行时仍需正确提供口令(配置文件中的password、环境变量或启动时交互输入),否则密钥无法解析。

适用前提与注意事项

  • 版本要求:该插件自Telegraf v1.25.0起提供(README 标注⭐ Telegraf v1.25.0),且仅注册了jose一个存储类型;使用前请确认版本。
  • 平台:README 标注💻 all,即所有平台均可使用。
  • 口令一致性与轮换:同一实例下所有密钥共用口令;更换口令意味着需重新写入全部密钥。
  • 引用命名:store-id 与 secret_key 受\w正则约束,建议使用字母、数字、下划线命名。
  • 动态密钥:本存储返回静态解析器(dynamic=false),不适合 TOTP 等需要周期性轮换取值的场景;此类需求应选择支持动态解析的存储类型。
  • 开发扩展:若需实现自己的密钥存储,可参照 docs/SECRETSTORES.md 中的插件开发指南与接口约定(SecretStore/SecretStoreEditorsecretstores.Add注册、sample.conf注入等)。

【免费下载链接】telegrafAgent for collecting, processing, aggregating, and writing metrics, logs, and other arbitrary data.项目地址: https://gitcode.com/GitHub_Trending/te/telegraf

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

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

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

立即咨询