news 2026/9/15 17:20:43

Envoy AWS 请求签名扩展架构:凭证提供链、SigV4 签名与异步凭证获取深度解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Envoy AWS 请求签名扩展架构:凭证提供链、SigV4 签名与异步凭证获取深度解析

Envoy AWS 请求签名扩展架构:凭证提供链、SigV4 签名与异步凭证获取深度解析

【免费下载链接】envoyCloud-native high-performance edge/middle/service proxy项目地址: https://gitcode.com/GitHub_Trending/en/envoy

导读

Envoy 通过aws_request_signingaws_lambda两个扩展,在代理层直接完成对 AWS API 的请求签名,让下游服务无需感知 AWS SDK 即可安全访问 S3、Lambda、SQS 等云资源。本文以 source/extensions/common/aws/README.md 为骨架,结合source/extensions/common/aws/下的源码实现,系统讲解 AWS 公共组件的六大核心机制:凭证提供器(Credentials Provider)、默认凭证提供链、基于元数据服务的异步凭证提供器、AWS 集群管理器、SigV4/SigV4A 签名器,以及支撑签名流程不中断的异步凭证获取订阅通知模型。读完本文,你将理解 Envoy 内部如何像 AWS SDK 一样定位并刷新凭证、如何复用内部集群完成元数据抓取、如何在凭证尚未就绪时暂停上游请求,以及 IAM Roles Anywhere 基于 X509 证书的新式签名如何落地。

一、整体架构概览

AWS 公共组件(Envoy::Extensions::Common::Aws)位于 source/extensions/common/aws,是aws_request_signingaws_lambda两个扩展共用的底层库。整体架构可分为四层:

  1. 凭证层(Credentials)Credentials容器(AccessKeyId / SecretAccessKey / SessionToken)与各类CredentialsProvider,负责从不同来源获取凭证;
  2. 编排层(Chain + Cluster Manager)CredentialsProviderChain按优先级串联多个提供器,AwsClusterManager统一管理用于抓取元数据的内部集群;
  3. 元数据抓取层(MetadataFetcher):以异步 HTTP 请求方式从 IMDS、ECS/EKS 容器代理或 STS 服务抓取临时凭证;
  4. 签名层(Signer):基于凭证对 HTTP 请求执行 SigV4 / SigV4A 签名,并暴露“凭证未就绪则暂停”的异步回调接口。

各核心类型的继承关系可从源码直接印证:所有凭证提供器继承自CredentialsProvider(credentials_provider.h),元数据类提供器继承自MetadataCredentialsProviderBase(metadata_credentials_provider_base.h),签名器统一实现Signer接口(signer.h)。

二、凭证提供器(Credential Providers)

2.1 设计思想:与 AWS SDK 对齐

Credential Providers(Envoy::Extensions::Common::Aws::CredentialsProvider)的实现方式与 AWS SDK 高度类似:每个提供器专职从一种特定来源获取凭证,彼此职责单一、可插拔。接口定义见 credentials_provider.h,核心方法有三个:

  • providerName():返回提供器名称(用于日志与统计);
  • getCredentials():同步返回当前可用凭证;
  • credentialsPending():返回是否仍处于凭证获取中(异步提供器专用)。

Credentials是一个不可变容器,构造时要求 access key 与 secret key 同时非空才认为是有效凭证,并提供hasCredentials()判断方法;所有组件在环境中找不到时返回std::nullopt,且空字符串同样视为未找到

2.2 静态凭证提供器

最简单的两类是静态来源提供器:

  • EnvironmentCredentialsProvider:从环境变量AWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEYAWS_SESSION_TOKEN读取凭证;
  • ConfigCredentialsProvider:从 Envoy 静态配置内嵌的凭证读取(对应inline_credential配置)。

这两类不需要任何网络交互,因此也不参与异步刷新机制,是“同步即得”的最快路径。

2.3 元数据类提供器

其余提供器均属于元数据类,需要向 AWS 的元数据/STS 端点发起 HTTP 请求:

