diff --git a/modules/cloudfront-with-s3-as-public-storage/README.md b/modules/cloudfront-with-s3-as-public-storage/README.md
index 3fbdd55..9bf4cac 100644
--- a/modules/cloudfront-with-s3-as-public-storage/README.md
+++ b/modules/cloudfront-with-s3-as-public-storage/README.md
@@ -48,6 +48,7 @@
| Name | Description |
|------|-------------|
| [arn](#output\_arn) | CDN distribution ARN. |
+| [bucket\_name](#output\_bucket\_name) | Name of the storage S3 bucket. |
| [deployment\_group](#output\_deployment\_group) | Deployment group name |
| [deployment\_group\_arn](#output\_deployment\_group\_arn) | Deployment group ARN |
| [deployment\_policy\_id](#output\_deployment\_policy\_id) | IAM policy for deploying CloudFront distribution. |
diff --git a/modules/iam/smtp-user/README.md b/modules/iam/smtp-user/README.md
new file mode 100644
index 0000000..6c04204
--- /dev/null
+++ b/modules/iam/smtp-user/README.md
@@ -0,0 +1,40 @@
+
+## Requirements
+
+| Name | Version |
+|------|---------|
+| [terraform](#requirement\_terraform) | ~> 1.0 |
+| [aws](#requirement\_aws) | ~> 5.0 |
+
+## Providers
+
+| Name | Version |
+|------|---------|
+| [aws](#provider\_aws) | ~> 5.0 |
+
+## Resources
+
+| Name | Type |
+|------|------|
+| [aws_iam_access_key.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_access_key) | resource |
+| [aws_iam_policy.ses_sender](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |
+| [aws_iam_user.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_user) | resource |
+| [aws_iam_user_policy_attachment.ses_sender](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_user_policy_attachment) | resource |
+| [aws_iam_policy_document.ses_sender](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
+
+## Inputs
+
+| Name | Description | Type | Default | Required |
+|------|-------------|------|---------|:--------:|
+| [name](#input\_name) | User name | `string` | n/a | yes |
+
+## Outputs
+
+| Name | Description |
+|------|-------------|
+| [access\_key\_as\_envs](#output\_access\_key\_as\_envs) | User access key map containing AWS\_ACCESS\_KEY\_ID and AWS\_SECRET\_ACCESS\_KEY. |
+| [arn](#output\_arn) | User ARN. |
+| [key\_id](#output\_key\_id) | Access key ID. |
+| [key\_secret](#output\_key\_secret) | Access secret access key. |
+| [name](#output\_name) | User name. |
+
\ No newline at end of file
diff --git a/modules/iam/smtp-user/main.tf b/modules/iam/smtp-user/main.tf
new file mode 100644
index 0000000..28587e9
--- /dev/null
+++ b/modules/iam/smtp-user/main.tf
@@ -0,0 +1,25 @@
+resource "aws_iam_user" "this" {
+ name = var.name
+}
+
+resource "aws_iam_access_key" "this" {
+ user = aws_iam_user.this.name
+}
+
+data "aws_iam_policy_document" "ses_sender" {
+ statement {
+ actions = ["ses:SendRawEmail"]
+ resources = ["*"]
+ }
+}
+
+resource "aws_iam_policy" "ses_sender" {
+ name = "ses_sender"
+ description = "Allows sending of e-mails via Simple Email Service"
+ policy = data.aws_iam_policy_document.ses_sender.json
+}
+
+resource "aws_iam_user_policy_attachment" "ses_sender" {
+ user = aws_iam_user.this.name
+ policy_arn = aws_iam_policy.ses_sender.arn
+}
\ No newline at end of file
diff --git a/modules/iam/smtp-user/outputs.tf b/modules/iam/smtp-user/outputs.tf
new file mode 100644
index 0000000..c65dcb0
--- /dev/null
+++ b/modules/iam/smtp-user/outputs.tf
@@ -0,0 +1,30 @@
+output "name" {
+ description = "User name."
+ value = aws_iam_user.this.name
+}
+
+output "arn" {
+ description = "User ARN."
+ value = aws_iam_user.this.arn
+}
+
+output "access_key_as_envs" {
+ description = "User access key map containing AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY."
+ value = {
+ AWS_ACCESS_KEY_ID = aws_iam_access_key.this.id
+ AWS_SECRET_ACCESS_KEY = aws_iam_access_key.this.ses_smtp_password_v4
+ }
+ sensitive = true
+}
+
+output "key_id" {
+ description = "Access key ID."
+ value = aws_iam_access_key.this.id
+ sensitive = true
+}
+
+output "key_secret" {
+ description = "Access secret access key."
+ value = aws_iam_access_key.this.ses_smtp_password_v4
+ sensitive = true
+}
diff --git a/modules/iam/smtp-user/variables.tf b/modules/iam/smtp-user/variables.tf
new file mode 100644
index 0000000..2b7ef4e
--- /dev/null
+++ b/modules/iam/smtp-user/variables.tf
@@ -0,0 +1,4 @@
+variable "name" {
+ type = string
+ description = "User name"
+}
\ No newline at end of file
diff --git a/modules/iam/smtp-user/versions.tf b/modules/iam/smtp-user/versions.tf
new file mode 100644
index 0000000..d50a6bd
--- /dev/null
+++ b/modules/iam/smtp-user/versions.tf
@@ -0,0 +1,10 @@
+terraform {
+ required_version = "~> 1.0"
+
+ required_providers {
+ aws = {
+ source = "hashicorp/aws"
+ version = "~> 5.0"
+ }
+ }
+}
diff --git a/templates/production/README.md b/templates/production/README.md
index b5e84c2..4e30e94 100644
--- a/templates/production/README.md
+++ b/templates/production/README.md
@@ -12,38 +12,54 @@
| Name | Version |
|------|---------|
| [aws](#provider\_aws) | 5.68.0 |
+| [aws.global](#provider\_aws.global) | 5.68.0 |
+| [random](#provider\_random) | 3.6.3 |
## Modules
| Name | Source | Version |
|------|--------|---------|
+| [app\_storage\_s3\_read\_write](#module\_app\_storage\_s3\_read\_write) | ../../modules/iam/s3-read-write | n/a |
+| [cert](#module\_cert) | ../../modules/acm-wildcard | n/a |
| [ci\_iam](#module\_ci\_iam) | ../../modules/iam/user-with-access-key | n/a |
| [cloudfront\_app](#module\_cloudfront\_app) | ../../modules/cloudfront-app | n/a |
| [cloudfront\_bucket\_policy](#module\_cloudfront\_bucket\_policy) | ../../modules/cloudfront-s3-origin-bucket-policy | n/a |
| [cloudfront\_deployment\_policy](#module\_cloudfront\_deployment\_policy) | ../../modules/cloudfront-deployment-policy | n/a |
+| [cloudfront\_dns](#module\_cloudfront\_dns) | ../../modules/route53/cloudfront-record | n/a |
| [cluster](#module\_cluster) | ../../modules/ecs-cluster | n/a |
| [database\_subnet](#module\_database\_subnet) | ../../modules/vpc-private-subnet | n/a |
| [db](#module\_db) | ../../modules/postgres | n/a |
| [ecr](#module\_ecr) | ../../modules/ecr-repository | n/a |
+| [iam\_app](#module\_iam\_app) | ../../modules/iam/user-with-access-key | n/a |
| [lb](#module\_lb) | ../../modules/lb/alb | n/a |
| [private\_subnet](#module\_private\_subnet) | ../../modules/vpc-private-subnet | n/a |
| [public\_subnet](#module\_public\_subnet) | ../../modules/vpc-public-subnet | n/a |
+| [secrets](#module\_secrets) | ../../modules/ssm/parameters | n/a |
| [secrets\_ci](#module\_secrets\_ci) | ../../modules/ssm/parameters | n/a |
-| [service](#module\_service) | ../../modules/ecs-service | n/a |
+| [service](#module\_service) | ../../modules/route53/load-balancer-record | n/a |
+| [ses](#module\_ses) | ../../modules/ses | n/a |
| [vpc](#module\_vpc) | ../../modules/vpc | n/a |
## Resources
| Name | Type |
|------|------|
+| [aws_alb_listener.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/alb_listener) | resource |
| [aws_iam_policy.ci_user](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |
+| [aws_iam_user_policy_attachment.allow_sending_email](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_user_policy_attachment) | resource |
| [aws_iam_user_policy_attachment.ci_user](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_user_policy_attachment) | resource |
+| [aws_lb_listener_rule.service](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lb_listener_rule) | resource |
+| [aws_s3_bucket.app_storage](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket) | resource |
| [aws_s3_bucket.apps_storage](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket) | resource |
+| [aws_s3_bucket.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket) | resource |
| [aws_s3_bucket_public_access_block.apps_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_public_access_block) | resource |
+| [aws_s3_bucket_public_access_block.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_public_access_block) | resource |
+| [random_id.example](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/id) | resource |
| [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source |
| [aws_iam_policy_document.ci_user](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
| [aws_region.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/region) | data source |
| [aws_route53_zone.domain](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/route53_zone) | data source |
+| [aws_route53_zone.name](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/route53_zone) | data source |
## Inputs
diff --git a/templates/production/acm.tf b/templates/production/acm.tf
new file mode 100644
index 0000000..461bf0a
--- /dev/null
+++ b/templates/production/acm.tf
@@ -0,0 +1,23 @@
+data "aws_route53_zone" "name" { # TODO adjust name to your project
+ provider = aws.global
+ name = "example.com" # TODO adjust name to your project
+}
+
+module "cert" {
+ providers = {
+ aws = aws.global
+ }
+
+ source = "../../modules/acm-wildcard"
+
+ domain = "example.com" # TODO adjust name to your project
+ validation_zone = "example.com" # TODO adjust name to your project
+ wildcard = true
+ validate = true
+
+ context = {
+ namespace = "name" # TODO adjust name to your project
+ stage = "production"
+ name = "acm"
+ }
+}
\ No newline at end of file
diff --git a/templates/production/ecr.tf b/templates/production/ecr.tf
index 40057a9..7d7a092 100644
--- a/templates/production/ecr.tf
+++ b/templates/production/ecr.tf
@@ -10,5 +10,4 @@ module "ecr" {
output "url" {
value = module.ecr.url
-
}
diff --git a/templates/production/ecs.tf b/templates/production/ecs.tf
index 59986a8..6ff1138 100644
--- a/templates/production/ecs.tf
+++ b/templates/production/ecs.tf
@@ -31,6 +31,8 @@ module "service" {
cluster_id = module.cluster.id
desired_count = 1
+ secrets = ["/name/production/service/terraform", "/name/production/service/editable"]
+
tcp_ports = [{
name = "http"
host = 0
@@ -43,3 +45,11 @@ module "service" {
name = "ecs"
}
}
+
+# TODO Optional variable to create SSM parameter for private key
+# resource "aws_ssm_parameter" "private_key" {
+# name = "/ecs/config/PRIVATE_KEY_PEM"
+# description = "Private key for EC2 instance"
+# type = "SecureString"
+# value = module.cluster.private_key_pem
+# }
\ No newline at end of file
diff --git a/templates/production/iam.tf b/templates/production/iam.tf
index e69de29..4412cb0 100644
--- a/templates/production/iam.tf
+++ b/templates/production/iam.tf
@@ -0,0 +1,10 @@
+module "iam_app" {
+ source = "../../modules/iam/user-with-access-key"
+
+ name = "name-production" # TODO adjust name to your project
+}
+
+resource "aws_iam_user_policy_attachment" "allow_sending_email" {
+ user = module.iam_app.name # TODO adjust name to your project
+ policy_arn = module.ses.send_email_policy_arn
+}
diff --git a/templates/production/networking.tf b/templates/production/networking.tf
index 875d2db..9c25e82 100644
--- a/templates/production/networking.tf
+++ b/templates/production/networking.tf
@@ -71,4 +71,45 @@ module "lb" {
force_https = true
context = local.context
+}
+
+resource "aws_alb_listener" "default" {
+ load_balancer_arn = module.lb.id
+ port = 443
+ protocol = "HTTPS"
+ certificate_arn = module.cert.arn
+ ssl_policy = "ELBSecurityPolicy-TLS-1-2-2017-01" # https://docs.aws.amazon.com/elasticloadbalancing/latest/application/create-https-listener.html
+
+ default_action {
+ type = "fixed-response"
+
+ fixed_response {
+ content_type = "text/plain"
+ message_body = "Hello there! Load balancer works."
+ status_code = "200"
+ }
+ }
+}
+
+
+resource "aws_lb_listener_rule" "service" {
+ listener_arn = aws_alb_listener.default.arn
+ priority = 60
+
+ action {
+ type = "forward"
+ target_group_arn = module.service.lb_target_group_id # TODO adjust name to your project
+ }
+
+ condition {
+ host_header {
+ values = ["api.example.com"] # TODO adjust name to your project
+ }
+ }
+
+ condition {
+ path_pattern {
+ values = ["/*"]
+ }
+ }
}
\ No newline at end of file
diff --git a/templates/production/rds.tf b/templates/production/rds.tf
index 6a0d41c..0347f39 100644
--- a/templates/production/rds.tf
+++ b/templates/production/rds.tf
@@ -23,5 +23,4 @@ module "db" {
parameter_group_family = "postgres16"
engine_version = "16.1"
instance_class = "db.t4g.small"
-
}
diff --git a/templates/production/route53.tf b/templates/production/route53.tf
index bddcff6..cc46d60 100644
--- a/templates/production/route53.tf
+++ b/templates/production/route53.tf
@@ -1,3 +1,19 @@
data "aws_route53_zone" "domain" {
name = "your-domain.com" # TODO adjust name to your project
+}
+
+module "cloudfront_dns" {
+ source = "../../modules/route53/cloudfront-record"
+
+ name = ""
+ zone_id = data.aws_route53_zone.example_com.zone_id # TODO adjust name to your project
+ distribution_id = module.cloudfront_app.id
+}
+
+module "service" {
+ source = "../../modules/route53/load-balancer-record"
+
+ lb_arn = module.lb.id
+ name = "service"
+ zone_id = data.aws_route53_zone.example_com.zone_id # TODO adjust name to your project
}
\ No newline at end of file
diff --git a/templates/production/s3.tf b/templates/production/s3.tf
new file mode 100644
index 0000000..1ce8d46
--- /dev/null
+++ b/templates/production/s3.tf
@@ -0,0 +1,29 @@
+resource "random_id" "example" {
+ byte_length = 4
+ prefix = "web-"
+}
+
+resource "aws_s3_bucket" "this" {
+ bucket = "apps-${random_id.example.hex}"
+}
+
+resource "aws_s3_bucket_public_access_block" "this" {
+ bucket = aws_s3_bucket.this.id
+
+ block_public_acls = true
+ block_public_policy = true
+ ignore_public_acls = true
+ restrict_public_buckets = true
+}
+
+resource "aws_s3_bucket" "app_storage" {
+ bucket = "production-name-app-storage" # TODO adjust name to your project
+}
+
+module "app_storage_s3_read_write" {
+ source = "../../modules/iam/s3-read-write"
+
+ name_prefix = "name-storage" # TODO adjust name to your project
+ bucket_arn = aws_s3_bucket.app_storage.arn
+ users = [module.iam_app.name] # TODO adjust name to your project
+}
diff --git a/templates/production/secrets.tf b/templates/production/secrets.tf
new file mode 100644
index 0000000..03741df
--- /dev/null
+++ b/templates/production/secrets.tf
@@ -0,0 +1,20 @@
+module "secrets" {
+ source = "../../modules/ssm/parameters"
+
+ context = {
+ namespace = "name" # TODO adjust name to your project
+ stage = "production"
+ name = "service" # TODO adjust name to your project
+ }
+
+ secrets = {
+ NODE_ENV = "production"
+ DATABASE_URL = module.db.url
+ AWS_REGION = var.region
+ }
+
+ editable_secrets = {
+ CORS_ORIGIN = "Edit in AWS Console"
+ ENVIRONMENT = "Edit in AWS Console"
+ }
+}
\ No newline at end of file
diff --git a/templates/production/ses.tf b/templates/production/ses.tf
new file mode 100644
index 0000000..86ccdd3
--- /dev/null
+++ b/templates/production/ses.tf
@@ -0,0 +1,13 @@
+module "ses" {
+ source = "../../modules/ses"
+
+ name_prefix = "name-production" # TODO adjust name to your project
+ domain_name = "example.com"
+ zone_id = data.aws_route53_zone.example_com.id # TODO adjust name to your project
+ verify_dkim = true
+ dmarc_enabled = true
+ spf_enabled = true
+ email_addresses = [
+ "your.name@example.com" # TODO adjust name to your project
+ ]
+}
diff --git a/templates/production/versions.tf b/templates/production/versions.tf
index cbdeb05..b95610f 100644
--- a/templates/production/versions.tf
+++ b/templates/production/versions.tf
@@ -1,13 +1,13 @@
terraform {
required_version = "~> 1.0"
- # cloud {
- # organization = "organization" # TODO adjust name to your project
-
- # workspaces {
- # name = "workspace" # TODO adjust name to your project
- # }
- # }
+ backend "s3" {
+ key = "production/terraform.tfstate"
+ bucket = "name-production-tf-state" # TODO adjust name to your project
+ region = var.region
+ encrypt = true
+ use_lockfile = true
+ }
required_providers {
aws = {
diff --git a/templates/staging/README.md b/templates/staging/README.md
index 00f1411..463c324 100644
--- a/templates/staging/README.md
+++ b/templates/staging/README.md
@@ -12,38 +12,53 @@
| Name | Version |
|------|---------|
| [aws](#provider\_aws) | ~> 5.0 |
+| [aws.global](#provider\_aws.global) | ~> 5.0 |
+| [random](#provider\_random) | ~> 3.0 |
## Modules
| Name | Source | Version |
|------|--------|---------|
+| [app\_storage\_s3\_read\_write](#module\_app\_storage\_s3\_read\_write) | ../../modules/iam/s3-read-write | n/a |
+| [cert](#module\_cert) | ../../modules/acm-wildcard | n/a |
| [ci\_iam](#module\_ci\_iam) | ../../modules/iam/user-with-access-key | n/a |
| [cloudfront\_app](#module\_cloudfront\_app) | ../../modules/cloudfront-app | n/a |
| [cloudfront\_bucket\_policy](#module\_cloudfront\_bucket\_policy) | ../../modules/cloudfront-s3-origin-bucket-policy | n/a |
| [cloudfront\_deployment\_policy](#module\_cloudfront\_deployment\_policy) | ../../modules/cloudfront-deployment-policy | n/a |
+| [cloudfront\_dns](#module\_cloudfront\_dns) | ../../modules/route53/cloudfront-record | n/a |
| [cluster](#module\_cluster) | ../../modules/ecs-cluster | n/a |
| [database\_subnet](#module\_database\_subnet) | ../../modules/vpc-private-subnet | n/a |
| [db](#module\_db) | ../../modules/postgres | n/a |
| [ecr](#module\_ecr) | ../../modules/ecr-repository | n/a |
+| [iam\_app](#module\_iam\_app) | ../../modules/iam/user-with-access-key | n/a |
| [lb](#module\_lb) | ../../modules/lb/alb | n/a |
| [private\_subnet](#module\_private\_subnet) | ../../modules/vpc-private-subnet | n/a |
| [public\_subnet](#module\_public\_subnet) | ../../modules/vpc-public-subnet | n/a |
+| [secrets](#module\_secrets) | ../../modules/ssm/parameters | n/a |
| [secrets\_ci](#module\_secrets\_ci) | ../../modules/ssm/parameters | n/a |
-| [service](#module\_service) | ../../modules/ecs-service | n/a |
+| [service](#module\_service) | ../../modules/route53/load-balancer-record | n/a |
+| [ses](#module\_ses) | ../../modules/ses | n/a |
| [vpc](#module\_vpc) | ../../modules/vpc | n/a |
## Resources
| Name | Type |
|------|------|
+| [aws_alb_listener.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/alb_listener) | resource |
| [aws_iam_policy.ci_user](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource |
+| [aws_iam_user_policy_attachment.allow_sending_email](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_user_policy_attachment) | resource |
| [aws_iam_user_policy_attachment.ci_user](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_user_policy_attachment) | resource |
+| [aws_lb_listener_rule.service](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lb_listener_rule) | resource |
+| [aws_s3_bucket.app_storage](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket) | resource |
| [aws_s3_bucket.apps_storage](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket) | resource |
+| [aws_s3_bucket.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket) | resource |
| [aws_s3_bucket_public_access_block.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_public_access_block) | resource |
+| [random_id.example](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/id) | resource |
| [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source |
| [aws_iam_policy_document.ci_user](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
| [aws_region.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/region) | data source |
| [aws_route53_zone.domain](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/route53_zone) | data source |
+| [aws_route53_zone.name](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/route53_zone) | data source |
## Inputs
diff --git a/templates/staging/acm.tf b/templates/staging/acm.tf
new file mode 100644
index 0000000..0978f28
--- /dev/null
+++ b/templates/staging/acm.tf
@@ -0,0 +1,23 @@
+data "aws_route53_zone" "name" { # TODO adjust name to your project
+ provider = aws.global
+ name = "example.com" # TODO adjust name to your project
+}
+
+module "cert" {
+ providers = {
+ aws = aws.global
+ }
+
+ source = "../../modules/acm-wildcard"
+
+ domain = "example.com" # TODO adjust name to your project
+ validation_zone = "example.com" # TODO adjust name to your project
+ wildcard = true
+ validate = true
+
+ context = {
+ namespace = "name" # TODO adjust name to your project
+ stage = "staging"
+ name = "acm"
+ }
+}
\ No newline at end of file
diff --git a/templates/staging/ecr.tf b/templates/staging/ecr.tf
index 40057a9..a0c6773 100644
--- a/templates/staging/ecr.tf
+++ b/templates/staging/ecr.tf
@@ -3,12 +3,11 @@ module "ecr" {
context = {
namespace = "name" # TODO adjust name to your project
- stage = "production"
+ stage = "staging"
name = "api"
}
}
output "url" {
value = module.ecr.url
-
}
diff --git a/templates/staging/ecs.tf b/templates/staging/ecs.tf
index 479997b..2f8872b 100644
--- a/templates/staging/ecs.tf
+++ b/templates/staging/ecs.tf
@@ -31,6 +31,8 @@ module "service" {
cluster_id = module.cluster.id
desired_count = 1
+ secrets = ["/name/staging/service/terraform", "/name/staging/service/editable"]
+
tcp_ports = [{
name = "http"
host = 0
@@ -43,3 +45,11 @@ module "service" {
name = "ecs"
}
}
+
+# TODO Optional variable to create SSM parameter for private key
+# resource "aws_ssm_parameter" "private_key" {
+# name = "/ecs/config/PRIVATE_KEY_PEM"
+# description = "Private key for EC2 instance"
+# type = "SecureString"
+# value = module.cluster.private_key_pem
+# }
\ No newline at end of file
diff --git a/templates/staging/iam.tf b/templates/staging/iam.tf
index e69de29..2b7d230 100644
--- a/templates/staging/iam.tf
+++ b/templates/staging/iam.tf
@@ -0,0 +1,10 @@
+module "iam_app" {
+ source = "../../modules/iam/user-with-access-key"
+
+ name = "name-staging" # TODO adjust name to your project
+}
+
+resource "aws_iam_user_policy_attachment" "allow_sending_email" {
+ user = module.iam_app.name # TODO adjust name to your project
+ policy_arn = module.ses.send_email_policy_arn
+}
diff --git a/templates/staging/networking.tf b/templates/staging/networking.tf
index 482b29f..bb47c3d 100644
--- a/templates/staging/networking.tf
+++ b/templates/staging/networking.tf
@@ -71,4 +71,45 @@ module "lb" {
force_https = true
context = local.context
+}
+
+resource "aws_alb_listener" "default" {
+ load_balancer_arn = module.lb.id
+ port = 443
+ protocol = "HTTPS"
+ certificate_arn = module.cert.arn
+ ssl_policy = "ELBSecurityPolicy-TLS-1-2-2017-01" # https://docs.aws.amazon.com/elasticloadbalancing/latest/application/create-https-listener.html
+
+ default_action {
+ type = "fixed-response"
+
+ fixed_response {
+ content_type = "text/plain"
+ message_body = "Hello there! Load balancer works."
+ status_code = "200"
+ }
+ }
+}
+
+
+resource "aws_lb_listener_rule" "service" {
+ listener_arn = aws_alb_listener.default.arn
+ priority = 60
+
+ action {
+ type = "forward"
+ target_group_arn = module.service.lb_target_group_id # TODO adjust name to your project
+ }
+
+ condition {
+ host_header {
+ values = ["api.example.com"] # TODO adjust name to your project
+ }
+ }
+
+ condition {
+ path_pattern {
+ values = ["/*"]
+ }
+ }
}
\ No newline at end of file
diff --git a/templates/staging/route53.tf b/templates/staging/route53.tf
index 305f220..635430f 100644
--- a/templates/staging/route53.tf
+++ b/templates/staging/route53.tf
@@ -1,3 +1,19 @@
data "aws_route53_zone" "domain" {
name = "staging.your-domain.com" # TODO adjust name to your project
+}
+
+module "cloudfront_dns" {
+ source = "../../modules/route53/cloudfront-record"
+
+ name = ""
+ zone_id = data.aws_route53_zone.example_com.zone_id # TODO adjust name to your project
+ distribution_id = module.cloudfront_app.id
+}
+
+module "service" {
+ source = "../../modules/route53/load-balancer-record"
+
+ lb_arn = module.lb.id
+ name = "service"
+ zone_id = data.aws_route53_zone.example_com.zone_id # TODO adjust name to your project
}
\ No newline at end of file
diff --git a/templates/staging/s3.tf b/templates/staging/s3.tf
new file mode 100644
index 0000000..0189e8b
--- /dev/null
+++ b/templates/staging/s3.tf
@@ -0,0 +1,29 @@
+resource "random_id" "example" {
+ byte_length = 4
+ prefix = "web-"
+}
+
+resource "aws_s3_bucket" "this" {
+ bucket = "apps-${random_id.example.hex}"
+}
+
+resource "aws_s3_bucket_public_access_block" "this" {
+ bucket = aws_s3_bucket.this.id
+
+ block_public_acls = true
+ block_public_policy = true
+ ignore_public_acls = true
+ restrict_public_buckets = true
+}
+
+resource "aws_s3_bucket" "app_storage" {
+ bucket = "staging-name-app-storage" # TODO adjust name to your project
+}
+
+module "app_storage_s3_read_write" {
+ source = "../../modules/iam/s3-read-write"
+
+ name_prefix = "name-storage" # TODO adjust name to your project
+ bucket_arn = aws_s3_bucket.app_storage.arn
+ users = [module.iam_app.name] # TODO adjust name to your project
+}
diff --git a/templates/staging/secrets.tf b/templates/staging/secrets.tf
new file mode 100644
index 0000000..898a5b2
--- /dev/null
+++ b/templates/staging/secrets.tf
@@ -0,0 +1,20 @@
+module "secrets" {
+ source = "../../modules/ssm/parameters"
+
+ context = {
+ namespace = "name" # TODO adjust name to your project
+ stage = "staging"
+ name = "service" # TODO adjust name to your project
+ }
+
+ secrets = {
+ NODE_ENV = "staging"
+ DATABASE_URL = module.db.url
+ AWS_REGION = var.region
+ }
+
+ editable_secrets = {
+ CORS_ORIGIN = "Edit in AWS Console"
+ ENVIRONMENT = "Edit in AWS Console"
+ }
+}
\ No newline at end of file
diff --git a/templates/staging/ses.tf b/templates/staging/ses.tf
new file mode 100644
index 0000000..b4c2e9d
--- /dev/null
+++ b/templates/staging/ses.tf
@@ -0,0 +1,13 @@
+module "ses" {
+ source = "../../modules/ses"
+
+ name_prefix = "name-staging" # TODO adjust name to your project
+ domain_name = "example.com"
+ zone_id = data.aws_route53_zone.example_com.id # TODO adjust name to your project
+ verify_dkim = true
+ dmarc_enabled = true
+ spf_enabled = true
+ email_addresses = [
+ "your.name@example.com" # TODO adjust name to your project
+ ]
+}
diff --git a/templates/staging/versions.tf b/templates/staging/versions.tf
index cbdeb05..729b871 100644
--- a/templates/staging/versions.tf
+++ b/templates/staging/versions.tf
@@ -1,13 +1,13 @@
terraform {
required_version = "~> 1.0"
- # cloud {
- # organization = "organization" # TODO adjust name to your project
-
- # workspaces {
- # name = "workspace" # TODO adjust name to your project
- # }
- # }
+ backend "s3" {
+ key = "staging/terraform.tfstate"
+ bucket = "name-staging-tf-state" # TODO adjust name to your project
+ region = var.region
+ encrypt = true
+ use_lockfile = true
+ }
required_providers {
aws = {