{"id":49882153,"url":"https://github.com/unfunco/terraform-aws-contact-form","last_synced_at":"2026-05-15T15:34:54.132Z","repository":{"id":350690370,"uuid":"1187805428","full_name":"unfunco/terraform-aws-contact-form","owner":"unfunco","description":"Terraform module to deploy a serverless contact form on AWS with Lambda, CloudFront, SES, and WAF.","archived":false,"fork":false,"pushed_at":"2026-04-19T14:13:08.000Z","size":66,"stargazers_count":0,"open_issues_count":1,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-19T16:18:21.798Z","etag":null,"topics":["amazon-web-services","aws","cloudfront","contact-form","infrastructure-as-code","lambda","python","serverless","ses","terraform","terraform-module","waf"],"latest_commit_sha":null,"homepage":"","language":"HCL","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/unfunco.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-21T07:27:50.000Z","updated_at":"2026-04-19T14:12:28.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/unfunco/terraform-aws-contact-form","commit_stats":null,"previous_names":["unfunco/terraform-aws-contact-form"],"tags_count":2,"template":false,"template_full_name":"unfunco/template-terraform-aws-module","purl":"pkg:github/unfunco/terraform-aws-contact-form","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/unfunco%2Fterraform-aws-contact-form","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/unfunco%2Fterraform-aws-contact-form/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/unfunco%2Fterraform-aws-contact-form/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/unfunco%2Fterraform-aws-contact-form/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/unfunco","download_url":"https://codeload.github.com/unfunco/terraform-aws-contact-form/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/unfunco%2Fterraform-aws-contact-form/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33071309,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-15T11:35:32.926Z","status":"ssl_error","status_checked_at":"2026-05-15T11:35:31.362Z","response_time":103,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["amazon-web-services","aws","cloudfront","contact-form","infrastructure-as-code","lambda","python","serverless","ses","terraform","terraform-module","waf"],"created_at":"2026-05-15T15:34:52.079Z","updated_at":"2026-05-15T15:34:54.121Z","avatar_url":"https://github.com/unfunco.png","language":"HCL","funding_links":[],"categories":[],"sub_categories":[],"readme":"# AWS Contact Form Terraform Module\n\n[![CI](https://github.com/unfunco/terraform-aws-contact-form/actions/workflows/ci.yaml/badge.svg)](https://github.com/unfunco/terraform-aws-contact-form/actions/workflows/ci.yaml)\n[![Terraform Registry](https://img.shields.io/badge/Terraform%20Registry-unfunco%2Fcontact--form-blue?logo=terraform)](https://registry.terraform.io/modules/unfunco/contact-form/aws)\n[![License: MIT](https://img.shields.io/badge/License-MIT-purple.svg)](LICENSE.md)\n\nA Terraform module for an AWS Lambda contact form endpoint fronted by CloudFront\nand protected by AWS WAF.\n\n## Getting started\n\n### Requirements\n\n- [Terraform] 1.14+\n\n### Installation and usage\n\nSee [`examples/minimal`](./examples/minimal) for the smallest deployable setup,\nor [`examples/static-website`](./examples/static-website) to route submissions\nthrough `unfunco/static-website/aws`.\n\n#### Minimal\n\n\u003c!-- x-release-please-start-version --\u003e\n\n```terraform\nprovider \"aws\" {\n  region = \"eu-west-2\"\n}\n\nmodule \"contact_form\" {\n  source  = \"unfunco/contact-form/aws\"\n  version = \"0.2.0\"\n\n  email_recipients = [\"hello@example.com\"]\n  ses_source_email = \"no-reply@example.com\"\n}\n\noutput \"contact_form_url\" {\n  value = module.contact_form.endpoint_url\n}\n```\n\n```html\n\n\u003cform action=\"https://\u003c\u003e\" method=\"post\"\u003e\n  \u003cinput name=\"email\" type=\"email\" required /\u003e\n  \u003cinput name=\"name\" type=\"text\" required /\u003e\n  \u003ctextarea name=\"message\" required\u003e\u003c/textarea\u003e\n  \u003cbutton type=\"submit\"\u003eSend\u003c/button\u003e\n\u003c/form\u003e\n```\n\n#### Behind `unfunco/static-website/aws`\n\n```terraform\nmodule \"contact_form\" {\n  source  = \"unfunco/contact-form/aws\"\n  version = \"0.2.0\"\n\n  name                           = \"unfunco-contact-form\"\n  create_cloudfront_distribution = false\n  allow_all_cloudfront_distributions = true\n\n  cors_allow_origins = [\n    \"https://unfun.co\",\n    \"https://www.unfun.co\",\n  ]\n\n  email_recipients = [\"hello@unfun.co\"]\n  ses_source_email = \"no-reply@unfun.co\"\n}\n```\n\n\u003c!-- x-release-please-end --\u003e\n\n```terraform\nmodule \"unfunco_website\" {\n  source  = \"unfunco/static-website/aws\"\n  version = \"0.5.0\"\n\n  domain_name         = \"unfun.co\"\n  cloudfront_web_acl_id = module.contact_form.waf_web_acl_arn\n\n  cloudfront_additional_origins = {\n    contact_form = {\n      domain_name              = module.contact_form.cloudfront_origin_domain_name\n      origin_access_control_id = module.contact_form.cloudfront_origin_access_control_id\n    }\n  }\n\n  cloudfront_ordered_cache_behaviors = [\n    {\n      path_pattern             = \"/contact\"\n      allowed_methods          = [\"OPTIONS\", \"POST\"]\n      cached_methods           = [\"OPTIONS\"]\n      cache_policy_id          = module.contact_form.cloudfront_cache_policy_id\n      origin_request_policy_id = module.contact_form.cloudfront_origin_request_policy_id\n      target_origin_id         = \"contact_form\"\n    },\n  ]\n}\n```\n\n```sh\ncurl -X POST https://\u003c\u003e \\\n  -H 'content-type: application/json' \\\n  -d '{\"name\":\"Alice Example\",\"email\":\"alice@example.com\",\"message\":\"Hello\"}'\n```\n\nSuccessful submissions return `200 OK` with a JSON confirmation message.\nValidation failures return a JSON `4xx` response describing the problem.\nBy default, the Lambda reserves 5 concurrent executions and rejects decoded\nrequest bodies over 16 KiB, submissions with more than 10 fields, or any field\nvalue longer than 2,000 characters.\n\n\u003c!-- BEGIN_TF_DOCS --\u003e\n### Resources\n\n| Name | Type |\n| ---- | ---- |\n| [aws_cloudfront_distribution.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudfront_distribution) | resource |\n| [aws_cloudfront_origin_access_control.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudfront_origin_access_control) | resource |\n| [aws_cloudwatch_log_group.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_group) | resource |\n| [aws_iam_role.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |\n| [aws_iam_role_policy.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy) | resource |\n| [aws_lambda_function.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_function) | resource |\n| [aws_lambda_function_url.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_function_url) | resource |\n| [aws_lambda_permission.function_url_cloudfront_any](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_permission) | resource |\n| [aws_lambda_permission.function_url_cloudfront_any_invoke](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_permission) | resource |\n| [aws_lambda_permission.function_url_cloudfront_managed](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_permission) | resource |\n| [aws_lambda_permission.function_url_cloudfront_managed_invoke](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_permission) | resource |\n| [aws_lambda_permission.function_url_cloudfront_trusted](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_permission) | resource |\n| [aws_lambda_permission.function_url_cloudfront_trusted_invoke](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_permission) | resource |\n| [aws_lambda_permission.function_url_public](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_permission) | resource |\n| [aws_lambda_permission.function_url_public_invoke](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_permission) | resource |\n| [aws_ssm_parameter.email_recipients](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ssm_parameter) | resource |\n| [aws_wafv2_web_acl.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/wafv2_web_acl) | resource |\n| [archive_file.lambda](https://registry.terraform.io/providers/hashicorp/archive/latest/docs/data-sources/file) | data source |\n| [aws_caller_identity.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source |\n| [aws_cloudfront_cache_policy.caching_disabled](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/cloudfront_cache_policy) | data source |\n| [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 |\n| [aws_iam_policy_document.assume_role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |\n| [aws_iam_policy_document.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |\n| [aws_partition.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/partition) | data source |\n| [aws_region.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/region) | data source |\n\n### Inputs\n\n| Name | Description | Type | Default | Required |\n| ---- | ----------- | ---- | ------- | :------: |\n| allow\\_all\\_cloudfront\\_distributions | Allow any CloudFront distribution to invoke the Lambda Function URL with SigV4-signed requests. This is useful when integrating with another CloudFront distribution in the same Terraform apply and its ARN is not available yet. Prefer trusted\\_cloudfront\\_distribution\\_arns when possible. | `bool` | `false` | no |\n| cloudfront\\_price\\_class | Price class for the CloudFront distribution that fronts the contact form endpoint. | `string` | `\"PriceClass_100\"` | no |\n| cors\\_allow\\_origins | List of allowed origins for CORS. | `list(string)` | ```[ \"*\" ]``` | no |\n| create | Enable/disable the creation of all resources. | `bool` | `true` | no |\n| create\\_cloudfront\\_distribution | Create a CloudFront distribution in front of the Lambda Function URL so the public endpoint can be protected by AWS WAF and the raw function URL can remain private to CloudFront. | `bool` | `true` | no |\n| create\\_waf | Create a secure-by-default AWS WAF web ACL for the public CloudFront distribution. The CloudFront-scope web ACL is managed in us-east-1 internally, as required by AWS. | `bool` | `true` | no |\n| email\\_recipients | List of emails to receive notifications. Requires ses\\_source\\_email when not empty. | `list(string)` | `[]` | no |\n| email\\_template | Custom HTML email template content. Use $field\\_name or $fields\\_html for variable substitution with form values. When null, the default template is used. | `string` | `null` | no |\n| enable\\_logging | Enable JSON application logging configuration and Powertools logger support for the Lambda function. | `bool` | `true` | no |\n| enable\\_powertools\\_development\\_mode | Enable Powertools development mode, debug logging, and Powertools event logging for the Lambda function. | `bool` | `false` | no |\n| enable\\_tracing | Enable AWS X-Ray tracing and Powertools tracer support for the Lambda function. | `bool` | `false` | no |\n| enable\\_waf\\_bot\\_control | Enable the AWS Managed Bot Control rule group on the module-managed WAF. This improves abuse resistance but incurs additional AWS WAF charges. | `bool` | `false` | no |\n| environment\\_variables | Additional environment variables to set on the Lambda function. | `map(string)` | `{}` | no |\n| fields | List of form fields to accept and validate. Supported types: text, email, textarea. | ```list(object({ name = string type = string }))``` | ```[ { \"name\": \"name\", \"type\": \"text\" }, { \"name\": \"email\", \"type\": \"email\" }, { \"name\": \"message\", \"type\": \"textarea\" } ]``` | no |\n| kms\\_key\\_arn | ARN of the KMS key to use for encrypting the log group. | `string` | `null` | no |\n| log\\_level | Application log level for Lambda and Powertools. Valid values: TRACE, DEBUG, INFO, WARN, ERROR, FATAL. DEBUG also enables Powertools event logging. | `string` | `\"INFO\"` | no |\n| log\\_retention\\_in\\_days | Number of days to retain logs in CloudWatch Log Group. | `number` | `365` | no |\n| max\\_field\\_count | Maximum number of fields accepted in a single submission, including hidden or extra fields. | `number` | `10` | no |\n| max\\_field\\_length | Maximum number of characters allowed in any submitted field value. | `number` | `2000` | no |\n| max\\_request\\_body\\_size | Maximum size, in bytes, allowed for the decoded request body. | `number` | `16384` | no |\n| memory\\_size | Amount of memory, in MB, allocated to the Lambda function. | `number` | `128` | no |\n| name | Name to use for the Lambda function and related resources. | `string` | `\"contact-form\"` | no |\n| reserved\\_concurrent\\_executions | Reserved concurrent executions for the Lambda function to cap abuse-driven parallelism. Set to -1 to remove the limit. | `number` | `5` | no |\n| ses\\_source\\_email | Verified SES sender address used for notifications. Required when email\\_recipients is not empty. | `string` | `null` | no |\n| tags | Tags to be applied to all applicable resources. | `map(string)` | `{}` | no |\n| trusted\\_cloudfront\\_distribution\\_arns | Existing CloudFront distribution ARNs that should be allowed to invoke the Lambda Function URL when you are routing contact-form traffic through another distribution, such as unfunco/static-website/aws. | `list(string)` | `[]` | no |\n| waf\\_rate\\_limit | Maximum number of requests allowed from a single IP address in a rolling 5-minute window before the module-managed AWS WAF blocks it. | `number` | `100` | no |\n| waf\\_web\\_acl\\_arn | Existing CLOUDFRONT-scope AWS WAF web ACL ARN to associate with the CloudFront distribution instead of creating one. | `string` | `null` | no |\n\n### Outputs\n\n| Name | Description |\n| ---- | ----------- |\n| cloudfront\\_cache\\_policy\\_id | CloudFront cache policy ID that disables caching for the contact form endpoint. |\n| cloudfront\\_distribution\\_arn | ARN of the CloudFront distribution that fronts the contact form endpoint. |\n| cloudfront\\_domain\\_name | CloudFront domain name for the public contact form endpoint. |\n| cloudfront\\_origin\\_access\\_control\\_id | CloudFront origin access control ID for securely using the Lambda Function URL as an origin in another CloudFront distribution, such as unfunco/static-website/aws. |\n| cloudfront\\_origin\\_domain\\_name | Domain name to use when wiring the Lambda Function URL into another CloudFront distribution as a custom origin. |\n| cloudfront\\_origin\\_request\\_policy\\_id | CloudFront origin request policy ID that forwards viewer headers except Host, suitable for Lambda Function URL origins. |\n| endpoint\\_url | Public URL to use for contact form submissions when this module manages the public endpoint itself. This is the CloudFront URL when the distribution is enabled; otherwise it falls back to the raw Lambda Function URL only when that URL is public. |\n| lambda\\_function\\_arn | ARN of the Lambda function. |\n| lambda\\_function\\_name | Name of the Lambda function. |\n| lambda\\_role\\_arn | ARN of the Lambda execution role. |\n| lambda\\_url | Lambda Function URL used as the CloudFront origin. When this module manages CloudFront or trusted\\_cloudfront\\_distribution\\_arns is set, this URL requires IAM-signed requests and is not intended for browsers. |\n| log\\_group\\_name | Name of the CloudWatch log group used by the Lambda function. |\n| waf\\_web\\_acl\\_arn | ARN of the AWS WAF web ACL created or used for the public CloudFront endpoint, whether that distribution is managed here or by another module. |\n\u003c!-- END_TF_DOCS --\u003e\n\n### Releases\n\nThis repository uses [Release Please] to automate releases. When pull requests\nwith [conventional commit] messages are merged, Release Please will open or\nupdate a pull request to bump the version and update the changelog. Once that\npull request is merged, a new release will be created.\n\n## License\n\n© 2026 [Daniel Morris]\\\nMade available under the terms of the [MIT License].\n\n[conventional commit]: https://www.conventionalcommits.org\n[daniel morris]: https://unfun.co\n[mit license]: LICENSE.md\n[release please]: https://github.com/googleapis/release-please\n[terraform]: https://www.terraform.io\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Funfunco%2Fterraform-aws-contact-form","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Funfunco%2Fterraform-aws-contact-form","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Funfunco%2Fterraform-aws-contact-form/lists"}