提供器凭证来源集群类型
InstanceProfileCredentialsProviderEC2 实例元数据服务 IMDS(169.254.169.254STATIC
ContainerCredentialsProviderECS/EKS 容器代理(AWS_CONTAINER_CREDENTIALS_RELATIVE_URI/AWS_CONTAINER_CREDENTIALS_FULL_URISTATIC
WebIdentityCredentialsProviderSTS AssumeRoleWithWebIdentity(token 来自文件或环境)LOGICAL_DNS
AssumeRoleCredentialsProviderSTS AssumeRoleLOGICAL_DNS
IAMRolesAnywhereCredentialsProviderIAM Roles Anywhere(基于 X509 证书)LOGICAL_DNS
CredentialsFileCredentialsProvider本地~/.aws/credentials文件静态

全部实现位于 credential_providers 目录。

2.4 刷新节奏与统计

元数据提供器在 metadata_credentials_provider_base.h 中统一定义了统计项:

  • credential_refreshes_performed(Counter):执行刷新次数;
  • credential_refreshes_failed(Counter):刷新失败次数;
  • credential_refreshes_succeeded(Counter):刷新成功次数;
  • metadata_refresh_state(Gauge):当前刷新状态。

凭证缓存的默认刷新策略定义在 credentials_provider.h:

  • REFRESH_INTERVAL = 1h:正常状态下凭证的缓存刷新周期;
  • REFRESH_GRACE_PERIOD = 60s:到期前的宽限期,避免临界时刻使用过期凭证;
  • MAX_CACHE_JITTER = 30s:最大刷新抖动,用于打散大规模实例同时刷新的峰值。

三、凭证提供链(Credential Provider Chain)

3.1 链式降级模型

CredentialsProviderChain(credentials_provider.h)是一个有序的凭证提供器列表。核心逻辑:

  • add(provider)追加提供器;
  • chainGetCredentials()从头到尾遍历,返回第一个能给出凭证的提供器的结果;
  • 一旦前序提供器通过getCredentials()返回了凭证,后续提供器不再被检查(这与 AWS SDK 的AWSCredentialsProviderChain语义一致,源码注释也明确引用了 aws-sdk-cpp 的参考实现)。

因此,链的顺序即凭证解析的优先级顺序。

3.2 默认凭证提供链

通过Extensions::Common::Aws::CommonCredentialsProviderChain::defaultCredentialsProviderChain可一键创建默认链,其定义在 credential_provider_chains.cc。README 明确给出的链顺序如下:

  1. EnvironmentCredentialsProvider(环境变量)
  2. CredentialsFileCredentialsProvider(本地凭证文件)
  3. IAMRolesAnywhereCredentialsProvider(Roles Anywhere)
  4. WebIdentityCredentialsProvider(Web Identity / STS)
  5. ContainerCredentialsProvider(ECS/EKS 容器代理)
  6. InstanceProfileCredentialsProvider(EC2 实例元数据)

从 credential_provider_chains.cc 的实现可以看到默认链的构建细节:无自定义配置时,代码依次构造environmentcredentials_filecontainerinstance_profileassume_role_with_web_identity五类提供器(此时 Roles Anywhere 仅在用户显式提供其配置时才被合并进链);若用户提供了部分提供器的自定义配置(如 Web Identity 的 token 文件路径、凭证文件的 profile 等),则通过MergeFrom合并覆盖。

该顺序体现了“越靠近本地、越廉价的方式越优先”:环境变量与文件解析零网络开销,其次是容器/实例元数据这类内网端点,最后才是需要额外网络跳转的 STS 类服务。

3.3 自定义凭证提供链

除了默认链,credential_provider_chains.h 还提供了customCredentialsProviderChain:完全由用户在配置中指定提供器集合与顺序。其校验逻辑在 credential_provider_chains.cc:自定义链至少需要包含一个凭证提供器,否则返回InvalidArgumentError。同时,源码对 AssumeRole 提供器做了一层防护——若 AssumeRole 内部再嵌套 AssumeRole,会记录 warning 并忽略内层配置(credential_provider_chains.cc),避免无限递归。

3.4 默认环境变量约定

Web Identity 与 Container 提供器在无显式配置时,依赖标准 AWS 环境变量(credential_provider_chains.cc):

  • AWS_WEB_IDENTITY_TOKEN_FILE:Web Identity token 文件路径;
  • AWS_ROLE_ARN:目标角色 ARN;
  • AWS_ROLE_SESSION_NAME:会话名(未设置时源码会用纳秒级时间戳生成,见 credential_provider_chains.h);
  • AWS_CONTAINER_CREDENTIALS_RELATIVE_URI:容器凭证相对 URI(优先使用);
  • AWS_CONTAINER_CREDENTIALS_FULL_URI:容器凭证完整 URI(备选);
  • AWS_CONTAINER_AUTHORIZATION_TOKEN:访问容器凭证端点时的授权 token;
  • AWS_EC2_METADATA_DISABLED:设为"true"时跳过 InstanceProfile 提供器(credential_provider_chains.cc)。

一个值得注意的细节:Web Identity 的 token 若来自文件,源码会自动为其配置watched_directory(credential_provider_chains.cc),从而在 Kubernetes 等场景下 token 文件被自动轮换时能实时感知并加载新 token。

四、元数据凭证提供器(Metadata Credential Providers)

4.1 异步 HTTP 抓取模型

元数据凭证提供器(Envoy::Extensions::Common::Aws::MetadataCredentialsProviderBase)是凭证提供器的异步子类:它通过异步 HTTP 请求从远端抓取凭证。为此它依赖两样基础设施:

  • 上游集群:由 AWS 集群管理器(AWS Cluster Manager)创建,用于发起 HTTP 请求;
  • MetadataFetcher:负责单次元数据抓取,其接口定义在 metadata_fetcher.h,设计上“一个实例同一时刻只抓取一次”,实现思路与 JwksFetcher 类似。

抓取失败被归类为三种原因(MetadataReceiver::Failure):Network(网络错误)、InvalidMetadata(解析失败)、MissingConfig(缺少配置)。

4.2 FirstRefresh 退避策略

元数据提供器的首次刷新采用指数退避(metadata_fetcher.h):

  • 初始状态为FirstRefresh,首次刷新失败后以2 秒为起点重试;
  • 每次翻倍,最大退避到 30 秒,直到首次成功;
  • 首次成功后进入Ready状态,之后按正常的缓存时长(1 小时 + 宽限期 + 抖动)周期性刷新。

4.3 线程本地缓存与单例

凭证在多个工作线程间共享,因此MetadataCredentialsProviderBase使用 ThreadLocal 槽位保存每个线程的凭证副本(metadata_credentials_provider_base.h),并通过setCredentialsToAllThreads在主线程写入后广播到各线程。

由于同一主机上 IMDS 只有一份实例,InstanceProfileCredentialsProvider被注册为单例SINGLETON_MANAGER_REGISTRATION(instance_profile_credentials_provider),见 credential_provider_chains.cc);ContainerCredentialsProvider同样如此。这样即使存在多个凭证提供链(例如 per-route 配置下每个路由都有一条链),也不会对 IMDS 产生多轮重复抓取

五、AWS 集群管理器(AWS Cluster Manager)

5.1 动机:集群去重与上线通知

当多个扩展(aws_request_signingaws_lambda)同时配置时,若各自创建指向同一目标的集群,会白白浪费资源。AWS Cluster Manager(AwsClusterManagerImpl,aws_cluster_manager.h)解决两个问题:

  1. 集群去重:多个元数据凭证提供器如果目标地址相同,共享同一个内部集群;只有不存在时才会新建;
  2. 上线订阅通知:提供器订阅“集群已就绪”事件,集群 online 后才开始凭证刷新周期,避免在集群尚未创建完成时盲目发请求。

5.2 关键接口

  • addManagedCluster(cluster_name, cluster_type, uri):申请集群。存在同名同目标集群则复用,否则创建;
  • addManagedClusterUpdateCallbacks(cluster_name, cb):注册集群更新回调,返回 RAII 句柄(AwsManagedClusterUpdateCallbacksHandlePtr),销毁句柄即自动退订(aws_cluster_manager.h);
  • getUriFromClusterName(cluster_name):按名取回 URI。

从 credential_provider_chains.cc 可看到具体用法:STS 类提供器以LOGICAL_DNS类型创建指向sts.<region>.amazonaws.com:443的集群;Container / InstanceProfile 则以STATIC类型创建指向元数据端点的集群。

5.3 集群按目标去重的具体表现

aws_cluster_manager.h 注释明确了各类提供器的去重粒度:

  • InstanceProfile:只需一个指向 IMDS 的集群,任意数量的aws_request_signing扩展实例共用;
  • Container:只需一个指向容器代理的集群,任意扩展实例共用;
  • WebIdentity / IAM Roles Anywhere:按 region(Roles Anywhere 按 trust anchor 推导出的主机)维护每 region 一个集群,同一 region 下不同 role ARN 或 session name 的多个提供器共享集群,并各自收到集群就绪通知。

5.4 固定单例(Pinned Singleton)

AwsClusterManagerImpl固定单例(pinned singleton)方式注册(SINGLETON_MANAGER_REGISTRATION(aws_cluster_manager),见 credential_provider_chains.cc,并通过singletonManager().getTyped(..., true)固定)。这意味着它一旦实例化,将存活到服务器进程结束。由此带来的收益是:即使aws_request_signingaws_lambda扩展被替换/重建,指向 IMDS 或 STS 的集群也不会被重新创建,避免了重建集群带来的额外延迟。源码中addManagedCluster在集群管理器初始化阶段无法实时创建时,会把集群请求排队(createQueuedClusters),待集群管理器就绪后再补建,保证不丢失任何提供器的请求。

六、请求签名(Signing)

6.1 SigV4 与 SigV4A

AWS 公共组件同时支持AWS SigV4AWS SigV4A两种签名协议。签名实现位于 signers 目录:

  • SigV4SignerImpl:标准 SigV4(x-amz-datex-amz-content-sha256等头部);
  • SigV4ASignerImpl:SigV4A(基于 ECDSA、支持多 region 签名的变体,头部使用x-amz-region-set);
  • IAMRolesAnywhereSigV4Signer:IAM Roles Anywhere 专用签名器。

签名器的行为验证直接复用 aws-c-auth 的官方签名测试语料(aws-signing-test-suite),确保 Envoy 生成的签名与 AWS SDK 输出完全一致。

6.2 签名流程与头部

SignerBaseImpl(signer_base_impl.h)实现了标准 SigV4 过程,并定义了签名相关的头部与查询参数常量:

  • 签名头部:x-amz-content-sha256x-amz-datex-amz-security-token
  • 默认排除签名头部:x-forwarded-forx-forwarded-protox-amzn-trace-id(避免代理链路附加头污染签名,可通过配置的 exclude/include matcher 扩展);
  • 预签名查询参数(query string 模式):X-Amz-AlgorithmX-Amz-CredentialX-Amz-DateX-Amz-Region-SetX-Amz-Security-TokenX-Amz-SignatureX-Amz-SignedHeadersX-Amz-Expires(默认过期时间 5 秒);
  • 空 body 的内容哈希使用空字符串的 SHA-256 常量e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
  • 也支持UNSIGNED-PAYLOAD字面量作为 content hash。

Signer接口(signer.h)提供四种签名入口:

  • sign(message, sign_body):对完整请求签名,可选择是否把 body 纳入签名(纳入时 body 必须被完整缓冲);
  • signEmptyPayload(headers):按空 body 签名;
  • signUnsignedPayload(headers):以UNSIGNED-PAYLOAD签名;
  • sign(headers, content_hash):调用方预计算好 body 的 SHA-256 十六进制值后签名。

当凭证尚在异步获取中时,以上签名方法返回absl::NotFoundError,调用方应通过addCallbackIfCredentialsPending等待凭证就绪。

6.3 IAM Roles Anywhere:基于 X509 的签名变体

IAM Roles Anywhere 引入了一种新的 SigV4 签名变体:基于 X509 证书身份而不是传统的 access key。其实现为IAMRolesAnywhereSignerBaseImpl,是使用X509Credential凭证类型的 SigV4 特化实现:

  • X509Credentials(credentials_provider.h)承载证书(base64 DER)、私钥 PEM、证书链、证书序列号、过期时间以及签名算法(RSA / ECDSA);
  • IAMRolesAnywhereX509CredentialsProvider从配置加载证书与私钥并完成初始化校验(credential_provider_chains.cc),初始化失败时该提供器会被整体禁用并记录 error 日志;
  • 随后由IAMRolesAnywhereSigV4Signer使用 X509 私钥对向 Roles Anywhere 服务(rolesanywhere服务名)发起的调用签名,换取临时 AK/SK 凭证。

从源码看,该提供器的集群名由 trust anchor ARN 推导出的主机名中的.替换为_生成(credential_provider_chains.cc),从而保证同一 trust anchor 复用同一集群。

七、异步凭证获取(Asynchronous Credential Retrieval)

7.1 为什么需要异步

aws_lambdaaws_request_signing扩展都支持异步凭证获取:当凭证尚在抓取时,上游请求会被暂停(paused),待凭证返回后再继续。这是冷启动场景下的关键能力——例如刚启动的 EC2/ECS 实例首次请求时 IMDS 尚未返回临时凭证,若直接签名会失败。

7.2 订阅/通知模型

整套机制建立在订阅/通知(subscription/notification)模型之上,核心流程如下:

  1. 订阅阶段:凭证提供链在初始化时,对链内每个元数据提供器调用subscribeToCredentialUpdates(见 credential_provider_chains.cc 的setupSubscriptions);
  2. 通知阶段:元数据提供器成功(或失败)获取凭证后,通过onCredentialUpdate回调通知已订阅的凭证提供链(CredentialSubscriberCallbacks接口定义在 credentials_provider.h)。订阅句柄使用 RAII +weak_ptr管理,保证提供器(可能是单例)比链存活更久时也不会悬挂;
  3. 等待阶段:签名器在签名请求时调用凭证链的addCallbackIfCredentialsPending(cb):若凭证当前不可用,则把回调存入队列并返回true;当链收到onCredentialUpdate通知后,会依次触发所有等待回调(对应 credentials_provider.h 中credential_pending_callbacks_列表);
  4. 恢复阶段:回调触发后,暂停的请求继续执行签名并放行。

7.3 各扩展的接入方式

每个使用签名异步能力的扩展,都通过addCallbackIfCredentialsPending在凭证未就绪时暂停自身执行流。Signer接口的注释(signer.h)明确约定:返回true表示凭证 pending 且回调已入队,返回false表示凭证已就绪可以立即签名。这一约定让上层扩展无需关心凭证细节,只需遵循“先检查 pending、再签名”的两步式流程。

八、从配置到运行:一次完整的签名请求旅程

结合上述机制,可以串起一次典型的签名请求完整链路:

  1. 扩展(如aws_request_signing)启动时,调用defaultCredentialsProviderChaincustomCredentialsProviderChain构建凭证提供链(credential_provider_chains.cc);
  2. 链构造期间,元数据类提供器通过AwsClusterManager申请内部集群并注册上线回调;集群管理器按目标去重,必要时创建 STATIC/LOGICAL_DNS 集群(aws_cluster_manager.h);
  3. 集群上线后通知提供器,提供器通过MetadataFetcher异步抓取凭证,首刷采用 2 秒起、最大 30 秒的指数退避;
  4. 凭证抓取期间,签名器调用addCallbackIfCredentialsPending挂起等待;凭证就绪后经setCredentialsToAllThreads广播到所有线程并通知订阅链(metadata_credentials_provider_base.h);
  5. 凭证就绪后,签名器按 SigV4/SigV4A 计算规范请求、生成Authorization头或预签名查询参数并放行请求;
  6. 之后按 1 小时刷新周期(含 60 秒宽限期与最多 30 秒抖动)在后台静默续期,保证代理长期运行不掉线。

九、进一步探索指引

  • 组件根目录与架构说明:source/extensions/common/aws/README.md
  • 凭证提供链的实现与默认链构建:credential_provider_chains.cc、credential_provider_chains.h
  • 各类凭证提供器:credential_providers
  • 元数据提供器基类与抓取器:metadata_credentials_provider_base.h、metadata_fetcher.h
  • 集群管理器:aws_cluster_manager.h、aws_cluster_manager.cc
  • 签名器接口与实现:signer.h、signer_base_impl.h、signers
  • 凭证与订阅模型定义:credentials_provider.h

结语

Envoy 的 AWS 公共组件用一套与 AWS SDK 对齐、但面向代理场景重构的设计,解决了代理层签名的三大难点:凭证来源多样化(环境、文件、容器、实例元数据、STS、Roles Anywhere 六类来源通过链式降级统一)、凭证获取的异步化(订阅通知 + 回调暂停,保证请求在凭证就绪前不失败)、集群资源的去重复用(固定单例集群管理器按目标共享集群并广播就绪事件)。理解这四层机制,是深入定制aws_request_signingaws_lambda扩展、排查“请求签名失败/凭证过期”类问题的基础。

【免费下载链接】envoyCloud-native high-performance edge/middle/service proxy项目地址: https://gitcode.com/GitHub_Trending/en/envoy

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/15 17:20:06

Android新闻推荐系统实战:端上推荐算法与工程调优

简介&#xff1a;基于Android的新闻推荐系统完整源码包&#xff0c;面向移动开发初学者、毕业设计选题者以及希望了解新闻类App整体架构的程序员。项目采用OkHttp与Gson实现网络请求和JSON解析&#xff0c;配合Glide处理图片加载&#xff0c;覆盖新闻列表、下拉刷新、加载更多、…

作者头像 李华
网站建设 2026/9/15 17:20:03

Hive Metastore 高可用与性能优化:提升查询效率与系统稳定性

Hive Metastore 高可用与性能优化&#xff1a;提升查询效率与系统稳定性 1. Hive Metastore 架构问题与独立部署方案 1.1 传统架构痛点分析 Hive Metastore 作为元数据管理中心&#xff0c;其性能直接影响整个 Hive 查询效率。传统架构中&#xff0c;Metastore 通常与 HiveServ…

作者头像 李华
网站建设 2026/9/15 17:19:58

Unity简约风UGUI动效:弹簧参数驱动的Q弹UI插件设计

简介&#xff1a;面向Unity开发者的UGUI插件资源包&#xff0c;主打动效UI、简约风格与Q弹动画&#xff0c;可帮助游戏和应用开发者高效搭建交互界面、提升视觉体验与用户沉浸感。压缩包共1969个文件、14.34MB大小&#xff0c;包含221个预制体、111个C#脚本、83个动画、49个动画…

作者头像 李华
网站建设 2026/9/15 17:18:26

Kimi K2 本地部署教程:1T 参数开源智能体模型的最小运行门槛

Kimi K2 本地部署教程&#xff1a;1T 参数开源智能体模型的最小运行门槛 【免费下载链接】Kimi-K2 Kimi K2 is the large language model series developed by Moonshot AI team 项目地址: https://gitcode.com/GitHub_Trending/ki/Kimi-K2 Kimi K2 是 Moonshot AI 开源…

作者头像 李华