Grafana Tempo 中的 AWS SigV4 签名:深入解析 prometheus/sigv4 RoundTripper 模块与 remote_write 集成
2026/9/19 21:48:07 网站建设 项目流程

Grafana Tempo 中的 AWS SigV4 签名:深入解析 prometheus/sigv4 RoundTripper 模块与 remote_write 集成

【免费下载链接】tempoGrafana Tempo is a high volume, minimal dependency distributed tracing backend.项目地址: https://gitcode.com/GitHub_Trending/tempo1/tempo

本文以 Grafana Tempo 仓库内 vendor 的 prometheus/sigv4 README 及其源码为线索,讲解该模块如何实现 AWS Signature Version 4(SigV4)请求签名,以及它在 Tempo metrics-generator 远程写入(remote_write)到 AWS 托管 Prometheus 服务时的实际应用。读完本文,你将掌握 sigv4 模块的核心 API、SigV4Config全部配置字段与校验规则、签名请求的底层流程,并能在 Tempo 配置文件中正确启用 SigV4 认证。

一、sigv4 模块是什么

github.com/prometheus/sigv4是一个独立的 Go 模块,它在 README 中自我定位非常清晰:

sigv4 provides a http.RoundTripper that will sign requests using Amazon's Signature Verification V4 signing procedure, using credentials from the default AWS credential chain.

即:它提供一个实现了http.RoundTripper接口的组件,用于按照 AWS SigV4 签名流程为 HTTP 请求签名,签名所需凭证来自 AWS 默认凭证链。它不关心请求要发给谁,只负责"在请求发出前,为它加上合法的 SigV4 认证信息"。

该模块被设计成独立于github.com/prometheus/common发布,README 明确说明了原因:

This is a separate module from github.com/prometheus/common to prevent it from having and propagating a dependency on the AWS SDK.

即:独立成模块是为了避免 Prometheus 公共库被迫引入并向外传播 AWS SDK 依赖,只有真正需要 SigV4 签名的项目(或模块)才引入它。同时 README 也提醒:

This module is considered internal to Prometheus, without any stability guarantees for external usage.

即该模块在 Prometheus 生态中被视为内部模块,对外部使用不提供稳定性保证——升级时 API 可能变动,生产使用需锁定版本。

