unfunco/terraform-aws-contact-form
GitHub: unfunco/terraform-aws-contact-form
这是一个基于 Terraform 的 AWS 无服务器联系表单模块,集成了 Lambda、CloudFront、SES 和 WAF 以实现安全部署和邮件通知。
Stars: 0 | Forks: 0
# AWS 联系表单 Terraform Module
[](https://github.com/unfunco/terraform-aws-contact-form/actions/workflows/ci.yaml)
[](https://registry.terraform.io/modules/unfunco/contact-form/aws)
[](LICENSE.md)
一个用于 AWS Lambda 联系表单端点的 Terraform 模块,前端使用 CloudFront
并由 AWS WAF 保护。
## 入门指南
### 要求
- [Terraform] 1.14+
### 安装和使用
请参阅 [`examples/minimal`](./examples/minimal) 了解最小的可部署设置,
或参阅 [`examples/static-website`](./examples/static-website) 以通过 `unfunco/static-website/aws`
路由提交内容。
#### 最小化示例
```
provider "aws" {
region = "eu-west-2"
}
module "contact_form" {
source = "unfunco/contact-form/aws"
version = "0.2.0"
email_recipients = ["hello@example.com"]
ses_source_email = "no-reply@example.com"
}
output "contact_form_url" {
value = module.contact_form.endpoint_url
}
```
```
```
#### 位于 `unfunco/static-website/aws` 之后
```
module "contact_form" {
source = "unfunco/contact-form/aws"
version = "0.2.0"
name = "unfunco-contact-form"
create_cloudfront_distribution = false
allow_all_cloudfront_distributions = true
cors_allow_origins = [
"https://unfun.co",
"https://www.unfun.co",
]
email_recipients = ["hello@unfun.co"]
ses_source_email = "no-reply@unfun.co"
}
```
```
module "unfunco_website" {
source = "unfunco/static-website/aws"
version = "0.5.0"
domain_name = "unfun.co"
cloudfront_web_acl_id = module.contact_form.waf_web_acl_arn
cloudfront_additional_origins = {
contact_form = {
domain_name = module.contact_form.cloudfront_origin_domain_name
origin_access_control_id = module.contact_form.cloudfront_origin_access_control_id
}
}
cloudfront_ordered_cache_behaviors = [
{
path_pattern = "/contact"
allowed_methods = ["OPTIONS", "POST"]
cached_methods = ["OPTIONS"]
cache_policy_id = module.contact_form.cloudfront_cache_policy_id
origin_request_policy_id = module.contact_form.cloudfront_origin_request_policy_id
target_origin_id = "contact_form"
},
]
}
```
```
curl -X POST https://<> \
-H 'content-type: application/json' \
-d '{"name":"Alice Example","email":"alice@example.com","message":"Hello"}'
```
成功的提交将返回带有 JSON 确认消息的 `200 OK`。
验证失败将返回描述问题的 JSON `4xx` 响应。
默认情况下,Lambda 预留 5 个并发执行,并拒绝解码后超过 16 KiB 的请求正文、
超过 10 个字段的提交,或任何长度超过 2,000 个字符的字段值。
### 资源
| 名称 | 类型 |
| ---- | ---- |
| [aws_cloudfront_distribution.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudfront_distribution) | resource |
| [aws_cloudfront_origin_access_control.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudfront_origin_access_control) | resource |
| [aws_cloudwatch_log_group.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_group) | resource |
| [aws_iam_role.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |
| [aws_iam_role_policy.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy) | resource |
| [aws_lambda_function.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_function) | resource |
| [aws_lambda_function_url.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_function_url) | resource |
| [aws_lambda_permission.function_url_cloudfront_any](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_permission) | resource |
| [aws_lambda_permission.function_url_cloudfront_any_invoke](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_permission) | resource |
| [aws_lambda_permission.function_url_cloudfront_managed](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_permission) | resource |
| [aws_lambda_permission.function_url_cloudfront_managed_invoke](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_permission) | resource |
| [aws_lambda_permission.function_url_cloudfront_trusted](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_permission) | resource |
| [aws_lambda_permission.function_url_cloudfront_trusted_invoke](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_permission) | resource |
| [aws_lambda_permission.function_url_public](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_permission) | resource |
| [aws_lambda_permission.function_url_public_invoke](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_permission) | resource |
| [aws_ssm_parameter.email_recipients](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ssm_parameter) | resource |
| [aws_wafv2_web_acl.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/wafv2_web_acl) | resource |
| [archive_file.lambda](https://registry.terraform.io/providers/hashicorp/archive/latest/docs/data-sources/file) | data source |
| [aws_caller_identity.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source |
| [aws_cloudfront_cache_policy.caching_disabled](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/cloudfront_cache_policy) | data source |
| [aws_cloudfront_origin_request_policy.all_viewer_except_host_header](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/cloudfront_origin_request_policy) | data source |
| [aws_iam_policy_document.assume_role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
| [aws_iam_policy_document.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
| [aws_partition.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/partition) | data source |
| [aws_region.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/region) | data source |
### 输入参数
| 名称 | 描述 | 类型 | 默认值 | 必填 |
| ---- | ----------- | ---- | ------- | :------: |
| allow\_all\_cloudfront\_distributions | 允许任何 CloudFront 分发使用 SigV4 签名请求调用 Lambda Function URL。当在同一 Terraform apply 中与另一个 CloudFront 分发集成且其 ARN 尚不可用时,这非常有用。如果可能,请优先使用 trusted\_cloudfront\_distribution\_arns。 | `bool` | `false` | no |
| cloudfront\_price\_class | 面向联系表单端点的 CloudFront 分发的价格等级。 | `string` | `"PriceClass_100"` | no |
| cors\_allow\_origins | 允许的 CORS 源列表。 | `list(string)` | ```[ "*" ]``` | no |
| create | 启用/禁用所有资源的创建。 | `bool` | `true` | no |
| create\_cloudfront\_distribution | 在 Lambda Function URL 前面创建一个 CloudFront 分发,以便公共端点受到 AWS WAF 保护,并且原始函数 URL 对 CloudFront 保持私有。 | `bool` | `true` | no |
| create\_waf | 为公共 CloudFront 分发创建一个默认安全的 AWS WAF Web ACL。根据 AWS 要求,CloudFront 范围的 Web ACL 在内部于 us-east-1 中进行管理。 | `bool` | `true` | no |
| email\_recipients | 接收通知的电子邮件列表。当不为空时,需要 ses\_source\_email。 | `list(string)` | `[]` | no |
| email\_template | 自定义 HTML 电子邮件模板内容。使用 $field\_name 或 $fields\_html 进行表单值的变量替换。当为 null 时,使用默认模板。 | `string` | `null` | no |
| enable\_logging | 为 Lambda 函数启用 JSON 应用程序日志记录配置和 Powertools 记录器支持。 | `bool` | `true` | no |
| enable\_powertools\_development\_mode | 为 Lambda 函数启用 Powertools 开发模式、调试日志记录和 Powertools 事件日志记录。 | `bool` | `false` | no |
| enable\_tracing | 为 Lambda 函数启用 AWS X-Ray 追踪和 Powertools 追踪器支持。 | `bool` | `false` | no |
| enable\_waf\_bot\_control | 在模块托管的 WAF 上启用 AWS 托管的 Bot Control 规则组。这可以提高滥用防御能力,但会产生额外的 AWS WAF 费用。 | `bool` | `false` | no |
| environment\_variables | 在 Lambda 函数上设置的其他环境变量。 | `map(string)` | `{}` | no |
| fields | 接受和验证的表单字段列表。支持的类型:text、email、textarea。 | ```list(object({ name = string type = string }))``` | ```[ { "name": "name", "type": "text" }, { "name": "email", "type": "email" }, { "name": "message", "type": "textarea" } ]``` | no |
| kms\_key\_arn | 用于加密日志组的 KMS 密钥的 ARN。 | `string` | `null` | no |
| log\_level | Lambda 和 Powertools 的应用程序日志级别。有效值:TRACE、DEBUG、INFO、WARN、ERROR、FATAL。DEBUG 也会启用 Powertools 事件日志记录。 | `string` | `"INFO"` | no |
| log\_retention\_in\_days | 在 CloudWatch Log Group 中保留日志的天数。 | `number` | `365` | no |
| max\_field\_count | 单次提交中接受的最大字段数,包括隐藏或额外字段。 | `number` | `10` | no |
| max\_field\_length | 任何提交字段值中允许的最大字符数。 | `number` | `2000` | no |
| max\_request\_body\_size | 解码后的请求主体允许的最大大小(以字节为单位)。 | `number` | `16384` | no |
| memory\_size | 分配给 Lambda 函数的内存量(以 MB 为单位)。 | `number` | `128` | no |
| name | 用于 Lambda 函数和相关资源的名称。 | `string` | `"contact-form"` | no |
| reserved\_concurrent\_executions | Lambda 函数的预留并发执行数,以限制滥用驱动的并行度。设置为 -1 可移除限制。 | `number` | `5` | no |
| ses\_source\_email | 用于通知的已验证 SES 发件人地址。当 email\_recipients 不为空时,此项为必填。 | `string` | `null` | no |
| tags | 应用于所有适用资源的标签。 | `map(string)` | `{}` | no |
| trusted\_cloudfront\_distribution\_arns | 当您通过另一个分发(例如 unfunco/static-website/aws)路由联系表单流量时,应被允许调用 Lambda Function URL 的现有 CloudFront 分发 ARN。 | `list(string)` | `[]` | no |
| waf\_rate\_limit | 在模块托管的 AWS WAF 阻止请求之前,单个 IP 地址在滚动的 5 分钟窗口内允许的最大请求数。 | `number` | `100` | no |
| waf\_web\_acl\_arn | 要与 CloudFront 分发关联的现有 CLOUDFRONT 范围的 AWS WAF Web ACL ARN,而不是创建一个新的。 | `string` | `null` | no |
### 输出参数
| 名称 | 描述 |
| ---- | ----------- |
| cloudfront\_cache\_policy\_id | 为联系表单端点禁用缓存的 CloudFront 缓存策略 ID。 |
| cloudfront\_distribution\_arn | 面向联系表单端点的 CloudFront 分发的 ARN。 |
| cloudfront\_domain\_name | 公共联系表单端点的 CloudFront 域名。 |
| cloudfront\_origin\_access\_control\_id | CloudFront 源访问控制 ID,用于在另一个 CloudFront 分发中安全地使用 Lambda Function URL 作为源,例如 unfunco/static-website/aws。 |
| cloudfront\_origin\_domain\_name | 将 Lambda Function URL 连接到另一个 CloudFront 分发作为自定义源时使用的域名。 |
| cloudfront\_origin\_request\_policy\_id | 转发除 Host 以外的查看器标头的 CloudFront 源请求策略 ID,适用于 Lambda Function URL 源。 |
| endpoint\_url | 当此模块自行管理公共端点时,用于联系表单提交的公共 URL。如果启用了分发,则为 CloudFront URL;否则,仅当该 URL 为公共时,才会回退到原始 Lambda Function URL。 |
| lambda\_function\_arn | Lambda 函数的 ARN。 |
| lambda\_function\_name | Lambda 函数的名称。 |
| lambda\_role\_arn | Lambda 执行角色的 ARN。 |
| lambda\_url | 用作 CloudFront 源的 Lambda Function URL。当此模块管理 CloudFront 或设置了 trusted\_cloudfront\_distribution\_arns 时,此 URL 需要 IAM 签名请求,并非面向浏览器。 |
| log\_group\_name | Lambda 函数使用的 CloudWatch 日志组的名称。 |
| waf\_web\_acl\_arn | 为公共 CloudFront 端点创建或使用的 AWS WAF Web ACL 的 ARN,无论该分发是由此处管理还是由另一个模块管理。 |
### 版本发布
此代码仓库使用 [Release Please] 自动化版本发布。当合并带有 [conventional commit] 消息的
拉取请求时,Release Please 将打开或更新一个拉取请求以升级版本并更新变更日志。
一旦该拉取请求被合并,将创建一个新版本。
## 许可证
© 2026 [Daniel Morris]\
根据 [MIT License] 的条款提供。
标签:AWS, CDN, CloudFront, CORS, DNS解析, DPI, ECS, Infrastructure as Code, Lambda, SES, Terraform, WAF, Web安全, 前端集成, 开源项目, 特权提升, 联系表单, 自动化部署, 蓝队分析, 表单提交, 邮件发送