使用 Terraform AWS Provider 构建 Cognito User Pool:完整示例与配置详解
【免费下载链接】terraform-provider-awsThe AWS Provider enables Terraform to manage AWS resources.项目地址: https://gitcode.com/GitHub_Trending/te/terraform-provider-aws
导读
本文围绕terraform-provider-aws仓库中的 Cognito User Pool 示例,完整讲解如何使用 Terraform 声明式创建 Amazon Cognito User Pool(用户池),并集成 IAM 角色与 Lambda 触发器。读完本文,你将掌握:用户池核心配置块(密码策略、Schema 属性、验证消息模板、SMS/邮件配置、Lambda 触发器)的每一项参数含义与取值约束,如何为 Cognito 服务与 Lambda 函数正确授权 IAM 角色,以及terraform plan / apply / destroy的完整运维流程。
示例源码位于 examples/cognito-user-pool/main.tf,对应的 Provider 实现为
internal/service/cognitoidp/user_pool.go,本文将以源码为准补充参数约束与默认值,确保示例可直接落地为真实配置。
一、示例概览:一次性交付用户池 + IAM + Lambda
该示例在单个.tf文件中完成了三件事:
| 资源 | 作用 | 在本示例中的角色 |
|---|---|---|
aws_iam_role.main | Lambda 执行角色 | 让 Lambda 以lambda.amazonaws.com服务身份运行 |
aws_lambda_function.main | 用户池触发器函数 | 承载用户池各类生命周期钩子 |
aws_iam_role.cidp | Cognito 身份池服务角色 | 允许 Cognito 代表用户池调用 SNS 发送短信 |
aws_iam_role_policy.main | 角色内联策略 | 授予sns:publish权限 |
aws_cognito_user_pool.pool | 用户池核心资源 | 本文讲解的主体 |
模块入口examples/cognito-user-pool/main.tf中声明了provider "aws",区域取自 variables.tf 中的var.aws_region,默认值为us-west-2,同时约束了 Terraform 版本>= 0.12。
从源码结构看,示例是一个最小可运行的闭环:Cognito 在发送短信验证码时通过aws_iam_role.cidp调用 SNS,而邮件与短信内容模板、密码策略、属性 Schema 等都由用户池资源自身配置,无需额外云资源。
二、运行示例:plan / apply / destroy 全流程
原文档给出了三阶段的 CLI 操作,这里补充每步的预期输出与用途:
# 1. 规划阶段:对比声明与当前云资源,输出将要执行的变更 terraform plan # 2. 应用阶段:实际创建/更新资源,并生成 terraform.tfstate 状态文件 terraform apply # 3. 销毁阶段:按 key_name 变量指定参数拆除整个栈 terraform destroy -var 'key_name={your_key_name}'terraform plan只做差异分析(dry-run),不触碰真实资源;建议在任何apply前先执行,确认预期变更符合意图。terraform apply会提示输入确认(除非带-auto-approve),执行后资源 ID 会写入 state。terraform destroy依次删除用户池、Lambda 函数与 IAM 角色;示例中原文档在 destroy 时使用-var传入key_name,此处变量并非本示例variables.tf中定义,属于文档遗留示例,实际使用时请根据自己定义的变量名传入对应值。
注意:Terraform 对
aws_cognito_user_pool默认是幂等的,重复apply不会产生额外资源;删除用户池前请确认没有关联的 App Client、Domain 等依赖,否则需先解除。
三、Provider 实现为示例背书:aws_cognito_user_pool的完整参数面
示例中使用的每一项配置,都能在 Provider 源码 internal/service/cognitoidp/user_pool.go 的 Schema 定义中找到对应字段。下表汇总了示例涉及的核心参数及其约束:
| 参数块/字段 | 位置(源码行号) | 类型与约束 | 默认值 |
|---|---|---|---|
alias_attributes | user_pool.goL121-130 | Set<String>,ForceNew,与username_attributes互斥 | 无 |
auto_verified_attributes | L135-142 | Set<String>,取值受awstypes.VerifiedAttributeType枚举约束 | 无 |
email_verification_subject/email_verification_message | L241-254 | 与verification_message_template.0.email_subject/email_message冲突 | 无 |
lambda_config | L263-387 | List,MaxItems=1;内部字段大多为ValidARN校验的 ARN 字符串 | 无 |
password_policy | L407-448 | List,MaxItems=1;minimum_length范围 6~99,password_history_size0~24,temporary_password_validity_days0~365 | 见下文 |
schema | L449-533 | Set,MinItems=1,MaxItems=50;attribute_data_type受枚举约束 | 无 |
sms_configuration | L539-563 | List,MaxItems=1;external_id必填,sns_caller_arn必填且需合法 ARN | 无 |
verification_message_template | L666-714 | List,MaxItems=1;default_email_option默认CONFIRM_WITH_CODE | CONFIRM_WITH_CODE |
sms_verification_message | L564-570 | 与verification_message_template.0.sms_message冲突 | 无 |
email_configuration.reply_to_email_address | L199-207 | 需匹配邮箱正则 | 无 |
mfa_configuration | L392-397 | 默认OFF | OFF |
3.1 别名与自动验证属性
alias_attributes:允许用户使用email、preferred_username等作为登录别名;源码中该字段标记ForceNew: true(L124),意味着修改后会触发资源重建,且与username_attributes互斥(L129)。auto_verified_attributes:声明注册后自动完成验证的属性,示例中选择["email"],即用户注册时 Cognito 自动发送验证码并验证邮箱。
3.2 验证消息模板
示例同时使用了顶层email_verification_subject / email_verification_message / sms_verification_message与嵌套verification_message_template:
email_verification_subject = "Device Verification Code" email_verification_message = "Please use the following code {####}" sms_verification_message = "{####} Baz" verification_message_template { default_email_option = "CONFIRM_WITH_CODE" }源码中这两组字段被标记为ConflictsWith互斥(L246、L253、L569),因此实际生产配置中二选一即可,示例同时列出是为了展示两种写法。{####}是 Cognito 约定的验证码占位符,消息内容须包含该占位符才能通过校验(见validUserPoolTemplateEmailMessage等校验函数)。
default_email_option支持CONFIRM_WITH_CODE与CONFIRM_WITH_LINK两种取值,默认CONFIRM_WITH_CODE(L673-678)。
3.3 密码策略
password_policy { minimum_length = 10 require_lowercase = false require_numbers = true require_symbols = false require_uppercase = true }源码约束:minimum_length范围 6~99(L417),另外可配置password_history_size(0~24)与temporary_password_validity_days(0~365)。示例刻意关闭小写与符号要求、强制数字与大小写,演示了灵活组合。
3.4 Schema 属性定义
示例定义了两个自定义属性:
schema { attribute_data_type = "String" developer_only_attribute = false mutable = false name = "email" required = true string_attribute_constraints { min_length = 7 max_length = 15 } } schema { attribute_data_type = "Number" developer_only_attribute = true mutable = true name = "mynumber" required = false number_attribute_constraints { min_value = 2 max_value = 6 } }源码限制:整个schema集合最多 50 项(L453),attribute_data_type只能取枚举定义的类型(String/Number/DateTime/Boolean 等,L460)。注意示例中 String 属性把min_length设为 7、max_length设为 15——这意味着用户邮箱必须满足该长度范围,实际部署时建议按真实邮箱长度调整。此外mutable = false表示该属性创建后不可修改,required = true表示注册时必填。
四、IAM 授权链路:Lambda 与 SNS 的两种信任模型
示例用两个 IAM 角色展示了 Terraform 中最常见的两种服务授权模式。
4.1 Lambda 执行角色aws_iam_role.main
resource "aws_iam_role" "main" { name = "terraform-example-lambda" assume_role_policy = <<EOF { "Version": "2012-10-17", "Statement": [ { "Action": "sts:AssumeRole", "Principal": { "Service": "lambda.amazonaws.com" }, "Effect": "Allow", "Sid": "" } ] } EOF }信任策略(Trust Policy)声明谁可以扮演这个角色——此处允许 AWS Lambda 服务代入。该角色随后被aws_lambda_function.main通过role = aws_iam_role.main.arn引用(main.tf L35),构成「函数 → 角色」的绑定。
4.2 Cognito 服务角色aws_iam_role.cidp
resource "aws_iam_role" "cidp" { name = "terraform-example-cognito-idp" path = "/service-role/" assume_role_policy = <<POLICY { "Version": "2012-10-17", "Statement": [ { "Sid": "", "Effect": "Allow", "Principal": { "Service": "cognito-idp.amazonaws.com" }, "Action": "sts:AssumeRole", "Condition": { "StringEquals": { "sts:ExternalId": "12345" } } } ] } POLICY }关键点在于Condition.sts:ExternalId——Cognito 在代入该角色时必须携带外部 ID12345,这为跨账户信任增加了安全护栏。同时注意:
- 角色路径设为
/service-role/,符合 AWS 管理控制台创建服务角色时的默认路径惯例; - 该角色的
external_id与用户池sms_configuration.external_id(main.tf L157)必须一致,否则短信发送会因信任校验失败。
4.3 内联策略:只给最小权限
resource "aws_iam_role_policy" "main" { name = "terraform-example-cognito-idp" role = aws_iam_role.cidp.id policy = <<EOF { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": ["sns:publish"], "Resource": ["*"] } ] } EOF }该策略通过role = aws_iam_role.cidp.id挂到 Cognito 服务角色上,只开放sns:publish——即用户池发送短信验证码时所需的唯一权限。sns_caller_arn = aws_iam_role.cidp.arn(main.tf L158)在用户池侧完成引用闭环。
五、Lambda 触发器:lambda_config的十个钩子与 V2 版本演进
示例将同一个Lambda 函数同时挂到用户池的全部生命周期钩子上,便于演示;生产环境通常按钩子拆分不同函数:
lambda_config { create_auth_challenge = aws_lambda_function.main.arn custom_message = aws_lambda_function.main.arn define_auth_challenge = aws_lambda_function.main.arn post_authentication = aws_lambda_function.main.arn post_confirmation = aws_lambda_function.main.arn pre_authentication = aws_lambda_function.main.arn pre_sign_up = aws_lambda_function.main.arn pre_token_generation = aws_lambda_function.main.arn user_migration = aws_lambda_function.main.arn verify_auth_challenge_response = aws_lambda_function.main.arn pre_token_generation_config { lambda_arn = aws_lambda_function.main.arn lambda_version = "V2_0" } }每个钩子的语义与源码位置:
| 触发器 | 触发时机 | 典型用途 |
|---|---|---|
pre_sign_up | 用户注册前 | 自定义注册校验、风控 |
post_confirmation | 确认注册后 | 初始化用户数据、发欢迎邮件 |
pre_authentication | 登录认证前 | 阻断/放行登录 |
post_authentication | 认证成功后 | 审计、更新最后登录时间 |
custom_message | 发送验证码/邀请前 | 定制邮件与短信内容 |
define_auth_challenge | 自定义认证挑战定义 | 无密码认证流程 |
create_auth_challenge | 创建挑战时 | 生成 MFA 挑战 |
verify_auth_challenge_response | 校验挑战答案 | 自定义 MFA 校验 |
user_migration | 首次登录时 | 从旧系统迁移用户 |
pre_token_generation | 签发 Token 前 | 注入自定义 Claims |
源码中这些字段均为ValidateFunc: verify.ValidARN(L269-383),即只能填合法 ARN。
值得注意的演进:源码 L349-374 中pre_token_generation标记为Optional + Computed,而新增的pre_token_generation_config子块要求同时提供lambda_arn与lambda_version(V2_0等,受awstypes.PreTokenGenerationLambdaVersionType枚举约束)。示例注释也指出:pre_token_generation字段保留是为了兼容旧配置,新配置应使用pre_token_generation_config并让两者 ARN 保持一致。
对应验收测试TestAccCognitoIDPUserPool_withLambda(user_pool_test.go L1264-1303)会逐一断言lambda_config.0.create_auth_challenge等 10 个字段与 Lambda 资源的 ARN 相等,并执行导入验证与更新验证,这为示例的字段用法提供了测试背书。
5.1 Lambda 函数本身的声明
resource "aws_lambda_function" "main" { filename = "lambda_function.zip" function_name = "terraform-example" role = aws_iam_role.main.arn handler = "exports.example" runtime = "nodejs24.x" }filename指向本地打包好的 lambda_function.zip(示例目录中已附带);handler为exports.example,即 zip 内 JS 文件导出名为example的函数;runtime为nodejs24.x,以当前仓库示例为准,不同版本的 Provider 支持的语言运行时集合可能不同。
六、SMS 与邮件发送:sms_configuration/email_configuration
6.1 短信配置
sms_configuration { external_id = "12345" sns_caller_arn = aws_iam_role.cidp.arn }源码 L539-563 规定:external_id与sns_caller_arn均为必填;sns_region可选(默认跟随 Provider 区域,可用verify.ValidRegionName校验)。此处的external_id必须与 4.2 节信任策略中的sts:ExternalId完全一致。
6.2 邮件配置
email_configuration { reply_to_email_address = "foo.bar@baz" }源码 L199-207 对该字段做了正则校验(必须匹配邮箱格式),且email_sending_account默认COGNITO_DEFAULT(即使用 Cognito 内置发件账户),生产环境可改用DEVELOPER模式并配合from_email_address/source_arn使用 SES。
七、标签与资源引用:Terraform 声明式的闭环
示例在用户池末尾声明了两枚标签:
tags = { Name = "FooBar" Project = "Terraform" }aws_cognito_user_pool的 Schema 中tags与tags_all均由 internal/tags 包生成(见 user_pool.go L585-586),所有支持标签的 AWS 资源在 Provider 中遵循同一套标准:tags声明、tags_all合并 Provider 默认标签后只读输出。
整个示例的资源依赖关系可以概括为一条引用链:
aws_iam_role.main ──> aws_lambda_function.main ──> aws_cognito_user_pool.pool.lambda_config aws_iam_role.cidp ──> aws_iam_role_policy.main(sns:publish) ──> aws_cognito_user_pool.pool.sms_configuration(sns_caller_arn + external_id)Terraform 依据这些aws_xxx.xxx.attr表达式自动推导依赖拓扑,apply时按序创建:先 IAM 角色,再 Lambda 函数,最后用户池。
八、从示例到生产的差异点提示
基于源码约束,示例中的几处写法在真实项目中需要调整:
- 互斥字段二选一:
email_verification_message与verification_message_template.0.email_message冲突(源码 L246),正式配置请统一使用verification_message_template块。 - Schema 约束要与业务匹配:示例中 email 属性
min_length = 7 / max_length = 15对真实邮箱过短,建议放宽或删除;required = true的email属性在 Cognito 中本就默认必填。 - Lambda 触发器按需裁剪:十个钩子指向同一函数适合演示,生产上应拆分并配独立的执行角色与最小权限策略。
- 短信区域与 SNS:如需跨区域发送短信,通过
sms_configuration.sns_region显式指定 SNS 区域,并确保对应区域存在可用主题/账号配额。 - 删除保护:源码中
deletion_protection默认INACTIVE(L151-156),生产用户池建议显式开启ACTIVE以防误删。
九、小结
本示例以 5 个资源、3 个文件(main.tf、variables.tf、lambda_function.zip)完整演示了 Cognito User Pool 的 Terraform 落地路径:通过 IAM 信任策略解决「Lambda 执行」与「Cognito 代发短信」两类授权,通过lambda_config把用户生命周期钩子接入函数,再以密码策略、Schema、消息模板与标签完成用户池的声明式配置。配合源码 internal/service/cognitoidp/user_pool.go 中的 Schema 约束与 user_pool_test.go 中的验收测试,可以进一步验证任意字段的取值边界与行为,作为自建身份体系的可靠起点。
【免费下载链接】terraform-provider-awsThe AWS Provider enables Terraform to manage AWS resources.项目地址: https://gitcode.com/GitHub_Trending/te/terraform-provider-aws
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考