在 Tempo 仓库中,该模块以 v0.4.1 版本被 vendor 进 vendor/github.com/prometheus/sigv4 目录,并在 go.mod 中声明为间接依赖(// indirect),由 Tempo 依赖的 Prometheus 配置库传递引入。

二、核心 API:NewSigV4RoundTripper

模块对外暴露的入口是一个构造函数,定义在 vendor/github.com/prometheus/sigv4/sigv4.go:

// NewSigV4RoundTripper returns a new http.RoundTripper that will sign requests // using Amazon's Signature Verification V4 signing procedure. The request will // then be handed off to the next RoundTripper provided by next. If next is nil, // http.DefaultTransport will be used. // // Credentials for signing are retrieved using the the default AWS credential // chain. If credentials cannot be found, an error will be returned. func NewSigV4RoundTripper(cfg *SigV4Config, next http.RoundTripper) (http.RoundTripper, error)

两个参数的含义:

  • cfg *SigV4Config:签名配置,见下文第三节。所有字段均可留空,空值会回退到 AWS 默认凭证链解析。
  • next http.RoundTripper:签名完成后的下一跳传输器,nil时使用http.DefaultTransport

构造函数内部做了四件关键的事,均可在 sigv4.go 源码中逐一印证:

  1. 装配 AWS SDK 加载选项:根据配置动态追加config.WithCredentialsProvider(静态 AccessKey/SecretKey)、config.WithUseFIPSEndpoint(FIPS 端点开关)、config.WithRegionconfig.WithSharedConfigProfile
  2. 加载并预检凭证:调用config.LoadDefaultConfig后立即执行awscfg.Credentials.Retrieve(ctx)若默认凭证链上找不到任何凭证,构造函数直接返回错误"could not get SigV4 credentials";若最终 region 为空,同样返回错误"region not configured in sigv4 or in default credentials chain"。这是"失败要快"的设计——签名器不会在请求发出时才报凭证缺失。
  3. 支持 STS AssumeRole:当RoleARN非空时,用stscreds.NewAssumeRoleProvider包装凭证提供者,并可附带ExternalID,实现跨账号/角色切换签名身份。
  4. 确定签名服务名:默认serviceName = "aps"(即 Amazon Prometheus Service),可通过配置覆盖。

返回的sigV4RoundTripper结构体包含 region、下一跳 transport、sync.Pool字节缓冲池、*aws.CredentialsCache凭证缓存和*signer.Signer签名器,其中凭证缓存(aws.NewCredentialsCache)配置了30 秒过期窗口和 0.5 抖动系数(见 credentialCacheOptions),避免大量并发请求在凭证即将过期时同时刷新。

三、SigV4Config:配置字段与校验规则

SigV4Config定义在 vendor/github.com/prometheus/sigv4/sigv4_config.go,全部字段带 YAML tag,可直接嵌入 Prometheus 风格的 YAML 配置:

YAML 字段Go 类型说明
regionstringAWS 区域,为空时从默认凭证链解析
access_keystring静态 Access Key,与secret_key必须成对出现
secret_keyconfig.Secret静态 Secret Key,类型为config.Secret(安全字符串,打印时会被遮蔽)
profilestringAWS 共享配置文件(~/.aws/credentials等)中的 profile 名
role_arnstring要扮演的 IAM 角色 ARN,启用 STS AssumeRole
external_idstringAssumeRole 的 External ID,只能与role_arn配合使用
use_fips_sts_endpointbool是否启用 STS 的 FIPS 端点
service_namestringSigV4 签名服务名,默认aps(Amazon Prometheus Service)

所有字段均带omitempty,即**"留空即走 AWS 默认凭证链"**——这是该模块的核心设计哲学:默认情况下,凭证、区域都会按 AWS 标准顺序从环境变量、共享凭证文件、ECS/EC2 元数据等默认凭证链中获取。

SigV4Config实现了UnmarshalYAML,在反序列化后立即调用Validate()(sigv4_config.go),强制两条配置规则:

func (c *SigV4Config) Validate() error { if (c.AccessKey == "") != (c.SecretKey == "") { return fmt.Errorf("must provide a AWS SigV4 Access key and Secret Key if credentials are specified in the SigV4 config") } if c.ExternalID != "" && c.RoleARN == "" { return fmt.Errorf("external_id can only be used with role_arn") } return nil }

即:AccessKey 与 SecretKey 必须同时提供或同时留空ExternalID 只有在配置了 RoleARN 时才有意义,否则配置校验直接失败。这意味着即使配置写错,错误也会在配置加载阶段暴露,而不是在运行时签名失败才暴露。

四、签名流程:RoundTrip 内部实现

签名在sigV4RoundTripper.RoundTrip中完成,见 sigv4.go。完整流程如下:

  1. 复用缓冲池:从sync.Pool取一个bytes.Buffer(初始容量 1KB,见 newBuf),defer保证归还,减少高并发下 GC 压力。
  2. 计算请求体哈希:若req.Body非空,把 body 整体拷贝进缓冲池,关闭原 body,用sha256.Sum256计算请求体哈希并 hex 编码;空 body 则使用预置的空串 SHA256 常量e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855。SigV4 规范要求签名必须覆盖请求体哈希,这就是其中的X-Amz-Content-Sha256值的来源。
  3. 规范化 URL 路径:按 AWS 文档要求执行req.URL.Path = path.Clean(req.URL.Path),消除路径中的...冗余,保证 canonical request 与 AWS 侧计算一致。
  4. 克隆请求并剔除 denylist 头req.Clone(req.Context())后删除签名黑名单头。当前黑名单为(sigv4HeaderDenylist):
    var sigv4HeaderDenylist = []string{ "uber-trace-id", }

    原因是uber-trace-id这类链路追踪头每跳都会变化,若参与签名会导致签名校验失败;签名完成后,再把原始请求中的该头恢复回去(见 sigv4.go)——即"签名时不带,发送时带上"。

  5. 获取凭证并签名:从凭证缓存rt.creds.Retrieve(ctx)获取当前有效凭证,调用 AWS SDK 的signer.SignHTTP(ctx, creds, signReq, strHash, serviceName, region, time.Now().UTC())为克隆出的请求写入AuthorizationX-Amz-DateX-Amz-Content-Sha256X-Amz-Security-Token(临时凭证时)等头。
  6. 交给下一跳发送:最终return rt.next.RoundTrip(signReq),把带签名的请求交给原始 transport 发出。

需要注意一个实现细节:签名发生在请求体被缓冲读取之后,因此RoundTrip期间 body 是可重读的bytes.Reader;同时签名目标与发送目标都是同一个克隆后的请求对象,原始req的 header 用于恢复黑名单头。这套实现与 Go 标准http.Client的中间件链可以无缝组合。

五、在 Grafana Tempo 中的实际应用:metrics-generator remote_write

sigv4 模块在 Tempo 中并非直接调用,而是通过Prometheus remote_write 配置体系间接生效,这条链路可以在源码中完整追踪:

  1. Tempo 的 metrics-generator 存储配置Config.RemoteWrite使用[]prometheus_config.RemoteWriteConfig类型,见 modules/generator/storage/config.go:
    // Prometheus remote write config // https://prometheus.io/docs/prometheus/latest/configuration/configuration/#remote_write RemoteWrite []prometheus_config.RemoteWriteConfig `yaml:"remote_write,omitempty"`
  2. 该类型来自 vendor 的 Prometheus 配置库,其结构体 RemoteWriteConfig 中内嵌了认证配置:
    SigV4Config *sigv4.SigV4Config `yaml:"sigv4,omitempty"` AzureADConfig *azuread.AzureADConfig `yaml:"azuread,omitempty"` GoogleIAMConfig *googleiam.Config `yaml:"google_iam,omitempty"`
  3. 因此,Tempo 的remote_write条目下可以直接写sigv4:块。配置校验逻辑(config.go)强制签名认证方式互斥basic_authauthorizationoauth2sigv4azureadgoogle_iam六种方式最多配置一种,否则报错。

以 Tempo metrics-generator 向 AWS 托管 Prometheus(APS)远程写入为例,最小可用配置形如:

metrics_generator: storage: remote_write: - url: https://aps-workspaces.us-east-1.amazonaws.com/workspaces/<workspace-id>/api/v1/remote_write sigv4: region: us-east-1 service_name: aps queue_config: max_samples_per_send: 1000
  • region也可以省略,交由默认凭证链解析;service_name默认就是aps,通常也无需显式写出。
  • 若 Tempo 运行在 EC2/ECS 上,可完全省略access_key/secret_key,通过实例 IAM 角色自动获取凭证;若在本地开发,可通过AWS_ACCESS_KEY_ID/AWS_SECRET_ACCESS_KEY环境变量或~/.aws/credentials提供。
  • 需要跨账号写入时,配置role_arn(可选加external_id),模块会走 STS AssumeRole。
  • 需要 FIPS 合规环境时,设置use_fips_sts_endpoint: true

注意:与remote_write相关联,Tempo 还默认开启remote_write_add_org_id_header(默认值为true,见 modules/generator/storage/config.go),多租户场景下会为每个租户注入X-Scope-OrgID头,这一点在对接 AWS 托管 Prometheus 的租户隔离/权限映射时也值得留意。

六、使用注意事项与边界

结合源码实现,有几个实践要点值得记录:

  1. 凭证错误尽早暴露NewSigV4RoundTripper在构造时就会尝试拉取凭证并校验 region,所以"凭证链未配置"会在启动阶段立刻报错,而不是等到第一次写请求才失败(sigv4.go)。
  2. 请求体会被整体读入内存:为了计算 SigV4 要求的 body 哈希,RoundTrip会把整个 body 缓冲到内存中。对超大 payload 的接口需要评估内存开销;remote_write 场景下 body 本身就是批量样本,符合该模块的设计预期。
  3. URL 路径会被path.Clean规范化/a/../b这类路径在签名前会被清洗,如果你的端点依赖未被清洗的原始路径,需要自行确认兼容性。
  4. 链路追踪头被排除在签名外uber-trace-id不会参与签名计算,避免链路上下文头导致签名不一致;发送时该头仍会原样保留。
  5. 模块稳定性:README 明确 sigv4 是 Prometheus 内部模块、外部使用无稳定性保证,升级 Tempo 或 Prometheus 库版本时若涉及该模块,建议关注其行为变更。
  6. 配置互斥:一个 remote_write 目标只能使用一种认证方式(sigv4basic_auth/oauth2等互斥),错误配置会在配置校验阶段被拒绝(config.go)。

七、小结

github.com/prometheus/sigv4虽然是一个体量很小的模块(两个 Go 源文件 + 一个 README),但它精确地解决了"给 HTTP 请求加上 AWS SigV4 签名"这一横切问题:以标准http.RoundTripper形式提供中间件能力、默认接入 AWS 默认凭证链、内置 STS AssumeRole 与 FIPS 支持、在构造期做凭证预检、并通过SigV4Config的 YAML 校验兜底配置错误。在 Grafana Tempo 中,它经由 Prometheus remote_write 配置体系,成为 metrics-generator 向 AWS 托管 Prometheus 安全推送指标的关键一环——理解它的配置字段与签名流程,即可在生产环境中正确、安全地启用 AWS 认证的远程写入链路。

【免费下载链接】tempoGrafana Tempo is a high volume, minimal dependency distributed tracing backend.项目地址: https://gitcode.com/GitHub_Trending/tempo1/tempo

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

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

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

立即咨询