资讯动态

使用 Terraform 将 Teleport Database Service 部署到 AWS ECS:基于 IAM Join Token 的完整示例解析

发布时间:2026/9/20 21:11:07 来源:尧图企业网站定制
使用 Terraform 将 Teleport Database Service 部署到 AWS ECS基于 IAM Join Token 的完整示例解析【免费下载链接】teleportThe easiest, and most secure way to access and protect all of your infrastructure.项目地址: https://gitcode.com/gh_mirrors/tel/teleport导读本文围绕 integrations/terraform-modules/teleport/container-service/aws/examples/db-service 示例展开讲解如何用 Terraform 把 Teleport 的数据库服务Database Service以容器方式部署到 AWS ECS Fargate并通过IAM Join Token使其安全加入一个已有的 Teleport 集群。读完本文你将掌握该示例的完整目录结构、每个 Terraform 文件的职责、teleport_config的写法要点、IAM 信任关系的自动推导逻辑以及模块底层如何把配置渲染进 ECS 任务定义——并可以直接把这一套方案复制到自己的基础设施中。示例概览一键拉起一个 ECS 上的数据库代理该示例的核心目标可以用一句话概括用纯 Terraform 声明式地创建一个承载 Teleport Database Service 的 ECS 服务并让这个容器代理通过 AWS IAM 身份认证join_method iam自动加入你已有的 Teleport 集群从而为集群提供数据库访问能力而无需在 ECS 上手工维护任何静态 Token。从 Terraform 模块依赖看整个示例只依赖两层模块SourceVersion作用teleport_database_service../..即本仓库模块container-service/aws当前仓库版本创建 ECS 集群、服务、任务定义、IAM 角色与安全组vpcterraform-aws-modules/vpc/aws6.6.0创建一个带 3 个可用区、公有/私有子网的示例 VPC它对外只暴露一个必填输入NameDescriptionTypeDefaultRequiredteleport_proxy_addrTeleport Proxy Service 的地址host:port形式stringn/ayes以及一个输出teleport_database_service完整导出模块创建的全部资源对象方便调用方进一步引用例如输出 ECS 集群 ARN、任务 IAM 角色 ARN 等。目录结构示例由六个文件组成该示例目录的完整清单如下位于 integrations/terraform-modules/teleport/container-service/aws/examples/db-servicedb-service/ ├── README.md # 本示例说明含自动生成的 TF-Docs 表格 ├── data.tf # 可用区数据源 ├── docs_description # TF-Docs 生成用的描述文本 ├── docs_title # TF-Docs 生成用的标题文本 ├── main.tf # VPC 与 Database Service 模块、IAM Join Token ├── outputs.tf # 导出 teleport_database_service ├── providers.tf # aws / teleport 两个 provider 配置 ├── variables.tf # teleport_proxy_addr 变量声明 └── versions.tf # Terraform 与 provider 版本约束其中docs_description、docs_title只是 terraform-docs 生成README.md中表格区的输入素材真正的业务逻辑集中在main.tf、providers.tf、versions.tf三个文件里。版本约束versions.tfversions.tf 定义了整套环境的版本基线terraform { required_version 1.5.7 required_providers { aws { source hashicorp/aws version ~ 6.0 } http { source hashicorp/http version ~ 3.0 } teleport { source terraform.releases.teleport.dev/gravitational/teleport version ~ 18.5 } } }几个值得注意的细节teleportprovider 的 source 是terraform.releases.teleport.dev/gravitational/teleport不是hashicorp/命名空间下的官方 registry需要在使用前执行terraform login或在 CLI 配置中信任该私有 registryhttpprovider~ 3.0不是直接在本示例中被声明使用而是随teleport_database_service模块的Managed Updates功能传递引入的见下文“版本管理”一节Terraform 版本要求 1.5.7与模块自身的required_version保持一致。Provider 配置providers.tfproviders.tf 同时配置了两个 providerprovider aws { region us-east-1 default_tags { tags { env example } } } provider teleport { addr var.teleport_proxy_addr profile_name replace(var.teleport_proxy_addr, /:[0-9].*/, ) }awsprovider 固定使用us-east-1并通过default_tags给所有 AWS 资源打上env example标签——这些标签会与模块内apply_aws_tags传入的标签合并teleportprovider 使用addr指向 Proxy 地址profile_name则通过正则replace(..., /:[0-9].*/, )从host:port中剥离端口部分得到纯主机名作为 tsh 配置文件名。这意味着使用该示例的前提是本机已经通过tsh login登录过对应集群Terraform 才能拿到创建teleport_provision_token所需的集群凭据。核心编排main.tf从 VPC 到数据库代理main.tf 是整个示例的灵魂按自上而下顺序完成三件事建 VPC → 起数据库服务模块 → 创建 IAM Join Token。第一步创建示例 VPClocals { namespace example } module vpc { source terraform-aws-modules/vpc/aws version 6.6.0 azs slice(data.aws_availability_zones.this.names, 0, 3) cidr 10.0.0.0/16 name ${local.namespace}-vpc public_subnets [10.0.1.0/24, 10.0.2.0/24, 10.0.3.0/24] private_subnets [10.0.101.0/24, 10.0.102.0/24, 10.0.103.0/24] }配合 data.tf 中的data aws_availability_zones this {}示例从当前区域真实可用的可用区中取前 3 个slice(..., 0, 3)来放置子网。VPC 使用10.0.0.0/16公有子网与私有子网各 3 个符合 ECS 多 AZ 高可用部署的最小布局。第二步调用 teleport_database_service 模块module teleport_database_service { source ../.. # Enable managed updates managed_updates_enabled true managed_updates_group default apply_aws_tags { example true } assign_public_ip true # must be true when using public subnets ecs_cluster_name ${local.namespace}-cluster ecs_service_name ${local.namespace}-svc ecs_service_subnets module.vpc.public_subnets ecs_task_desired_count 1 environment_vars { EXAMPLE_VAR EXAMPLE_VALUE } vpc_id module.vpc.vpc_id teleport_config { version v3 teleport { join_params { token_name ${local.namespace}-iam method iam } proxy_server var.teleport_proxy_addr log { severity DEBUG } } auth_service { enabled no } proxy_service { enabled no } ssh_service { enabled no } discovery_service { enabled no } db_service { enabled yes resources [ { labels { env example } } ] } } }这段代码集中体现了本示例的三个设计要点teleport_config使用原生 Terraform 语法书写最终会被模块渲染成teleport start --config-string所需的 YAML见下文“任务定义里发生了什么”一节。它等价于一段标准 Teleport 配置version: v3通过join_params.method iam和token_name example-iam指定 IAM 加入方式proxy_server指向你的 Proxy 地址日志级别设为DEBUG便于排障。仅开启db_serviceauth_service、proxy_service、ssh_service、discovery_service全部显式enabled no这与“数据库代理”的定位完全吻合——ECS 上的容器只充当 Database Service不承担集群控制面职责。db_service.resources[0].labels { env example }声明了该服务托管的数据库标签Teleport 集群将依据这一标签把注册请求路由到本代理。assign_public_ip true与公有子网配套由于示例 VPC 的公网子网直连 Internet Gateway容器需要被分配公网 IP 才能反向连接 Teleport Proxy模块 README 明确要求——assign_public_ip true时子网必须是公有子网false时则必须是走 NAT 网关的私有子网。第三步创建 IAM Join Tokenresource teleport_provision_token iam { metadata { name ${local.namespace}-iam description Allow the Teleport ECS agent to join the cluster using AWS IAM credentials. } spec { allow [{ aws_arn module.teleport_database_service.teleport_provision_token_allow_aws_arn }] join_method iam roles [Db] } version v2 }这是整个示例最巧妙的部分它通过teleportprovider 在你的 Teleport 集群里创建一个join_method iam、roles [Db]的 provisioning token作用域精确到一条 ARN该 ARN 不是手写的而是直接引用模块输出module.teleport_database_service.teleport_provision_token_allow_aws_arn。查看模块 outputs.tf 可知其推导公式value format( arn:%v:sts::%v:assumed-role/%v/*, one(data.aws_partition.this[*].partition), one(data.aws_caller_identity.this[*].account_id), one(aws_iam_role.ecs_task[*].name), )即arn:aws:sts::account:assumed-role/ecs_task_role_name/*。换句话说模块自动查询当前 AWS 账号 ID 与分区加上它创建的 ECS 任务 IAM 角色名拼出“该任务角色可被信任”的完整 ARN 通配表达式。容器启动后带着 ECS 任务角色的临时 STS 凭据去连接 ProxyTeleport 侧用这条 token 的allow.aws_arn与之比对通过即放行——全程无需静态 Token天然具备自动轮换能力。模块输入速查哪些参数值得关注teleport_database_service模块即 container-service/aws暴露了丰富的输入除示例中已使用的之外下面这些在实际生产中经常被用到输入默认值说明ecs_task_cpu2048任务 CPU 单元数Fargate 计费单位ecs_task_memory4096任务内存MiBecs_task_desired_count2期望运行的任务副本数示例中显式设为1ecs_task_cloudwatch_log_group_retention_days30CloudWatch 日志保留天数ecs_task_cloudwatch_log_group_kms_key_idnull日志组加密 KMS Key为null时使用 CloudWatch 默认加密createtrue全局开关置false可只取输出不创建资源create_security_grouptrue是否创建任务安全组可用security_group_ids追加既有安全组security_group_ids[]额外附加到任务的安全组ecs_task_role_inline_policynull合并进任务 IAM 角色内联策略的 JSON常用于给数据库代理授予访问目标数据库的权限ecs_task_role_self_assumption_allowedtrue任务角色是否允许自我 assumeIAM Join 前置条件之一teleport_container_imagepublic.ecr.aws/gravitational/teleport-ent-distrolessTeleport 容器镜像注意默认是企业版 distroless 镜像teleport_version19.0.0-prealpha.2显式指定 Teleport 版本一般交给 Managed Updates 决定managed_updates_enabled/managed_updates_grouptrue/default是否从 v2 Managed Updates 端点解析推荐版本模块的常用输出包括ecs_cluster_arn、ecs_service_arn、ecs_task_definition_arn、ecs_execution_role_arn、ecs_task_role_arn、security_group_id、teleport_config以及上文的teleport_provision_token_allow_aws_arn完整清单见 container-service/aws/README.md。任务定义里发生了什么从 Terraform 配置到容器启动为了理解“模块如何把teleport_config变成运行中的代理”需要看模块的 aws_ecs_task_definition.tf。其核心容器定义片段如下container_definitions jsonencode([ { command [ # rewrite SIGTERM (15) to SIGQUIT (3) so ECS stop signal triggers graceful Teleport shutdown --rewrite, 15:3, --, teleport, start, --config-string, base64encode(yamlencode(var.teleport_config)), ] entryPoint [/usr/bin/dumb-init] ... image ${var.teleport_container_image}:${local.teleport_version} logConfiguration { ... awslogs ... } name teleport } ])这段实现揭示了三个底层细节配置传递方式teleport_config先被yamlencode序列化成 YAML再base64encode编码通过teleport start --config-string注入容器——所以teleport_config里的键名如db_service、join_params与 Teleport 原生 YAML 配置一一对应。优雅停机--rewrite 15:3通过 dumb-init 把 ECS 停止容器时发送的SIGTERM(15) 改写成SIGQUIT(3)从而触发 Teleport 的优雅关闭流程避免代理被强杀导致会话中断。版本来源镜像 tag 由local.teleport_version决定其计算逻辑是——若启用了 Managed Updates则从data.http.managed_updates拉取auto_update.agent_version否则回退到var.teleport_version再统一去掉前导v。同时任务定义上的precondition还强制约束开启 Managed Updates 时teleport_config.teleport.proxy_server必须非空见 aws_ecs_task_definition.tf这是模块保证能正确解析更新源的前提也是示例中必须传teleport_proxy_addr的原因之一。此外任务使用network_mode awsvpc与requires_compatibilities [FARGATE]日志走awslogs驱动写入模块创建的 CloudWatch Log Group任务与执行两个 IAM 角色分别承载“Teleport 自身运行所需权限”和“拉取镜像、写日志所需权限”。部署步骤与验证前置条件已配置好 Teleport 集群与tsh并能以管理员身份登录示例中创建 provisioning token 需要相应权限本机已通过tsh login proxy登录且tsh配置文件与providers.tf中profile_name推导出的主机名一致已配置 AWS 凭据Access Key 或 SSO且账号有创建 VPC、ECS、IAM 的权限已信任terraform.releases.teleport.dev私有 registry首次执行terraform init时按提示完成登录。操作步骤# 1. 初始化拉取模块与 provider terraform init # 2. 确认执行计划重点检查 teleport_provision_token 与 ECS 资源 terraform plan -varteleport_proxy_addrproxy.example.com:443 # 3. 应用 terraform apply -varteleport_proxy_addrproxy.example.com:443应用成功后可以按以下顺序验证terraform output teleport_database_service查看模块导出的完整资源ECS 集群/服务/任务 ARN、角色 ARN、安全组 ID、CloudWatch 日志组在 Teleport 侧运行tsh status确认集群连接正常再用tsh db ls或 Web UI 的 Databases 页面查看是否出现envexample标签的数据库服务实例登录 AWS 控制台查看 ECS 服务是否处于RUNNING、任务是否通过健康检查并到 CloudWatch Log Group 中检查teleport start的启动日志示例配置了DEBUG级别会输出 IAM Join 的完整握手过程。变更与清理调整ecs_task_desired_count即可水平扩缩容代理副本需要数据库代理访问具体数据库时通过ecs_task_role_inline_policy给任务角色授予对应数据库的访问策略并在db_service.resources中补充数据库标签或静态资源清单不再需要时执行terraform destroy即可回收全部资源注意 provisioning token 是创建在 Teleport 集群内的资源也会一并删除。小结db-service示例是一个“麻雀虽小、五脏俱全”的 ECS 化 Teleport 代理模板它用最少的外部依赖一个 VPC 模块 一个自研模块演示了从网络环境搭建、teleport_config编写、IAM Join Token 创建到版本托管的全流程。其核心可复用资产有三点纯声明式的teleport_config写法与 Teleport 原生 YAML 语义一致可平移到任意容器平台teleport_provision_token_allow_aws_arn自动推导让“ECS 任务角色 ↔ Teleport IAM Join Token”的信任关系零手写、随模块自动闭环Managed Updates 机制把 Teleport 版本选择权交给官方更新端点配合proxy_server校验前置条件降低长期维护成本。如果你正在把 Teleport 的数据库访问能力容器化落地到 AWS可以直接以本示例为基线先原样部署跑通链路再按上文“模块输入速查”中的参数逐项替换成生产配置即可。【免费下载链接】teleportThe easiest, and most secure way to access and protect all of your infrastructure.项目地址: https://gitcode.com/gh_mirrors/tel/teleport创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价