
terraform-provider-aws Provider 设计原则API 边界、资源类型模式与跨服务限制【免费下载链接】terraform-provider-awsThe AWS Provider enables Terraform to manage AWS resources.项目地址: https://gitcode.com/GitHub_Trending/te/terraform-provider-aws本文围绕 Terraform AWS Providerterraform-provider-aws官方的设计指南 docs/provider-design.md 展开系统讲解该 Provider 如何划定 AWS API/SDK 的职责边界、如何把 AWS 服务的各类 API 能力映射为 Terraform 资源类型邀请/接受者模型、隐式关联、数据源命名、IAM 资源策略、运行态管理、任务执行与等待器、版本化资源以及凭据外泄的安全设计底线并结合仓库源码给出每种设计模式的真实落地证据。读完本文你将能够判断一个 AWS 功能该不该由本 Provider 实现、该做成什么形态的资源并在为 Provider 贡献新资源时做出符合维护者评审标准的设计决策。设计总纲遵循 HashiCorp Provider Design PrinciplesTerraform AWS Provider 的设计遵循 HashiCorp 官方《Provider Design Principles》所确立的准则。该通用文档给出了多年 Terraform 设计与实现经验沉淀出的高层设计要点而docs/provider-design.md则是在这一总纲之上针对 AWS 生态的具体补充一部分章节细化总纲与 AWS Provider 之间的差异另一部分记录总纲未覆盖的 AWS 特有问题。贡献指南的其他页面则负责代码、测试和文档等实现细节。在源码层面这一总纲的核心体现是 internal/conns/ 中的 AWS 客户端构建与 internal/service/ 下按服务划分的联邦式目录结构每个 AWS 服务一个包资源、数据源、测试各自独立各服务可独立演进。API 与 SDK 边界Provider 使用 AWS Go SDK 实现 AWS 各服务 API 的支持因此AWS API 与 SDK 的能力上限就是 Provider 的能力上限。文档给出了一个清晰的职责分界SDK 操作负责 AWS 组件的生命周期管理创建、查询、更新、删除一个数据库等SDK 操作通常不负责组件内部的功能性操作例如在数据库上执行一条 SQL 查询这类操作不应出现在 Provider 中。文档还明确列出了不属于本 Provider 预期范围的功能类别并指明替代方向文中对应指向 Terraform Registry 中的其他 Provider如 HTTP、TLS、Kubernetes、Active Directory、External Provider 等原始 HTTP(S) 处理——属于通用 HTTP Provider 的职责超出 EKS 服务 API 范围的 Kubernetes 资源管理——属于 Kubernetes Provider 的职责Active Directory 或其他协议客户端——属于相应协议 Provider 的职责要求执行 Terraform 的宿主机上额外安装软件的功能——目前明确包括依赖 AWS CLI 的场景。这一条的设计动机很重要如果宿主机上没有 AWS CLI配置就会失败Provider 的部署边界因此被破坏。此类需求应交由 External Provider 等机制处理。这个边界的判断标准可以概括为该功能是否纯粹通过 AWS 服务 API 就能完成生命周期管理。是则属于本 Provider否则寻找其他 Provider。基础设施即代码IaC适用性维护者的设计目标是尽可能覆盖 AWS API但并非 API 的每个方面都适合 IaC 建模。文档指出关键区分IaC 最适合不可变基础设施immutable infrastructure——即资源以完整描述其单一期望状态的方式定义而不是通过动态过程定义mutable infrastructure。这意味着某些 AWS 组件如果其配置本质上是运行中的动态状态机例如只能通过交互式过程推进的状态用声明式 Terraform 建模就会牵强。文档给受影响用户的建议是向 AWS 提交 Support case推动 AWS 把组件做得更自包含、更兼容 IaC这些 case 往往还能挖出 AWS 服务与 API 中未被良好记录的内部行为。资源类型设计的七种模式总则CRUD 启发式与联邦式设计Terraform 资源最适合作为最小的基础设施积木供使用者在此基础上构建更复杂的配置和抽象如 Terraform Module。判断某个 AWS 功能是否应该实现为 Terraform 资源的通用启发式是该 AWS 服务 API 是否提供完整的 CRUDcreate/read/update/delete操作。但并非所有 AWS API 能力都能干净地落入 CRUD 生命周期管理需要额外的设计考量。文档特别强调一个前提整个 Provider 的设计与实现是联邦式federated的——不同服务对同一概念的实现和术语可能不同因此该指南不是穷尽式的清单而是提供通用概念和基础术语帮助贡献者看懂既有实现、找对方向。模式一授权/接受者Authorization/Acceptance资源部分 AWS 服务对跨账号关联或访问采用邀请-接受模型文档列举的典型场景包括Direct Connect Association Proposals关联提案GuardDuty Member Invitations成员邀请RAM Resource Share Associations资源共享关联Route 53 VPC AssociationsVPC 关联Security Hub Member Invitations成员邀请AWS 建立跨区域/跨账号关联有两种方式邀请邀请/提案模式一个 AWS 账号发出邀请或提案生成标识符另一个账号使用该标识符接受邀请隐式关联模式配置一个指向另一 AWS 账号标识符的引用接收账号无需显式接受即可完成关联并投入使用。邀请/提案模式的建模规则术语以 AWS 服务 API 为准API 叫 invitation 就用 invitation叫 proposal 就用 proposal发起账号创建 invitation 或 proposal 资源前提是 API 有创建和读取邀请的操作响应账号创建 accepter 资源前提是 API 在响应账号侧有接受、读取、拒绝邀请的操作并按如下方式映射Create接受邀请Read读取邀请以确定其状态。注意有些 API 中邀请会过期消失使关联复杂化——如果资源读不到邀请开发者应实现回退逻辑去读取该邀请/提案所关联的 API 资源Delete拒绝或以其他方式删除邀请。源码印证仓库中 GuardDuty 的实现 internal/service/guardduty/invite_accepter.go 完整体现了上述规则。resourceInviteAccepter只注册了Create/Read/Delete三个操作无 UpdateCreate 中先通过ListInvitations按主账号 ID 查找邀请、再用AcceptInvitation接受Read 则调用findMasterAccountByDetectorID读取已建立的主从关联——这正是文档所说的邀请可能已消失回退读取关联资源策略的实现Delete 走解除成员关系的路径。资源 schema 也只有detector_id与master_account_id两个只读/强制重建属性是典型的最小关联资源。隐式关联模式的建模规则创建 association 资源可选再配一个 authorization 资源直接把 CRUD 映射到 AWS 服务 API 的对应操作上。模式二跨服务功能Cross-Service Functionality——明确拒绝许多 AWS 服务构建在其他 AWS 服务之上例如EKS Node Groups 管理 Auto Scaling GroupsLambda Functions 管理 EC2 ENITransfer Servers 管理 EC2 VPC Endpoints有些跨服务的 API 实现缺少对其他服务的管理能力或描述能力会让 Terraform 资源在端到端配置中显得不完整。基于 HashiCorp Provider Design Principles 中资源应代表单一 API 对象的目标文档给出硬性规则资源只能与单一 AWS 服务 API 通信维护者不会批准跨服务资源。背后的理由有四条意外的 IAM 权限需求高安全环境中跨服务所需的全部权限可能不可获得或不可接受意外的 CloudTrail 日志其他服务也会为该资源生成 CloudTrail 日志超出使用者的预期审计范围意外的端点配置需求使用 VPC 端点等自定义端点的组织需要额外配置未预期的 API 端点服务内部实现的不稳定性跨服务行为不属于主服务 API 的一部分可能随时间变化且服务团队在 API 升级时未必将其视为 breaking change。文档还给出了第 4 点的真实案例某个 Lambda 资源曾帮助清理因常见配置错误而多出的 ENI网络接口。使用者因为该问题极难诊断而觉得这项功能很有用。多年后 AWS 更新了 Lambda API使用者立即报告 Terraform 执行开始失败由于大量配置依赖近期版本无法降级 Provider而对于运行在很旧版本的组织强行升级修复又可能引发不相关的意外变更。最终 HashiCorp 与 AWS 进行了大规模用户沟通以帮助升级和修复配置Provider 维护者和使用者都付出了大量时间成本。这个案例是跨服务资源会随主服务 API 之外的变动而失效这一风险的实证。模式三数据源Data Sources的命名与分类数据源是与资源不同的 Terraform 资源类型用于只读地查找或获取数据不应在远端系统上产生副作用。数据源按其预期返回对象的数量分为两类复数数据源Plural Data Sources返回零、一或多个结果通常与某个托管资源类型相关联结果通常是集合set除非远端系统提供顺序保证命名规则使用复数后缀s或es且不应包含任何具体属性。文档示例应命名aws_ec2_transit_gateways而不是aws_ec2_transit_gateway_ids。单数数据源Singular Data Sources返回恰好一个结果或报错命名规则同样不包含具体属性。文档示例应命名aws_ec2_transit_gateway而不是aws_ec2_transit_gateway_id。这条命名规则在仓库中可大量验证例如 internal/service/sns/topic_policy_list.go 与sns包下的单数查找数据源即遵循此约定——复数形式返回集合单数形式做一对一查找。模式四IAM 资源策略Resource-Based Policy独立成资源部分 AWS 组件允许通过 API 指定 IAM 资源策略即与该组件关联的 IAM 策略文档列举的例子包括ECR Repository PoliciesECR 仓库策略EFS File System PoliciesEFS 文件系统策略SNS Topic PoliciesSNS 主题策略设计规则Provider 开发者应将其实现为新资源而不是加到宿主资源上。理由有三策略必须包含宿主资源的 ARN如果在同一资源内部解决这个自引用需要绕弯子的自定义 diff 处理极其累赘多资源策略需要互相引用 ARN不拆分资源会引入配置循环依赖运维与安全的职责分离拆分后运维者可以把配置逻辑上划分为纯运维和安全边界两部分让环境中 IAM 变更与基础设施变更由不同角色和权限负责。唯一的罕见例外策略在资源创建时就是必需的此时可以并入主资源。源码印证仓库中的 internal/service/sns/topic_policy.go 即按此规则实现为独立的aws_sns_topic_policy资源文件第 28 行的SDKResource(aws_sns_topic_policy, nameTopic Policy)注册声明而非aws_sns_topic的一个属性ECR、EFS 等服务包中同样存在对应的*_policy独立资源文件模式一致。模式五资源运行态Running State管理——内置于资源部分 AWS 组件支持启动、停止、启用或禁用文档列举的例子包括Batch Job QueuesCloudFront DistributionsRDS DB Event Subscriptions设计规则这类能力应实现为宿主资源内的属性通常体现为布尔/枚举型配置项而不是单独的资源。理由是使用者无法在 Terraform 的声明式配置中实际地管理与资源运行状态的交互——把 start/stop 拆成资源会让配置语义变得反直觉。即使在当前 API 下更新运行态没有明显问题的场景这种内置式实现也提供了一致性与面向未来的稳定性。模式六任务执行与等待器Task Execution and Waiter资源——独立成资源有些 AWS 操作是异步的Terraform 请求 AWS 执行任务后AWS 最初只确认已收到请求Terraform 需要轮询状态直到完成。文档列举的例子包括ACM 证书验证EC2 AMI 复制RDS DB 集群快照管理设计规则只要 AWS 服务 API 提供了启动任务和读取任务状态的操作就应该创建一个独立的资源来代表该任务而不是把任务功能塞进父资源——那会模糊父资源基础设施管理的本职。维护者即使这意味着与已有资源存在一定重复也偏好此方案。文档给出的例子Provider 中既有aws_ami资源本身又有复制 AMI 的独立资源。这种模块化让使用者可以用另一个资源去管理任务资源产出的结果。源码印证internal/service/ec2/ec2_ami_copy.go 中注册的aws_ami_copy资源正是这一模式的实现——它与aws_ami同处 EC2 服务包内专门建模跨区/跨账号复制 AMI这一异步任务复制请求发出后等待新 AMI 可用产出的 AMI ID 可作为其他资源如 EBS 快照、实例启动配置的输入正是任务结果可被其他资源消费的模块化收益。同目录下还有ebs_snapshot_copy.go、ebs_volume_copy.go等复制类资源共同构成该模式在 EC2 服务中的族谱。模式七版本化Versioned资源——视 API 语义而定AWS 支持部分组件存在多个版本文档列举的例子包括ECS Task DefinitionsLambda FunctionsSecrets Manager Secrets总体规则为单个版本创建独立资源。文档给出的例子Provider 同时有aws_secretsmanager_secret与aws_secretsmanager_secret_version两个资源。仓库中 internal/service/secretsmanager/secret_version.go 即实现了后者与secret.go中的主资源分离版本可通过标签指定符合版本可独立管理的 API 语义。但在某些情况下版本处理应保留在主资源中。决策准则有三条创建组件时 AWS 必然同时创建版本→ 版本处理并入同一 Terraform 资源。用一个资源创建组件、再换另一个资源来更新会让使用者困惑API 允许删除版本、且使用者希望删除版本→ 应实现独立的版本资源API 只支持发布新版本无法删除→ 两种做法都可接受但当前多数实现是自包含的。原因是 Terraform 当前配置语言不原生支持不改变 state 值就跨资源触发更新或重建拆分会迫使使用者使用triggers之类的资源与配置变通手段实现难度上升。文档同时注明如果未来配置语言支持了这类能力本指南可能更新为倾向独立资源届时将参照任务执行与等待器资源一节的指引。安全底线拒绝 AWS 凭据外泄文档最后一节设定了一条安全红线出于安全考虑维护者不会批准任何能让使用者引用或导出正在运行的 Provider 之 AWS 凭据的数据源。文档承认存在合理用例例如在同一 Terraform 配置中执行 AWS CLI 调用但指出该机制可能导致凭据在 Terraform 之外被发现和滥用具体担忧包括界面与日志泄露凭据值可能出现在 Terraform 用户界面输出或日志中任何有界面或日志访问权限的人都能看到State 明文存储值目前以明文保存在 Terraform state 中任何能访问 state 文件、或通过引用该 state 的其他 Terraform 配置的人都能获得凭据安全姿态的默认降级新增的此类功能虽然实现上是选择性启用opt-in的但同样意味着组织无法通过安全控制或策略将其opt-out——采纳更弱的默认安全姿态需要提前公告且会阻止已实施相应安全控制的组织升级到包含此类功能的版本。这三点共同构成凭据不得进入 Terraform 数据流的论证值会流经日志、state、其他配置引用等多条不可控通道且该弱点无法在使用者侧关闭。结语作为贡献决策清单使用docs/provider-design.md的价值不仅在于记录既有实现更在于它是新资源实现的评审标准一个提交在贡献之前可以先对照本文的七种模式自检——功能是否在 AWS API/SDK 边界内是否适合 IaC 的不可变建模是邀请/接受者模型、隐式关联、跨服务调用、策略、运行态、异步任务还是版本应内置还是拆分是否触碰凭据红线仓库中 internal/service/ 下数百个服务包如 internal/service/guardduty/、internal/service/ec2/、internal/service/sns/、internal/service/secretsmanager/中大量既有资源就是这套决策树执行后的产物可作为同类功能的参照实现。【免费下载链接】terraform-provider-awsThe AWS Provider enables Terraform to manage AWS resources.项目地址: https://gitcode.com/GitHub_Trending/te/terraform-provider-aws创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考