├── modules ├── aws-vpc │ ├── .envrc │ ├── examples │ │ ├── full │ │ │ ├── .tflint.hcl │ │ │ ├── .envrc │ │ │ ├── versions.tf │ │ │ └── main.tf │ │ ├── ipam │ │ │ ├── .tflint.hcl │ │ │ └── main.tf │ │ └── simple │ │ │ ├── .tflint.hcl │ │ │ ├── .envrc │ │ │ ├── versions.tf │ │ │ └── main.tf │ ├── Makefile │ ├── outputs.tf │ ├── versions.tf │ ├── test │ │ ├── integration_test.go │ │ └── go.mod │ ├── variables.tf │ ├── go.mod │ ├── main.tf │ └── README.md ├── aws-ec2-asg │ ├── .envrc │ ├── examples │ │ └── simple │ │ │ ├── .tflint.hcl │ │ │ ├── .envrc │ │ │ ├── user_data.sh │ │ │ └── main.tf │ ├── test │ │ ├── go.mod │ │ └── integration_test.go │ ├── Makefile │ ├── versions.tf │ ├── outputs.tf │ ├── cloudwatch-config.tftpl │ ├── variables.tf │ ├── main.tf │ └── README.md ├── aws-https-alb │ ├── .envrc │ ├── examples │ │ └── simple │ │ │ ├── .tflint.hcl │ │ │ ├── .envrc │ │ │ └── main.tf │ ├── test │ │ ├── go.mod │ │ └── integration_test.go │ ├── Makefile │ ├── outputs.tf │ ├── versions.tf │ ├── waf.tf │ ├── variables.tf │ ├── main.tf │ └── README.md ├── aws-s3-bucket │ ├── .envrc │ ├── examples │ │ └── simple │ │ │ ├── .tflint.hcl │ │ │ ├── .envrc │ │ │ └── main.tf │ ├── Makefile │ ├── outputs.tf │ ├── versions.tf │ ├── test │ │ ├── integration_test.go │ │ └── go.mod │ ├── main.tf │ ├── variables.tf │ └── README.md ├── aws-ipam │ ├── examples │ │ └── simple │ │ │ ├── .tflint.hcl │ │ │ └── main.tf │ ├── Makefile │ ├── outputs.tf │ ├── versions.tf │ ├── test │ │ ├── integration_test.go │ │ └── go.mod │ ├── variables.tf │ ├── main.tf │ └── README.md ├── aws-tgw │ ├── examples │ │ └── simple │ │ │ ├── .tflint.hcl │ │ │ ├── versions.tf │ │ │ └── main.tf │ ├── outputs.tf │ ├── Makefile │ ├── versions.tf │ ├── test │ │ ├── integration_test.go │ │ └── go.mod │ ├── variables.tf │ ├── main.tf │ └── README.md ├── aws-ecs-cluster │ ├── examples │ │ └── simple │ │ │ ├── .tflint.hcl │ │ │ ├── user_data.sh.tftpl │ │ │ └── main.tf │ ├── Makefile │ ├── outputs.tf │ ├── versions.tf │ ├── test │ │ ├── integration_test.go │ │ └── go.mod │ ├── variables.tf │ ├── main.tf │ └── README.md ├── bananalab-platform │ ├── examples │ │ └── simple │ │ │ ├── .tflint.hcl │ │ │ ├── boot_script.sh.tftpl │ │ │ └── main.tf │ ├── Makefile │ ├── versions.tf │ ├── test │ │ ├── integration_test.go │ │ └── go.mod │ ├── outputs.tf │ ├── variables.tf │ ├── main.tf │ └── README.md └── bananalab-ecs-service │ ├── examples │ └── simple │ │ ├── .tflint.hcl │ │ ├── userdata.sh.tftpl │ │ ├── container-definitions.json │ │ └── main.tf │ ├── Makefile │ ├── versions.tf │ ├── test │ ├── integration_test.go │ └── go.mod │ ├── outputs.tf │ ├── variables.tf │ ├── main.tf │ └── README.md ├── .template ├── .envrc ├── examples │ └── simple │ │ ├── .envrc │ │ └── main.tf ├── Makefile ├── main.tf ├── outputs.tf ├── variables.tf ├── versions.tf └── test │ └── integration_test.go ├── .envrc ├── CHANGELOG.md ├── .github └── workflows │ ├── release-please.yaml │ └── terratest.yaml ├── .terraform-docs.yaml ├── .devcontainer └── devcontainer.json ├── .pre-commit-config.yaml ├── .gitignore ├── Makefile └── README.md /modules/aws-vpc/.envrc: -------------------------------------------------------------------------------- 1 | source_up 2 | 3 | export MODULE_NAME="aws-vpc" 4 | -------------------------------------------------------------------------------- /.template/.envrc: -------------------------------------------------------------------------------- 1 | source_up 2 | 3 | export MODULE_NAME="{{ .Env.MODULENAME }}" 4 | -------------------------------------------------------------------------------- /modules/aws-ec2-asg/.envrc: -------------------------------------------------------------------------------- 1 | source_up 2 | 3 | export MODULE_NAME="aws-ec2-asg" 4 | -------------------------------------------------------------------------------- /modules/aws-https-alb/.envrc: -------------------------------------------------------------------------------- 1 | source_up 2 | 3 | export MODULE_NAME="aws-https-alb" 4 | -------------------------------------------------------------------------------- /modules/aws-s3-bucket/.envrc: -------------------------------------------------------------------------------- 1 | source_up 2 | 3 | export MODULE_NAME="aws-s3-bucket" 4 | -------------------------------------------------------------------------------- /modules/aws-vpc/examples/full/.tflint.hcl: -------------------------------------------------------------------------------- 1 | config { 2 | disabled_by_default = true 3 | } 4 | -------------------------------------------------------------------------------- /modules/aws-vpc/examples/ipam/.tflint.hcl: -------------------------------------------------------------------------------- 1 | config { 2 | disabled_by_default = true 3 | } 4 | -------------------------------------------------------------------------------- /modules/aws-ipam/examples/simple/.tflint.hcl: -------------------------------------------------------------------------------- 1 | config { 2 | disabled_by_default = true 3 | } 4 | -------------------------------------------------------------------------------- /modules/aws-tgw/examples/simple/.tflint.hcl: -------------------------------------------------------------------------------- 1 | config { 2 | disabled_by_default = true 3 | } 4 | -------------------------------------------------------------------------------- /modules/aws-vpc/examples/simple/.tflint.hcl: -------------------------------------------------------------------------------- 1 | config { 2 | disabled_by_default = true 3 | } 4 | -------------------------------------------------------------------------------- /modules/aws-ec2-asg/examples/simple/.tflint.hcl: -------------------------------------------------------------------------------- 1 | config { 2 | disabled_by_default = true 3 | } 4 | -------------------------------------------------------------------------------- /modules/aws-ecs-cluster/examples/simple/.tflint.hcl: -------------------------------------------------------------------------------- 1 | config { 2 | disabled_by_default = true 3 | } 4 | -------------------------------------------------------------------------------- /modules/aws-https-alb/examples/simple/.tflint.hcl: -------------------------------------------------------------------------------- 1 | config { 2 | disabled_by_default = true 3 | } 4 | -------------------------------------------------------------------------------- /modules/aws-s3-bucket/examples/simple/.tflint.hcl: -------------------------------------------------------------------------------- 1 | config { 2 | disabled_by_default = true 3 | } 4 | -------------------------------------------------------------------------------- /modules/bananalab-platform/examples/simple/.tflint.hcl: -------------------------------------------------------------------------------- 1 | config { 2 | disabled_by_default = true 3 | } 4 | -------------------------------------------------------------------------------- /modules/bananalab-ecs-service/examples/simple/.tflint.hcl: -------------------------------------------------------------------------------- 1 | config { 2 | disabled_by_default = true 3 | } 4 | -------------------------------------------------------------------------------- /modules/aws-ec2-asg/test/go.mod: -------------------------------------------------------------------------------- 1 | module aws-ec2-asg 2 | 3 | go 1.15 4 | 5 | require github.com/gruntwork-io/terratest v0.41.11 6 | -------------------------------------------------------------------------------- /modules/aws-https-alb/test/go.mod: -------------------------------------------------------------------------------- 1 | module aws-https-alb 2 | 3 | go 1.15 4 | 5 | require github.com/gruntwork-io/terratest v0.41.11 6 | -------------------------------------------------------------------------------- /.envrc: -------------------------------------------------------------------------------- 1 | if ! has pre-commit; then 2 | log_status 'Warning: pre-commit not found. Hooks will not run.' 3 | else 4 | pre-commit install 5 | fi 6 | -------------------------------------------------------------------------------- /modules/bananalab-platform/examples/simple/boot_script.sh.tftpl: -------------------------------------------------------------------------------- 1 | 2 | #!/bin/bash -uex 3 | # Any additional instance configuration goes here. 4 | echo 'Done.' 5 | -------------------------------------------------------------------------------- /.template/examples/simple/.envrc: -------------------------------------------------------------------------------- 1 | source_up 2 | 3 | # You can set variables used by your sample code here. 4 | # Example: 5 | # export TF_VAR_name="test-value" 6 | -------------------------------------------------------------------------------- /modules/aws-vpc/examples/full/.envrc: -------------------------------------------------------------------------------- 1 | source_up 2 | 3 | # You can set variables used by your sample code here. 4 | # Example: 5 | # export TF_VAR_name="test-value" 6 | -------------------------------------------------------------------------------- /modules/aws-vpc/examples/simple/.envrc: -------------------------------------------------------------------------------- 1 | source_up 2 | 3 | # You can set variables used by your sample code here. 4 | # Example: 5 | # export TF_VAR_name="test-value" 6 | -------------------------------------------------------------------------------- /modules/aws-ec2-asg/examples/simple/.envrc: -------------------------------------------------------------------------------- 1 | source_up 2 | 3 | # You can set variables used by your sample code here. 4 | # Example: 5 | # export TF_VAR_name="test-value" 6 | -------------------------------------------------------------------------------- /modules/aws-https-alb/examples/simple/.envrc: -------------------------------------------------------------------------------- 1 | source_up 2 | 3 | # You can set variables used by your sample code here. 4 | # Example: 5 | # export TF_VAR_name="test-value" 6 | -------------------------------------------------------------------------------- /modules/aws-s3-bucket/examples/simple/.envrc: -------------------------------------------------------------------------------- 1 | source_up 2 | 3 | # You can set variables used by your sample code here. 4 | # Example: 5 | # export TF_VAR_name="test-value" 6 | -------------------------------------------------------------------------------- /modules/aws-ec2-asg/examples/simple/user_data.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | yum update -y 3 | amazon-linux-extras enable nginx1 4 | yum install -y \ 5 | nginx \ 6 | amazon-cloudwatch-agent 7 | chkconfig nginx on 8 | -------------------------------------------------------------------------------- /modules/aws-tgw/outputs.tf: -------------------------------------------------------------------------------- 1 | output "result" { 2 | description = <<-EOT 3 | The result of the module. 4 | EOT 5 | value = { 6 | transit_gateway = aws_ec2_transit_gateway.this 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /modules/aws-ecs-cluster/examples/simple/user_data.sh.tftpl: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | yum update -y 3 | amazon-linux-extras enable nginx1 4 | yum install -y \ 5 | nginx \ 6 | amazon-cloudwatch-agent 7 | chkconfig nginx on 8 | -------------------------------------------------------------------------------- /modules/aws-ipam/Makefile: -------------------------------------------------------------------------------- 1 | SHELL := $(shell which bash) 2 | .PHONY: test 3 | 4 | test: 5 | pushd test; \ 6 | go mod init "aws-ipam"; \ 7 | go mod tidy; \ 8 | go test -v -tags integration -timeout 3600s; \ 9 | popd 10 | -------------------------------------------------------------------------------- /modules/aws-tgw/Makefile: -------------------------------------------------------------------------------- 1 | SHELL := $(shell which bash) 2 | .PHONY: test 3 | 4 | test: 5 | pushd test; \ 6 | go mod init "aws-tgw"; \ 7 | go mod tidy; \ 8 | go test -v -tags integration -timeout 3600s; \ 9 | popd 10 | -------------------------------------------------------------------------------- /modules/aws-vpc/Makefile: -------------------------------------------------------------------------------- 1 | SHELL := $(shell which bash) 2 | .PHONY: test 3 | 4 | test: 5 | pushd test; \ 6 | go mod init "aws-vpc"; \ 7 | go mod tidy; \ 8 | go test -v -tags integration -timeout 3600s; \ 9 | popd 10 | -------------------------------------------------------------------------------- /modules/aws-vpc/examples/full/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | aws = { 4 | source = "hashicorp/aws" 5 | version = "~>5.0" 6 | } 7 | } 8 | required_version = "~>1.5" 9 | } 10 | -------------------------------------------------------------------------------- /modules/aws-vpc/examples/simple/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | aws = { 4 | source = "hashicorp/aws" 5 | version = "~>5.0" 6 | } 7 | } 8 | required_version = "~>1.5" 9 | } 10 | -------------------------------------------------------------------------------- /.template/Makefile: -------------------------------------------------------------------------------- 1 | SHELL := $(shell which bash) 2 | .PHONY: test 3 | 4 | test: 5 | pushd test; \ 6 | go mod init "{{ .Env.MODULENAME }}"; \ 7 | go mod tidy; \ 8 | go test -v -tags integration -timeout 3600s; \ 9 | popd 10 | -------------------------------------------------------------------------------- /modules/aws-ec2-asg/Makefile: -------------------------------------------------------------------------------- 1 | SHELL := $(shell which bash) 2 | .PHONY: test 3 | 4 | test: 5 | pushd test; \ 6 | go mod init "aws-ec2-asg"; \ 7 | go mod tidy; \ 8 | go test -v -tags integration -timeout 3600s; \ 9 | popd 10 | -------------------------------------------------------------------------------- /modules/aws-https-alb/Makefile: -------------------------------------------------------------------------------- 1 | SHELL := $(shell which bash) 2 | .PHONY: test 3 | 4 | test: 5 | pushd test; \ 6 | go mod init "aws-https-alb"; \ 7 | go mod tidy; \ 8 | go test -v -tags integration -timeout 3600s; \ 9 | popd 10 | -------------------------------------------------------------------------------- /modules/aws-s3-bucket/Makefile: -------------------------------------------------------------------------------- 1 | SHELL := $(shell which bash) 2 | .PHONY: test 3 | 4 | test: 5 | pushd test; \ 6 | go mod init "aws-s3-bucket"; \ 7 | go mod tidy; \ 8 | go test -v -tags integration -timeout 3600s; \ 9 | popd 10 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## 0.1.0 (2024-07-25) 4 | 5 | 6 | ### Bug Fixes 7 | 8 | * Loosen module name restriction. ([0236a74](https://github.com/bananalab/terraform-modules-template/commit/0236a74b0bcf5459d9d71b3dc042b2f47f3cc5bd)) 9 | -------------------------------------------------------------------------------- /modules/aws-ecs-cluster/Makefile: -------------------------------------------------------------------------------- 1 | SHELL := $(shell which bash) 2 | .PHONY: test 3 | 4 | test: 5 | pushd test; \ 6 | go mod init "aws-ecs-cluster"; \ 7 | go mod tidy; \ 8 | go test -v -tags integration -timeout 3600s; \ 9 | popd 10 | -------------------------------------------------------------------------------- /modules/bananalab-platform/Makefile: -------------------------------------------------------------------------------- 1 | SHELL := $(shell which bash) 2 | .PHONY: test 3 | 4 | test: 5 | pushd test; \ 6 | go mod init "bananalab-platform"; \ 7 | go mod tidy; \ 8 | go test -v -tags integration -timeout 3600s; \ 9 | popd 10 | -------------------------------------------------------------------------------- /modules/bananalab-ecs-service/Makefile: -------------------------------------------------------------------------------- 1 | SHELL := $(shell which bash) 2 | .PHONY: test 3 | 4 | test: 5 | pushd test; \ 6 | go mod init "empire-ecs-service"; \ 7 | go mod tidy; \ 8 | go test -v -tags integration -timeout 3600s; \ 9 | popd 10 | -------------------------------------------------------------------------------- /.template/main.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * 5 | */ 6 | 7 | resource "random_pet" "this" { 8 | keepers = { 9 | time = timestamp() 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /modules/aws-ec2-asg/versions.tf: -------------------------------------------------------------------------------- 1 | 2 | terraform { 3 | required_version = "~>1.5" 4 | required_providers { 5 | aws = { 6 | source = "hashicorp/aws" 7 | version = "~>5.0" 8 | } 9 | random = { 10 | source = "hashicorp/random" 11 | version = "~>3.0" 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /.template/outputs.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * 5 | */ 6 | 7 | output "result" { 8 | description = <<-EOT 9 | The result of the module. 10 | EOT 11 | value = random_pet.this 12 | } 13 | -------------------------------------------------------------------------------- /.template/variables.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * 5 | */ 6 | 7 | variable "input" { 8 | type = string 9 | description = <<-EOT 10 | This variable is not used. 11 | EOT 12 | default = null 13 | } 14 | -------------------------------------------------------------------------------- /modules/aws-s3-bucket/outputs.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * 5 | */ 6 | 7 | output "result" { 8 | description = <<-EOT 9 | The result of the module. 10 | EOT 11 | value = { 12 | bucket = aws_s3_bucket.this 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /modules/aws-ec2-asg/outputs.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * 5 | */ 6 | 7 | output "result" { 8 | description = <<-EOT 9 | The result of the module. 10 | EOT 11 | value = { 12 | autoscaling_group = aws_autoscaling_group.this 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /.github/workflows/release-please.yaml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: 4 | - main 5 | name: release-please 6 | jobs: 7 | release-please: 8 | if: ${{ true }} # Set this to false to disable releases. 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: google-github-actions/release-please-action@v3 12 | with: 13 | release-type: terraform-module 14 | -------------------------------------------------------------------------------- /modules/aws-vpc/outputs.tf: -------------------------------------------------------------------------------- 1 | output "result" { 2 | description = <<-EOT 3 | The result of the module. 4 | EOT 5 | value = { 6 | vpc = aws_vpc.this 7 | public_subnets = aws_subnet.public 8 | private_subnets = aws_subnet.private 9 | public_route_table = try(aws_route_table.public[0], null) 10 | private_route_tables = aws_route_table.private 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /modules/aws-ecs-cluster/outputs.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * 5 | */ 6 | 7 | output "result" { 8 | description = <<-EOT 9 | The result of the module. 10 | EOT 11 | value = { 12 | cluster = aws_ecs_cluster.this 13 | capacity_provider = aws_ecs_capacity_provider.this 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /modules/aws-ipam/outputs.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * 5 | */ 6 | 7 | output "result" { 8 | description = <<-EOT 9 | The result of the module. 10 | EOT 11 | value = { 12 | ipam = aws_vpc_ipam.this 13 | pool = aws_vpc_ipam_pool.this 14 | cidr = aws_vpc_ipam_pool_cidr.this 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /.template/versions.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * 6 | */ 7 | 8 | terraform { 9 | required_providers { 10 | random = { 11 | source = "hashicorp/random" 12 | version = "~>3" 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /.terraform-docs.yaml: -------------------------------------------------------------------------------- 1 | formatter: "markdown" 2 | 3 | sort: 4 | enabled: true 5 | by: required 6 | 7 | content: |- 8 | 9 | {{ .Header }} 10 | 11 | ## Example 12 | 13 | ```hcl 14 | {{ include "examples/simple/main.tf" }} 15 | ``` 16 | 17 | 18 | {{ .Modules }} 19 | 20 | {{ .Providers }} 21 | 22 | {{ .Requirements }} 23 | 24 | {{ .Resources }} 25 | 26 | {{ .Inputs }} 27 | 28 | {{ .Outputs }} 29 | 30 | {{ .Footer }} 31 | -------------------------------------------------------------------------------- /modules/aws-ipam/versions.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * 6 | */ 7 | 8 | terraform { 9 | required_version = "~>1.5" 10 | required_providers { 11 | aws = { 12 | source = "hashicorp/aws" 13 | version = "~>5.0" 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /modules/aws-tgw/versions.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * 6 | */ 7 | 8 | terraform { 9 | required_version = "~>1.5" 10 | required_providers { 11 | aws = { 12 | source = "hashicorp/aws" 13 | version = "~>5.0" 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /modules/aws-vpc/versions.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * 6 | */ 7 | 8 | terraform { 9 | required_providers { 10 | aws = { 11 | source = "hashicorp/aws" 12 | version = "~>5.0" 13 | } 14 | } 15 | required_version = "~>1.5" 16 | } 17 | -------------------------------------------------------------------------------- /.template/test/integration_test.go: -------------------------------------------------------------------------------- 1 | //go:build integration 2 | 3 | package test 4 | 5 | import ( 6 | "testing" 7 | 8 | "github.com/gruntwork-io/terratest/modules/terraform" 9 | ) 10 | 11 | func TestTerraformSimpleExample(t *testing.T) { 12 | terraformOptions := terraform.WithDefaultRetryableErrors(t, &terraform.Options{ 13 | TerraformDir: "../examples/simple", 14 | }) 15 | 16 | defer terraform.Destroy(t, terraformOptions) 17 | 18 | terraform.InitAndApply(t, terraformOptions) 19 | } 20 | -------------------------------------------------------------------------------- /modules/aws-ecs-cluster/versions.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * 6 | */ 7 | 8 | terraform { 9 | required_version = "~>1.5" 10 | required_providers { 11 | aws = { 12 | source = "hashicorp/aws" 13 | version = "~>5.0" 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /modules/aws-s3-bucket/versions.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * 6 | */ 7 | 8 | terraform { 9 | required_providers { 10 | aws = { 11 | source = "hashicorp/aws" 12 | version = "~>5.0" 13 | } 14 | } 15 | required_version = ">= 1.3.0" 16 | } 17 | -------------------------------------------------------------------------------- /modules/bananalab-ecs-service/examples/simple/userdata.sh.tftpl: -------------------------------------------------------------------------------- 1 | 2 | #!/bin/bash -uex 3 | docker plugin install rexray/s3fs:latest --grant-all-permissions \ 4 | # TODO: Use IAM role for S3fs 5 | S3FS_ACCESSKEY=xxxxx \ 6 | S3FS_SECRETKEY=xxxxx \ 7 | S3FS_OPTIONS="allow_other,umask=000" \ 8 | LIBSTORAGE_INTEGRATION_VOLUME_OPERATIONS_MOUNT_ROOTPATH=/ 9 | cat <<'EOF' >> /etc/ecs/ecs.config 10 | ECS_CLUSTER=${name} 11 | ECS_ENABLE_TASK_IAM_ROLE=true 12 | EOF 13 | echo 'Done.' 14 | -------------------------------------------------------------------------------- /modules/aws-ec2-asg/test/integration_test.go: -------------------------------------------------------------------------------- 1 | //go:build integration 2 | 3 | package test 4 | 5 | import ( 6 | "testing" 7 | 8 | "github.com/gruntwork-io/terratest/modules/terraform" 9 | ) 10 | 11 | func TestTerraformSimpleExample(t *testing.T) { 12 | terraformOptions := terraform.WithDefaultRetryableErrors(t, &terraform.Options{ 13 | TerraformDir: "../examples/simple", 14 | }) 15 | 16 | defer terraform.Destroy(t, terraformOptions) 17 | 18 | terraform.InitAndApply(t, terraformOptions) 19 | } 20 | -------------------------------------------------------------------------------- /modules/aws-ipam/test/integration_test.go: -------------------------------------------------------------------------------- 1 | //go:build integration 2 | 3 | package test 4 | 5 | import ( 6 | "testing" 7 | 8 | "github.com/gruntwork-io/terratest/modules/terraform" 9 | ) 10 | 11 | func TestTerraformSimpleExample(t *testing.T) { 12 | terraformOptions := terraform.WithDefaultRetryableErrors(t, &terraform.Options{ 13 | TerraformDir: "../examples/simple", 14 | }) 15 | 16 | defer terraform.Destroy(t, terraformOptions) 17 | 18 | terraform.InitAndApply(t, terraformOptions) 19 | } 20 | -------------------------------------------------------------------------------- /modules/aws-tgw/examples/simple/versions.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * 6 | */ 7 | 8 | terraform { 9 | required_version = "~>1.5" 10 | required_providers { 11 | aws = { 12 | source = "hashicorp/aws" 13 | version = "~>5.0" 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /modules/aws-tgw/test/integration_test.go: -------------------------------------------------------------------------------- 1 | //go:build integration 2 | 3 | package test 4 | 5 | import ( 6 | "testing" 7 | 8 | "github.com/gruntwork-io/terratest/modules/terraform" 9 | ) 10 | 11 | func TestTerraformSimpleExample(t *testing.T) { 12 | terraformOptions := terraform.WithDefaultRetryableErrors(t, &terraform.Options{ 13 | TerraformDir: "../examples/simple", 14 | }) 15 | 16 | defer terraform.Destroy(t, terraformOptions) 17 | 18 | terraform.InitAndApply(t, terraformOptions) 19 | } 20 | -------------------------------------------------------------------------------- /modules/aws-vpc/test/integration_test.go: -------------------------------------------------------------------------------- 1 | //go:build integration 2 | 3 | package test 4 | 5 | import ( 6 | "testing" 7 | 8 | "github.com/gruntwork-io/terratest/modules/terraform" 9 | ) 10 | 11 | func TestTerraformSimpleExample(t *testing.T) { 12 | terraformOptions := terraform.WithDefaultRetryableErrors(t, &terraform.Options{ 13 | TerraformDir: "../examples/simple", 14 | }) 15 | 16 | defer terraform.Destroy(t, terraformOptions) 17 | 18 | terraform.InitAndApply(t, terraformOptions) 19 | } 20 | -------------------------------------------------------------------------------- /modules/bananalab-ecs-service/versions.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * 6 | */ 7 | 8 | terraform { 9 | required_version = "~>1.5" 10 | required_providers { 11 | aws = { 12 | source = "hashicorp/aws" 13 | version = "~>5.0" 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /modules/bananalab-platform/versions.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * 6 | */ 7 | 8 | terraform { 9 | required_version = "~>1.5.0" 10 | required_providers { 11 | aws = { 12 | source = "hashicorp/aws" 13 | version = "~>5.0" 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /modules/aws-ecs-cluster/test/integration_test.go: -------------------------------------------------------------------------------- 1 | //go:build integration 2 | 3 | package test 4 | 5 | import ( 6 | "testing" 7 | 8 | "github.com/gruntwork-io/terratest/modules/terraform" 9 | ) 10 | 11 | func TestTerraformSimpleExample(t *testing.T) { 12 | terraformOptions := terraform.WithDefaultRetryableErrors(t, &terraform.Options{ 13 | TerraformDir: "../examples/simple", 14 | }) 15 | 16 | defer terraform.Destroy(t, terraformOptions) 17 | 18 | terraform.InitAndApply(t, terraformOptions) 19 | } 20 | -------------------------------------------------------------------------------- /modules/aws-https-alb/outputs.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * 5 | */ 6 | 7 | output "result" { 8 | description = <<-EOT 9 | The result of the module. 10 | EOT 11 | value = { 12 | aws_lb = aws_lb.this 13 | http_listener = aws_lb_listener.this 14 | https_listener = aws_lb_listener.https 15 | route53_record = data.aws_route53_zone.this 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /modules/aws-https-alb/test/integration_test.go: -------------------------------------------------------------------------------- 1 | //go:build integration 2 | 3 | package test 4 | 5 | import ( 6 | "testing" 7 | 8 | "github.com/gruntwork-io/terratest/modules/terraform" 9 | ) 10 | 11 | func TestTerraformSimpleExample(t *testing.T) { 12 | terraformOptions := terraform.WithDefaultRetryableErrors(t, &terraform.Options{ 13 | TerraformDir: "../examples/simple", 14 | }) 15 | 16 | defer terraform.Destroy(t, terraformOptions) 17 | 18 | terraform.InitAndApply(t, terraformOptions) 19 | } 20 | -------------------------------------------------------------------------------- /modules/aws-s3-bucket/test/integration_test.go: -------------------------------------------------------------------------------- 1 | //go:build integration 2 | 3 | package test 4 | 5 | import ( 6 | "testing" 7 | 8 | "github.com/gruntwork-io/terratest/modules/terraform" 9 | ) 10 | 11 | func TestTerraformSimpleExample(t *testing.T) { 12 | terraformOptions := terraform.WithDefaultRetryableErrors(t, &terraform.Options{ 13 | TerraformDir: "../examples/simple", 14 | }) 15 | 16 | defer terraform.Destroy(t, terraformOptions) 17 | 18 | terraform.InitAndApply(t, terraformOptions) 19 | } 20 | -------------------------------------------------------------------------------- /modules/bananalab-ecs-service/test/integration_test.go: -------------------------------------------------------------------------------- 1 | //go:build integration 2 | 3 | package test 4 | 5 | import ( 6 | "testing" 7 | 8 | "github.com/gruntwork-io/terratest/modules/terraform" 9 | ) 10 | 11 | func TestTerraformSimpleExample(t *testing.T) { 12 | terraformOptions := terraform.WithDefaultRetryableErrors(t, &terraform.Options{ 13 | TerraformDir: "../examples/simple", 14 | }) 15 | 16 | defer terraform.Destroy(t, terraformOptions) 17 | 18 | terraform.InitAndApply(t, terraformOptions) 19 | } 20 | -------------------------------------------------------------------------------- /modules/bananalab-platform/test/integration_test.go: -------------------------------------------------------------------------------- 1 | //go:build integration 2 | 3 | package test 4 | 5 | import ( 6 | "testing" 7 | 8 | "github.com/gruntwork-io/terratest/modules/terraform" 9 | ) 10 | 11 | func TestTerraformSimpleExample(t *testing.T) { 12 | terraformOptions := terraform.WithDefaultRetryableErrors(t, &terraform.Options{ 13 | TerraformDir: "../examples/simple", 14 | }) 15 | 16 | defer terraform.Destroy(t, terraformOptions) 17 | 18 | terraform.InitAndApply(t, terraformOptions) 19 | } 20 | -------------------------------------------------------------------------------- /modules/aws-ecs-cluster/variables.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * 5 | */ 6 | 7 | variable "name" { 8 | type = string 9 | description = <<-EOT 10 | Name of ECS Cluster and other resources. 11 | EOT 12 | } 13 | 14 | variable "autoscaling_group_arn" { 15 | type = string 16 | description = <<-EOT 17 | ARN of autoscaling group to associate with the cluster. 18 | EOT 19 | } 20 | -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "customizations": { 3 | "vscode": { 4 | "extensions": [ 5 | "amazonwebservices.aws-toolkit-vscode", 6 | "Bridgecrew.checkov", 7 | "hashicorp.hcl", 8 | "hashicorp.terraform", 9 | "ms-vscode.makefile-tools", 10 | "SimonSiefke.svg-preview" 11 | ], 12 | "settings": { 13 | "editor.formatOnSave": true 14 | } 15 | } 16 | }, 17 | "image": "bananalab/devcontainer", 18 | "remoteUser": "devcontainer" 19 | } 20 | -------------------------------------------------------------------------------- /modules/bananalab-platform/outputs.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * 5 | */ 6 | 7 | output "result" { 8 | description = <<-EOT 9 | The result of the module. 10 | EOT 11 | value = { 12 | vpc = module.vpc.result 13 | asg = module.asg.result 14 | alb = module.alb.result 15 | ecs = module.ecs.result 16 | log_bucket = module.log_bucket.result 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /.template/examples/simple/main.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * Examples should illustrate typical use cases. 3 | * For multiple examples each should have its own directory. 4 | * 5 | * > Running module examples uses a local state file. 6 | * > If you delete the .terraform directory the resources 7 | * > will be orphaned. 8 | */ 9 | 10 | provider "random" {} 11 | 12 | module "this" { 13 | source = "../../" 14 | } 15 | 16 | output "result" { 17 | description = <<-EOT 18 | The result of the module. 19 | EOT 20 | value = module.this.result 21 | } 22 | -------------------------------------------------------------------------------- /modules/aws-ipam/variables.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * 5 | */ 6 | 7 | variable "root_cidr" { 8 | type = string 9 | description = <<-EOT 10 | Top level CIDR. 11 | EOT 12 | } 13 | 14 | variable "ipam_regions" { 15 | type = list(string) 16 | description = <<-EOT 17 | List of regions to enable the IPAM in. The region of the provider is 18 | automatically included. 19 | EOT 20 | default = [] 21 | } 22 | -------------------------------------------------------------------------------- /modules/aws-https-alb/versions.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * 6 | */ 7 | 8 | terraform { 9 | required_version = "~>1.5.0" 10 | required_providers { 11 | aws = { 12 | source = "hashicorp/aws" 13 | version = "~>5.0" 14 | } 15 | random = { 16 | source = "hashicorp/random" 17 | version = "~>3.0" 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /modules/bananalab-ecs-service/outputs.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * 5 | */ 6 | 7 | output "result" { 8 | description = <<-EOT 9 | The result of the module. 10 | EOT 11 | value = { 12 | task_definition = aws_ecs_task_definition.this 13 | service = aws_ecs_service.this 14 | target_group = aws_lb_target_group.this 15 | listener_rule = aws_lb_listener_rule.this 16 | ecs_execution_role = aws_iam_role.ecs_execution 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /modules/aws-vpc/examples/full/main.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | default_tags { 3 | tags = { 4 | Terraformed = true 5 | Environment = "test" 6 | Name = "vpc-module-test" 7 | } 8 | } 9 | } 10 | 11 | data "aws_availability_zones" "available" { 12 | state = "available" 13 | } 14 | 15 | module "this" { 16 | source = "../../" 17 | name = "example" 18 | availability_zones = slice(data.aws_availability_zones.available.names, 0, 2) 19 | ipam_pool_id = "ipam-pool-04c7e976c8ae04494" 20 | attach_transit_gateway = true 21 | transit_gateway_id = "tgw-01c8de5704729bc19" 22 | vpc_netmask_length = 16 23 | subnets_netmask_length = 20 24 | } 25 | -------------------------------------------------------------------------------- /modules/aws-ipam/examples/simple/main.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * Examples should illustrate typical use cases. 3 | * For multiple examples each should have its own directory. 4 | * 5 | * > Running module examples uses a local state file. 6 | * > If you delete the .terraform directory the resources 7 | * > will be orphaned. 8 | */ 9 | 10 | provider "aws" { 11 | default_tags { 12 | tags = { 13 | terraformed = "true" 14 | example = "simple" 15 | module = "aws-ipam" 16 | } 17 | } 18 | } 19 | 20 | module "this" { 21 | source = "../../" 22 | root_cidr = "10.0.0.0/8" 23 | } 24 | 25 | output "result" { 26 | description = <<-EOT 27 | The result of the module. 28 | EOT 29 | value = module.this.result 30 | } 31 | -------------------------------------------------------------------------------- /modules/aws-vpc/examples/simple/main.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | default_tags { 3 | tags = { 4 | Terraformed = true 5 | Environment = "test" 6 | Name = "vpc-module-test" 7 | } 8 | } 9 | } 10 | 11 | data "aws_availability_zones" "available" { 12 | state = "available" 13 | } 14 | 15 | locals { 16 | availability_zones = slice(data.aws_availability_zones.available.names, 0, 2) 17 | } 18 | 19 | module "this" { 20 | source = "../../" 21 | name = "example" 22 | availability_zones = local.availability_zones 23 | vpc_ip_address = "10.11.0.0" 24 | vpc_netmask_length = 16 25 | subnets_netmask_length = 20 26 | create_public_subnets = true 27 | create_nat_gateways = true 28 | } 29 | -------------------------------------------------------------------------------- /modules/aws-ec2-asg/examples/simple/main.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | default_tags { 3 | tags = { 4 | Terraformed = true 5 | Environment = "test" 6 | Name = "asg-module-test" 7 | } 8 | } 9 | } 10 | 11 | data "aws_subnets" "private" { 12 | tags = { 13 | Tier = "Private" 14 | } 15 | } 16 | 17 | module "this" { 18 | source = "../../" 19 | name = "asg-module-example" 20 | user_data = templatefile("user_data.sh", {}) 21 | subnet_ids = data.aws_subnets.private.ids 22 | ami_ssm_parameter = "/aws/service/ecs/optimized-ami/amazon-linux-2/recommended" 23 | } 24 | 25 | output "result" { 26 | description = <<-EOT 27 | The result of the module. 28 | EOT 29 | value = module.this.result 30 | } 31 | -------------------------------------------------------------------------------- /modules/aws-tgw/examples/simple/main.tf: -------------------------------------------------------------------------------- 1 | 2 | provider "aws" { 3 | default_tags { 4 | tags = { 5 | Name = "aws-tgw-module-example" 6 | } 7 | } 8 | } 9 | 10 | data "aws_availability_zones" "available" { 11 | state = "available" 12 | } 13 | 14 | locals { 15 | availability_zones = slice(data.aws_availability_zones.available.names, 0, 2) 16 | } 17 | 18 | module "this" { 19 | source = "../../" 20 | vpc_cidr = "172.16.0.0/16" 21 | vpc_name = "example" 22 | client_cidrs = ["10.0.0.0/8"] 23 | availability_zones = local.availability_zones 24 | subnets_netmask_length = 20 25 | } 26 | 27 | output "result" { 28 | description = <<-EOT 29 | The result of the module. 30 | EOT 31 | value = module.this.result 32 | } 33 | -------------------------------------------------------------------------------- /modules/bananalab-ecs-service/examples/simple/container-definitions.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "cpu": 0, 4 | "environment": [], 5 | "essential": true, 6 | "image": "nginx", 7 | "logConfiguration": { 8 | "logDriver": "awslogs", 9 | "options": { 10 | "awslogs-create-group": "true", 11 | "awslogs-group": "/ecs/nginx", 12 | "awslogs-region": "us-west-1", 13 | "awslogs-stream-prefix": "ecs" 14 | } 15 | }, 16 | "memory": 1024, 17 | "mountPoints": [], 18 | "name": "nginx", 19 | "portMappings": [ 20 | { 21 | "appProtocol": "http", 22 | "containerPort": 80, 23 | "hostPort": 80, 24 | "name": "nginx_web-80-tcp", 25 | "protocol": "tcp" 26 | } 27 | ], 28 | "volumesFrom": [] 29 | } 30 | ] 31 | -------------------------------------------------------------------------------- /modules/aws-vpc/examples/ipam/main.tf: -------------------------------------------------------------------------------- 1 | /** 2 | Create a simple VPC with IPAM addressing. 3 | >> Note: VPC destruction may timeout with IPAM integration. 4 | */ 5 | 6 | provider "aws" { 7 | default_tags { 8 | tags = { 9 | Terraformed = true 10 | Environment = "test" 11 | Name = "vpc-module-test" 12 | } 13 | } 14 | } 15 | 16 | data "aws_availability_zones" "available" { 17 | state = "available" 18 | } 19 | 20 | module "this" { 21 | source = "../../" 22 | name = "example" 23 | availability_zones = slice(data.aws_availability_zones.available.names, 0, 2) 24 | ipam_pool_id = "ipam-pool-04c7e976c8ae04494" 25 | vpc_netmask_length = 16 26 | subnets_netmask_length = 20 27 | create_public_subnets = true 28 | create_nat_gateways = true 29 | } 30 | -------------------------------------------------------------------------------- /modules/aws-https-alb/examples/simple/main.tf: -------------------------------------------------------------------------------- 1 | variable "name" { 2 | default = "aws-https-module-example" 3 | } 4 | 5 | variable "domain_name" { 6 | default = "bananalab.dev" 7 | } 8 | 9 | data "aws_vpc" "default" { 10 | default = true 11 | } 12 | 13 | data "aws_subnets" "default" { 14 | filter { 15 | name = "vpc-id" 16 | values = [data.aws_vpc.default.id] 17 | } 18 | filter { 19 | name = "default-for-az" 20 | values = ["true"] 21 | } 22 | } 23 | 24 | module "this" { 25 | source = "../../" 26 | name = var.name 27 | vpc_id = data.aws_vpc.default.id 28 | subnet_ids = data.aws_subnets.default.ids 29 | application_host = var.name 30 | domain_name = var.domain_name 31 | } 32 | 33 | output "result" { 34 | description = <<-EOT 35 | The result of the module. 36 | EOT 37 | value = module.this.result 38 | } 39 | -------------------------------------------------------------------------------- /modules/aws-tgw/variables.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * 5 | */ 6 | 7 | variable "availability_zones" { 8 | type = list(string) 9 | description = <<-EOT 10 | Availability zones to create resources in. 11 | EOT 12 | } 13 | 14 | variable "vpc_cidr" { 15 | type = string 16 | description = <<-EOT 17 | CIDR block for VPC 18 | EOT 19 | } 20 | 21 | variable "vpc_name" { 22 | type = string 23 | description = <<-EOT 24 | Name of the VPC. 25 | EOT 26 | } 27 | 28 | variable "subnets_netmask_length" { 29 | type = number 30 | description = <<-EOT 31 | Number of subnet bits for subnets. 32 | EOT 33 | } 34 | 35 | variable "client_cidrs" { 36 | type = list(string) 37 | description = <<-EOT 38 | Client CIDR blocks to route. 39 | EOT 40 | } 41 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/antonbabenko/pre-commit-terraform 3 | rev: v1.72.2 4 | hooks: 5 | - id: terraform_checkov 6 | args: 7 | - --args=--quiet 8 | - --args=--directory=modules 9 | - id: terraform_docs 10 | exclude: (\.template\/.*$|.*\/examples\/.*|.*\/test\/.*) 11 | args: 12 | - --args=--config=.terraform-docs.yaml 13 | - --hook-config=--path-to-file=README.md 14 | - --hook-config=--add-to-existing-file=true 15 | - --hook-config=--create-file-if-not-exist=true 16 | - id: terraform_fmt 17 | - id: terraform_tflint 18 | - repo: https://github.com/pre-commit/pre-commit-hooks 19 | rev: v2.3.0 20 | hooks: 21 | - id: check-json 22 | - id: check-merge-conflict 23 | - id: check-yaml 24 | - id: end-of-file-fixer 25 | - id: pretty-format-json 26 | args: 27 | - --autofix 28 | - id: trailing-whitespace 29 | - repo: https://github.com/codespell-project/codespell 30 | rev: v2.1.0 31 | hooks: 32 | - id: codespell 33 | - repo: https://github.com/igorshubovych/markdownlint-cli 34 | rev: v0.31.1 35 | hooks: 36 | - id: markdownlint 37 | -------------------------------------------------------------------------------- /modules/aws-ecs-cluster/main.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * 5 | */ 6 | 7 | resource "aws_ecs_cluster" "this" { 8 | name = var.name 9 | 10 | setting { 11 | name = "containerInsights" 12 | value = "enabled" 13 | } 14 | } 15 | 16 | resource "aws_ecs_capacity_provider" "this" { 17 | name = var.name 18 | 19 | auto_scaling_group_provider { 20 | auto_scaling_group_arn = var.autoscaling_group_arn 21 | managed_termination_protection = "DISABLED" 22 | 23 | managed_scaling { 24 | maximum_scaling_step_size = 5 25 | minimum_scaling_step_size = 1 26 | status = "ENABLED" 27 | target_capacity = 100 28 | } 29 | } 30 | } 31 | 32 | resource "aws_ecs_cluster_capacity_providers" "this" { 33 | cluster_name = aws_ecs_cluster.this.name 34 | 35 | capacity_providers = ["FARGATE", "FARGATE_SPOT", aws_ecs_capacity_provider.this.name] 36 | 37 | default_capacity_provider_strategy { 38 | base = 1 39 | weight = 100 40 | capacity_provider = aws_ecs_capacity_provider.this.name 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Local .terraform directories 2 | **/.terraform/* 3 | 4 | # .tfstate files 5 | *.tfstate 6 | *.tfstate.* 7 | 8 | # Crash log files 9 | crash.log 10 | crash.*.log 11 | 12 | # Exclude all .tfvars files, which are likely to contain sensitive data, such as 13 | # password, private keys, and other secrets. These should not be part of version 14 | # control as they are data points which are potentially sensitive and subject 15 | # to change depending on the environment. 16 | *.tfvars 17 | *.tfvars.json 18 | 19 | # Ignore override files as they are usually used to override resources locally and so 20 | # are not checked in 21 | override.tf 22 | override.tf.json 23 | *_override.tf 24 | *_override.tf.json 25 | 26 | # Include override files you do wish to add to version control using negated pattern 27 | # !example_override.tf 28 | 29 | # Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan 30 | # example: *tfplan* 31 | 32 | # Ignore CLI configuration files 33 | .terraformrc 34 | terraform.rc 35 | 36 | # Ignore lock files for modules. 37 | .terraform.lock.hcl 38 | 39 | # Temp files for release-please config 40 | .release-please-config.json.tmp 41 | 42 | #Brewfile lock shouldn't be in scm 43 | Brewfile.lock.json 44 | -------------------------------------------------------------------------------- /modules/bananalab-platform/examples/simple/main.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * Examples should illustrate typical use cases. 3 | * For multiple examples each should have its own directory. 4 | * 5 | * > Running module examples uses a local state file. 6 | * > If you delete the .terraform directory the resources 7 | * > will be orphaned. 8 | */ 9 | 10 | locals { 11 | name = terraform.workspace 12 | domain_name = "bananalab.dev" 13 | availability_zones = slice(data.aws_availability_zones.available.names, 0, 2) 14 | asg_min_instances = length(local.availability_zones) 15 | } 16 | 17 | provider "aws" { 18 | default_tags { 19 | tags = { 20 | terraformed = "true" 21 | example = "simple" 22 | module = "bananalab-platform" 23 | } 24 | } 25 | } 26 | 27 | data "aws_availability_zones" "available" { 28 | state = "available" 29 | } 30 | 31 | module "this" { 32 | source = "../../" 33 | name = local.name 34 | availability_zones = local.availability_zones 35 | domain_name = local.domain_name 36 | asg_min_instances = local.asg_min_instances 37 | boot_script = templatefile("${path.module}/boot_script.sh.tftpl", {}) 38 | } 39 | 40 | output "result" { 41 | description = <<-EOT 42 | The result of the module. 43 | EOT 44 | value = module.this.result 45 | } 46 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | SHELL := $(shell which bash) 2 | 3 | MODULES_DIR=modules 4 | MODULENAME_PATTERN=^[0-9a-z-]*$$ 5 | 6 | ifeq (module,$(firstword $(MAKECMDGOALS))) 7 | RUN_ARGS := $(wordlist 2,$(words $(MAKECMDGOALS)),$(MAKECMDGOALS)) 8 | $(eval $(RUN_ARGS):;@:) 9 | endif 10 | 11 | ifdef TERM 12 | BOLD=$(shell tput bold) 13 | RED=$(shell tput setaf 1) 14 | GREEN=$(shell tput setaf 2) 15 | YELLOW=$(shell tput setaf 3) 16 | RESET=$(shell tput sgr0) 17 | endif 18 | 19 | .PHONY: module 20 | 21 | module : 22 | @MODULENAME=$(RUN_ARGS); \ 23 | MODULES_DIR=$(MODULES_DIR); \ 24 | MODULENAME_PATTERN=$(MODULENAME_PATTERN); \ 25 | if [ -z $$MODULENAME ]; then \ 26 | echo "$(BOLD)$(RED)No module name provided.$(RESET)"; \ 27 | echo "$(BOLD)Example usage: \`make module my-module\`$(RESET)"; \ 28 | exit 1; \ 29 | elif [[ ! $$MODULENAME =~ $$MODULENAME_PATTERN ]]; then \ 30 | echo "$(BOLD)$(RED)Module name must match \'$$MODULENAME_PATTERN'.$(RESET)"; \ 31 | echo "$(BOLD)Example usage: \`make module my-module\`$(RESET)"; \ 32 | exit 1; \ 33 | elif [ -d $$MODULES_DIR/$$MODULENAME ]; then \ 34 | echo "$(BOLD)$(RED)Module $$MODULENAME already exists.$(RESET)"; \ 35 | exit 1; \ 36 | else \ 37 | MODULENAME=$$MODULENAME gomplate --input-dir=.template --output-dir=$$MODULES_DIR/$$MODULENAME; \ 38 | echo "$(BOLD)$(GREEN)$$MODULES_DIR/$$MODULENAME$(RESET)"; \ 39 | git checkout -b "$$MODULENAME"; \ 40 | cd $$MODULES_DIR/$$MODULENAME; \ 41 | make test; \ 42 | fi 43 | -------------------------------------------------------------------------------- /modules/aws-ipam/main.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * 5 | Creates an Organizational shared IPAM. 6 | */ 7 | 8 | data "aws_region" "current" {} 9 | data "aws_organizations_organization" "this" {} 10 | 11 | locals { 12 | all_ipam_regions = distinct(concat([data.aws_region.current.name], var.ipam_regions)) 13 | } 14 | 15 | resource "aws_vpc_ipam" "this" { 16 | dynamic "operating_regions" { 17 | for_each = local.all_ipam_regions 18 | content { 19 | region_name = operating_regions.value 20 | } 21 | } 22 | } 23 | 24 | resource "aws_vpc_ipam_pool" "this" { 25 | address_family = "ipv4" 26 | ipam_scope_id = aws_vpc_ipam.this.private_default_scope_id 27 | locale = data.aws_region.current.name 28 | } 29 | 30 | resource "aws_vpc_ipam_pool_cidr" "this" { 31 | ipam_pool_id = aws_vpc_ipam_pool.this.id 32 | cidr = var.root_cidr 33 | } 34 | 35 | resource "aws_ram_resource_share" "this" { 36 | name = "${aws_vpc_ipam_pool.this.id} share" 37 | } 38 | 39 | resource "aws_ram_principal_association" "this" { 40 | principal = data.aws_organizations_organization.this.arn 41 | resource_share_arn = aws_ram_resource_share.this.arn 42 | } 43 | 44 | resource "aws_ram_resource_association" "this" { 45 | resource_arn = aws_vpc_ipam_pool.this.arn 46 | resource_share_arn = aws_ram_resource_share.this.arn 47 | } 48 | -------------------------------------------------------------------------------- /modules/aws-ecs-cluster/examples/simple/main.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | name = "module-ecs-example" 3 | } 4 | 5 | provider "aws" { 6 | default_tags { 7 | tags = { 8 | Terraformed = true 9 | Environment = "test" 10 | Name = local.name 11 | } 12 | } 13 | } 14 | 15 | data "aws_availability_zones" "available" { 16 | state = "available" 17 | } 18 | 19 | locals { 20 | availability_zones = slice(data.aws_availability_zones.available.names, 0, 2) 21 | } 22 | 23 | module "vpc" { 24 | source = "../../../aws-vpc" 25 | name = local.name 26 | vpc_ip_address = "10.97.0.0" 27 | vpc_netmask_length = 16 28 | availability_zones = local.availability_zones 29 | subnets_netmask_length = 20 30 | create_public_subnets = true 31 | create_nat_gateways = true 32 | } 33 | 34 | module "asg" { 35 | source = "../../../aws-ec2-asg" 36 | name = local.name 37 | subnet_ids = [for subnet in module.vpc.result.private_subnets : subnet.id] 38 | ami_ssm_parameter = "/aws/service/ecs/optimized-ami/amazon-linux-2/recommended" 39 | instance_role_policies = [ 40 | "arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceforEC2Role", 41 | "arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy", 42 | "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore", 43 | "arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess", 44 | "arn:aws:iam::aws:policy/CloudWatchLogsFullAccess" 45 | ] 46 | user_data = templatefile("user_data.sh.tftpl", { name = local.name }) 47 | instance_tags = { 48 | AmazonECSManaged = true 49 | } 50 | } 51 | 52 | module "this" { 53 | source = "../.." 54 | name = local.name 55 | autoscaling_group_arn = module.asg.result.autoscaling_group.arn 56 | } 57 | 58 | output "result" { 59 | description = <<-EOT 60 | The result of the module. 61 | EOT 62 | value = module.this.result 63 | } 64 | -------------------------------------------------------------------------------- /modules/aws-ec2-asg/cloudwatch-config.tftpl: -------------------------------------------------------------------------------- 1 | ${jsonencode({ 2 | "agent": { 3 | "metrics_collection_interval": 60, 4 | "run_as_user": "root" 5 | }, 6 | "logs": { 7 | "logs_collected": { 8 | "files": { 9 | "collect_list": [ 10 | { 11 | "file_path": "/var/log/messages", 12 | "log_group_name": "${autoscaling_group_name}/messages", 13 | "log_stream_name": "{instance_id}", 14 | "retention_in_days": -1 15 | } 16 | ] 17 | } 18 | } 19 | }, 20 | "metrics": { 21 | "aggregation_dimensions": [ 22 | [ 23 | "InstanceId" 24 | ] 25 | ], 26 | "append_dimensions": { 27 | "AutoScalingGroupName": "$${aws:AutoScalingGroupName}", 28 | "ImageId": "$${aws:ImageId}", 29 | "InstanceId": "$${aws:InstanceId}", 30 | "InstanceType": "$${aws:InstanceType}" 31 | }, 32 | "metrics_collected": { 33 | "disk": { 34 | "measurement": [ 35 | "used_percent" 36 | ], 37 | "metrics_collection_interval": 60, 38 | "resources": [ 39 | "*" 40 | ] 41 | }, 42 | "mem": { 43 | "measurement": [ 44 | "mem_used_percent" 45 | ], 46 | "metrics_collection_interval": 60 47 | }, 48 | "statsd": { 49 | "metrics_aggregation_interval": 60, 50 | "metrics_collection_interval": 10, 51 | "service_address": ":8125" 52 | } 53 | } 54 | } 55 | }) 56 | } 57 | -------------------------------------------------------------------------------- /modules/bananalab-ecs-service/examples/simple/main.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * Examples should illustrate typical use cases. 3 | * For multiple examples each should have its own directory. 4 | * 5 | * > Running module examples uses a local state file. 6 | * > If you delete the .terraform directory the resources 7 | * > will be orphaned. 8 | */ 9 | 10 | provider "aws" { 11 | default_tags { 12 | tags = { 13 | terraformed = "true" 14 | example = "simple" 15 | module = local.name 16 | } 17 | } 18 | } 19 | 20 | data "aws_vpc" "this" { 21 | tags = { 22 | Name = local.platform_id 23 | } 24 | } 25 | 26 | data "aws_subnets" "private" { 27 | filter { 28 | name = "vpc-id" 29 | values = [data.aws_vpc.this.id] 30 | } 31 | 32 | tags = { 33 | Tier = "Private" 34 | } 35 | } 36 | 37 | data "aws_ecs_cluster" "this" { 38 | cluster_name = local.platform_id 39 | } 40 | 41 | data "aws_lb" "this" { 42 | name = local.platform_id 43 | } 44 | 45 | locals { 46 | name = "bananalab-ecs-service-example" 47 | domain_name = "bananalab.dev" 48 | platform_id = "default" 49 | container_definitions = file("container-definitions.json") 50 | volumes = {} 51 | 52 | load_balancer_targets = { 53 | "nginx" = { port = 80 } 54 | } 55 | 56 | url_rewrites = {} 57 | 58 | } 59 | 60 | module "this" { 61 | source = "../../" 62 | name = local.name 63 | fqdn = "${local.name}.${local.domain_name}" 64 | ecs_cluster_id = data.aws_ecs_cluster.this.id 65 | capacity_provider = local.platform_id 66 | subnet_ids = data.aws_subnets.private.ids 67 | load_balancer_arn = data.aws_lb.this.arn 68 | container_definitions = local.container_definitions 69 | volumes = local.volumes 70 | load_balancer_targets = local.load_balancer_targets 71 | url_rewrites = local.url_rewrites 72 | } 73 | 74 | output "result" { 75 | description = <<-EOT 76 | The result of the module. 77 | EOT 78 | value = module.this.result 79 | } 80 | -------------------------------------------------------------------------------- /modules/bananalab-platform/variables.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * 5 | */ 6 | 7 | variable "name" { 8 | type = string 9 | description = <<-EOT 10 | The name of the resources created by this module. 11 | This value is used as the basis for naming various resources. 12 | EOT 13 | } 14 | 15 | variable "availability_zones" { 16 | type = list(string) 17 | description = <<-EOT 18 | Availability zones to create resources in. 19 | EOT 20 | } 21 | 22 | variable "domain_name" { 23 | type = string 24 | description = <<-EOT 25 | Name of existing Route53 domain to use. 26 | EOT 27 | } 28 | 29 | variable "asg_instance_type" { 30 | type = string 31 | description = <<-EOT 32 | EC2 instance type to use in the autoscaling group. 33 | EOT 34 | default = "m6i.4xlarge" 35 | } 36 | 37 | variable "ecs_agent_config" { 38 | type = map(string) 39 | description = <<-EOT 40 | Key / Value pairs of ECS Agent environment variables. 41 | See: https://github.com/aws/amazon-ecs-agent/blob/master/README.md#environment-variables 42 | For options. 43 | ECS_CLUSTER is set by default. 44 | EOT 45 | default = {} 46 | } 47 | 48 | variable "boot_script" { 49 | type = string 50 | description = <<-EOT 51 | Content of shell script to execute at EC2 boot. 52 | Do not include plain text secrets. 53 | EOT 54 | default = null 55 | } 56 | 57 | variable "asg_max_instances" { 58 | type = number 59 | description = <<-EOT 60 | Maximum number of instances in the autoscaling group. If this is less than 61 | `asg_min_instances` then `asg_min_instances` will be used. 62 | EOT 63 | default = 1 64 | } 65 | 66 | variable "asg_min_instances" { 67 | type = number 68 | description = <<-EOT 69 | Minimum number of instances in the autoscaling group. 70 | EOT 71 | default = 1 72 | } 73 | 74 | variable "asg_root_volume_size" { 75 | type = number 76 | description = <<-EOT 77 | Size in GB of root volume. 78 | EOT 79 | default = 1000 80 | } 81 | -------------------------------------------------------------------------------- /modules/aws-https-alb/waf.tf: -------------------------------------------------------------------------------- 1 | resource "aws_wafv2_web_acl" "this" { 2 | #checkov:skip=CKV2_AWS_31:False positive. 3 | #checkov:skip=CKV_AWS_192:N/A 4 | count = var.enable_waf ? 1 : 0 5 | name = var.name 6 | scope = "REGIONAL" 7 | 8 | default_action { 9 | allow { 10 | } 11 | } 12 | dynamic "rule" { 13 | for_each = var.waf_managed_rules 14 | content { 15 | name = "AWS-${rule.key}" 16 | priority = index(keys(var.waf_managed_rules), rule.key) 17 | override_action { 18 | none {} 19 | } 20 | statement { 21 | managed_rule_group_statement { 22 | name = rule.key 23 | vendor_name = "AWS" 24 | dynamic "rule_action_override" { 25 | for_each = lookup(rule.value, "rule_action_overrides", {}) 26 | content { 27 | name = rule_action_override.key 28 | action_to_use { 29 | allow { 30 | 31 | } 32 | } 33 | } 34 | } 35 | } 36 | } 37 | visibility_config { 38 | cloudwatch_metrics_enabled = true 39 | metric_name = "AWS-${rule.key}" 40 | sampled_requests_enabled = true 41 | } 42 | } 43 | } 44 | 45 | visibility_config { 46 | cloudwatch_metrics_enabled = true 47 | metric_name = var.name 48 | sampled_requests_enabled = true 49 | } 50 | } 51 | 52 | resource "aws_wafv2_web_acl_association" "this" { 53 | count = var.enable_waf ? 1 : 0 54 | web_acl_arn = aws_wafv2_web_acl.this[0].arn 55 | resource_arn = aws_lb.this.arn 56 | } 57 | 58 | resource "aws_cloudwatch_log_group" "this" { 59 | #checkov:skip=CKV_AWS_158: TODO: Enable KMS 60 | #checkov:skip=CKV_AWS_338: TODO: Set retention 61 | count = var.enable_waf ? 1 : 0 62 | name = "aws-waf-logs-${aws_wafv2_web_acl.this[0].name}" 63 | retention_in_days = var.waf_log_retention_days 64 | } 65 | 66 | resource "aws_wafv2_web_acl_logging_configuration" "this" { 67 | count = var.enable_waf ? 1 : 0 68 | log_destination_configs = [aws_cloudwatch_log_group.this[0].arn] 69 | resource_arn = aws_wafv2_web_acl.this[0].arn 70 | } 71 | -------------------------------------------------------------------------------- /modules/aws-vpc/variables.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * 5 | */ 6 | 7 | variable "name" { 8 | type = string 9 | description = <<-EOT 10 | Name of the VPC. Used to name various other resources. 11 | EOT 12 | } 13 | 14 | variable "availability_zones" { 15 | type = list(string) 16 | description = <<-EOT 17 | Availability zones to create resources in. 18 | EOT 19 | } 20 | 21 | variable "vpc_ip_address" { 22 | type = string 23 | description = <<-EOT 24 | Base IP address block for VPC. Combined with `vpc_netmask_length` to form 25 | CIDR for the VPC. 26 | Conflicts with `ipam_pool_id`. 27 | EOT 28 | default = null 29 | } 30 | 31 | variable "vpc_netmask_length" { 32 | type = number 33 | description = <<-EOT 34 | The netmask length of the IPv4 CIDR to allocate to this VPC. 35 | EOT 36 | } 37 | 38 | variable "ipam_pool_id" { 39 | type = string 40 | description = <<-EOT 41 | The ID of an IPv4 IPAM pool you want to use for allocating this VPC's CIDR. 42 | Conflicts with `vpc_ip_address`. 43 | EOT 44 | default = null 45 | } 46 | 47 | variable "subnets_netmask_length" { 48 | type = string 49 | description = <<-EOT 50 | The netmask length of the IPv4 CIDR you want to allocate to subnets. 51 | Must be greater than `vpc_netmask_lengthh` 52 | EOT 53 | } 54 | 55 | variable "attach_transit_gateway" { 56 | type = bool 57 | description = <<-EOT 58 | Toggle Transit Gateway attachment. 59 | Requires `transit_gateway_id`. 60 | EOT 61 | default = false 62 | } 63 | 64 | variable "transit_gateway_id" { 65 | type = string 66 | description = <<-EOT 67 | Transit gateway to connect to. 68 | Requires `attach_transit_gateway`. 69 | Conflicts with `create_nat_gateways`. 70 | EOT 71 | default = null 72 | } 73 | 74 | variable "create_public_subnets" { 75 | type = bool 76 | description = <<-EOT 77 | Toggle public subnet creation. 78 | EOT 79 | default = false 80 | } 81 | 82 | variable "create_nat_gateways" { 83 | type = bool 84 | description = <<-EOT 85 | Toggle nat gateway creation. 86 | Conflicts with `transit_gateway_id`. 87 | Requires `create_public_subnets`. 88 | EOT 89 | default = false 90 | } 91 | -------------------------------------------------------------------------------- /modules/aws-s3-bucket/examples/simple/main.tf: -------------------------------------------------------------------------------- 1 | # tflint-ignore: all 2 | 3 | variable "bucket" { default = null } 4 | variable "bucket_prefix" { default = null } 5 | variable "force_destroy" { default = false } 6 | variable "object_lock_enabled" { default = false } 7 | variable "tags" { default = null } 8 | variable "block_public_acls" { default = true } 9 | variable "block_public_policy" { default = true } 10 | variable "ignore_public_acls" { default = true } 11 | variable "restrict_public_buckets" { default = true } 12 | variable "versioning_enabled" { default = true } 13 | variable "expected_bucket_owner" { default = null } 14 | variable "logging_enabled" { default = false } 15 | variable "logging_target_bucket" { default = null } 16 | variable "logging_target_prefix" { default = null } 17 | variable "enable_server_side_encryption" { default = true } 18 | variable "kms_master_key_id" { default = null } 19 | variable "enable_replication" { default = false } 20 | variable "replication_role" { default = null } 21 | variable "replication_target_bucket" { default = null } 22 | 23 | 24 | 25 | module "this" { 26 | source = "../../" 27 | bucket = var.bucket 28 | bucket_prefix = var.bucket_prefix 29 | force_destroy = var.force_destroy 30 | object_lock_enabled = var.object_lock_enabled 31 | tags = var.tags 32 | block_public_acls = var.block_public_acls 33 | block_public_policy = var.block_public_policy 34 | ignore_public_acls = var.ignore_public_acls 35 | versioning_enabled = var.versioning_enabled 36 | logging_enabled = var.logging_enabled 37 | logging_target_bucket = var.logging_target_bucket 38 | logging_target_prefix = var.logging_target_prefix 39 | expected_bucket_owner = var.expected_bucket_owner 40 | restrict_public_buckets = var.restrict_public_buckets 41 | enable_server_side_encryption = var.enable_server_side_encryption 42 | kms_master_key_id = var.kms_master_key_id 43 | enable_replication = var.enable_replication 44 | replication_role = var.replication_role 45 | replication_target_bucket = var.replication_target_bucket 46 | } 47 | 48 | output "result" { 49 | description = <<-EOT 50 | The result of the module. 51 | EOT 52 | value = module.this.result 53 | } 54 | -------------------------------------------------------------------------------- /modules/aws-https-alb/variables.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * 5 | */ 6 | 7 | 8 | variable "name" { 9 | type = string 10 | description = <<-EOT 11 | The name of the ALB. 12 | This value is used as the basis for naming various other resources. 13 | EOT 14 | } 15 | 16 | variable "vpc_id" { 17 | description = <<-EOT 18 | ID of VPC. 19 | EOT 20 | type = string 21 | } 22 | 23 | variable "subnet_ids" { 24 | type = list(string) 25 | description = <<-EOT 26 | Subnets to deploy Load Balancer in. 27 | EOT 28 | } 29 | 30 | variable "domain_name" { 31 | description = <<-EOT 32 | DNS domain. 33 | This will be combined with application_host to form the fqdn. 34 | This should already exist as a route53 hosted domain. 35 | EOT 36 | type = string 37 | } 38 | 39 | variable "application_host" { 40 | description = <<-EOT 41 | Hostname where the application will be reachable. 42 | EOT 43 | type = string 44 | } 45 | 46 | variable "waf_log_retention_days" { 47 | description = <<-EOT 48 | Number of days to retain WAF logs 49 | EOT 50 | type = number 51 | default = 90 52 | } 53 | 54 | variable "enable_waf" { 55 | description = <<-EOT 56 | Enable or disable WAF. 57 | EOT 58 | type = bool 59 | default = true 60 | } 61 | 62 | variable "idle_timeout" { 63 | description = <<-EOT 64 | The time in seconds that the connection is allowed to be idle. 65 | EOT 66 | type = number 67 | default = 600 68 | } 69 | 70 | variable "log_bucket" { 71 | type = string 72 | description = <<-EOT 73 | S3 bucket to store logs. 74 | EOT 75 | } 76 | 77 | variable "waf_managed_rules" { 78 | type = map(object({ 79 | rule_action_overrides = optional(map(string), {}) 80 | })) 81 | description = <<-EOT 82 | List of WAF managed rules. 83 | EOT 84 | default = { 85 | AWSManagedRulesPHPRuleSet = {} 86 | AWSManagedRulesAmazonIpReputationList = {} 87 | AWSManagedRulesAnonymousIpList = {} 88 | AWSManagedRulesCommonRuleSet = { 89 | rule_action_overrides = { 90 | SizeRestrictions_BODY = "allow" 91 | } 92 | } 93 | AWSManagedRulesKnownBadInputsRuleSet = {} 94 | AWSManagedRulesLinuxRuleSet = {} 95 | AWSManagedRulesSQLiRuleSet = {} 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /modules/aws-tgw/main.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * 5 | */ 6 | 7 | locals { 8 | vpc_ip_address = split("/", var.vpc_cidr)[0] 9 | vpc_netmask_length = split("/", var.vpc_cidr)[1] 10 | } 11 | 12 | module "vpc" { 13 | source = "../aws-vpc" 14 | name = var.vpc_name 15 | vpc_ip_address = local.vpc_ip_address 16 | vpc_netmask_length = local.vpc_netmask_length 17 | availability_zones = var.availability_zones 18 | subnets_netmask_length = var.subnets_netmask_length 19 | create_public_subnets = true 20 | create_nat_gateways = true 21 | } 22 | 23 | resource "aws_ec2_transit_gateway" "this" { 24 | # #checkov:skip=CKV_AWS_331:The transit gateway is shared with the org. 25 | dns_support = "enable" 26 | vpn_ecmp_support = "enable" 27 | default_route_table_association = "enable" 28 | default_route_table_propagation = "enable" 29 | auto_accept_shared_attachments = "enable" 30 | } 31 | 32 | resource "aws_ec2_transit_gateway_vpc_attachment" "this" { 33 | vpc_id = module.vpc.result.vpc.id 34 | subnet_ids = [for subnet in module.vpc.result.private_subnets : subnet.id] 35 | transit_gateway_id = aws_ec2_transit_gateway.this.id 36 | dns_support = "enable" 37 | transit_gateway_default_route_table_association = "true" 38 | transit_gateway_default_route_table_propagation = "true" 39 | } 40 | 41 | 42 | resource "aws_ram_resource_share" "this" { 43 | name = "${aws_ec2_transit_gateway.this.id} share" 44 | } 45 | 46 | data "aws_organizations_organization" "this" {} 47 | 48 | resource "aws_ram_principal_association" "this" { 49 | principal = data.aws_organizations_organization.this.arn 50 | resource_share_arn = aws_ram_resource_share.this.arn 51 | } 52 | 53 | resource "aws_ram_resource_association" "this" { 54 | resource_arn = aws_ec2_transit_gateway.this.arn 55 | resource_share_arn = aws_ram_resource_share.this.arn 56 | } 57 | 58 | resource "aws_ec2_transit_gateway_route" "this" { 59 | destination_cidr_block = "0.0.0.0/0" 60 | transit_gateway_attachment_id = aws_ec2_transit_gateway_vpc_attachment.this.id 61 | transit_gateway_route_table_id = aws_ec2_transit_gateway.this.association_default_route_table_id 62 | } 63 | 64 | resource "aws_route" "this" { 65 | for_each = toset(var.client_cidrs) 66 | route_table_id = module.vpc.result.public_route_table.id 67 | destination_cidr_block = each.value 68 | transit_gateway_id = aws_ec2_transit_gateway.this.id 69 | } 70 | -------------------------------------------------------------------------------- /modules/aws-tgw/test/go.mod: -------------------------------------------------------------------------------- 1 | module aws-tgw 2 | 3 | go 1.19 4 | 5 | require github.com/gruntwork-io/terratest v0.42.0 6 | 7 | require ( 8 | cloud.google.com/go v0.105.0 // indirect 9 | cloud.google.com/go/compute v1.12.1 // indirect 10 | cloud.google.com/go/compute/metadata v0.2.1 // indirect 11 | cloud.google.com/go/iam v0.7.0 // indirect 12 | cloud.google.com/go/storage v1.27.0 // indirect 13 | github.com/agext/levenshtein v1.2.3 // indirect 14 | github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect 15 | github.com/aws/aws-sdk-go v1.44.122 // indirect 16 | github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect 17 | github.com/davecgh/go-spew v1.1.1 // indirect 18 | github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect 19 | github.com/golang/protobuf v1.5.2 // indirect 20 | github.com/google/go-cmp v0.5.9 // indirect 21 | github.com/google/uuid v1.3.0 // indirect 22 | github.com/googleapis/enterprise-certificate-proxy v0.2.0 // indirect 23 | github.com/googleapis/gax-go/v2 v2.7.0 // indirect 24 | github.com/hashicorp/errwrap v1.0.0 // indirect 25 | github.com/hashicorp/go-cleanhttp v0.5.2 // indirect 26 | github.com/hashicorp/go-getter v1.7.1 // indirect 27 | github.com/hashicorp/go-multierror v1.1.0 // indirect 28 | github.com/hashicorp/go-safetemp v1.0.0 // indirect 29 | github.com/hashicorp/go-version v1.6.0 // indirect 30 | github.com/hashicorp/hcl/v2 v2.9.1 // indirect 31 | github.com/hashicorp/terraform-json v0.13.0 // indirect 32 | github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a // indirect 33 | github.com/jmespath/go-jmespath v0.4.0 // indirect 34 | github.com/klauspost/compress v1.15.11 // indirect 35 | github.com/mattn/go-zglob v0.0.2-0.20190814121620-e3c945676326 // indirect 36 | github.com/mitchellh/go-homedir v1.1.0 // indirect 37 | github.com/mitchellh/go-testing-interface v1.14.1 // indirect 38 | github.com/mitchellh/go-wordwrap v1.0.1 // indirect 39 | github.com/pmezard/go-difflib v1.0.0 // indirect 40 | github.com/stretchr/testify v1.8.1 // indirect 41 | github.com/tmccombs/hcl2json v0.3.3 // indirect 42 | github.com/ulikunitz/xz v0.5.10 // indirect 43 | github.com/zclconf/go-cty v1.9.1 // indirect 44 | go.opencensus.io v0.24.0 // indirect 45 | golang.org/x/crypto v0.1.0 // indirect 46 | golang.org/x/net v0.7.0 // indirect 47 | golang.org/x/oauth2 v0.1.0 // indirect 48 | golang.org/x/sys v0.5.0 // indirect 49 | golang.org/x/text v0.7.0 // indirect 50 | golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect 51 | google.golang.org/api v0.103.0 // indirect 52 | google.golang.org/appengine v1.6.7 // indirect 53 | google.golang.org/genproto v0.0.0-20221201164419-0e50fba7f41c // indirect 54 | google.golang.org/grpc v1.51.0 // indirect 55 | google.golang.org/protobuf v1.28.1 // indirect 56 | gopkg.in/yaml.v3 v3.0.1 // indirect 57 | ) 58 | -------------------------------------------------------------------------------- /modules/aws-ipam/test/go.mod: -------------------------------------------------------------------------------- 1 | module aws-ipam 2 | 3 | go 1.20 4 | 5 | require github.com/gruntwork-io/terratest v0.43.9 6 | 7 | require ( 8 | cloud.google.com/go v0.105.0 // indirect 9 | cloud.google.com/go/compute v1.12.1 // indirect 10 | cloud.google.com/go/compute/metadata v0.2.1 // indirect 11 | cloud.google.com/go/iam v0.7.0 // indirect 12 | cloud.google.com/go/storage v1.27.0 // indirect 13 | github.com/agext/levenshtein v1.2.3 // indirect 14 | github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect 15 | github.com/aws/aws-sdk-go v1.44.122 // indirect 16 | github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect 17 | github.com/davecgh/go-spew v1.1.1 // indirect 18 | github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect 19 | github.com/golang/protobuf v1.5.3 // indirect 20 | github.com/google/go-cmp v0.5.9 // indirect 21 | github.com/google/uuid v1.3.0 // indirect 22 | github.com/googleapis/enterprise-certificate-proxy v0.2.0 // indirect 23 | github.com/googleapis/gax-go/v2 v2.7.0 // indirect 24 | github.com/hashicorp/errwrap v1.0.0 // indirect 25 | github.com/hashicorp/go-cleanhttp v0.5.2 // indirect 26 | github.com/hashicorp/go-getter v1.7.1 // indirect 27 | github.com/hashicorp/go-multierror v1.1.0 // indirect 28 | github.com/hashicorp/go-safetemp v1.0.0 // indirect 29 | github.com/hashicorp/go-version v1.6.0 // indirect 30 | github.com/hashicorp/hcl/v2 v2.9.1 // indirect 31 | github.com/hashicorp/terraform-json v0.13.0 // indirect 32 | github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a // indirect 33 | github.com/jmespath/go-jmespath v0.4.0 // indirect 34 | github.com/klauspost/compress v1.15.11 // indirect 35 | github.com/mattn/go-zglob v0.0.2-0.20190814121620-e3c945676326 // indirect 36 | github.com/mitchellh/go-homedir v1.1.0 // indirect 37 | github.com/mitchellh/go-testing-interface v1.14.1 // indirect 38 | github.com/mitchellh/go-wordwrap v1.0.1 // indirect 39 | github.com/pmezard/go-difflib v1.0.0 // indirect 40 | github.com/stretchr/testify v1.8.1 // indirect 41 | github.com/tmccombs/hcl2json v0.3.3 // indirect 42 | github.com/ulikunitz/xz v0.5.10 // indirect 43 | github.com/zclconf/go-cty v1.9.1 // indirect 44 | go.opencensus.io v0.24.0 // indirect 45 | golang.org/x/crypto v0.1.0 // indirect 46 | golang.org/x/net v0.8.0 // indirect 47 | golang.org/x/oauth2 v0.1.0 // indirect 48 | golang.org/x/sys v0.6.0 // indirect 49 | golang.org/x/text v0.8.0 // indirect 50 | golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect 51 | google.golang.org/api v0.103.0 // indirect 52 | google.golang.org/appengine v1.6.7 // indirect 53 | google.golang.org/genproto v0.0.0-20221201164419-0e50fba7f41c // indirect 54 | google.golang.org/grpc v1.51.0 // indirect 55 | google.golang.org/protobuf v1.31.0 // indirect 56 | gopkg.in/yaml.v3 v3.0.1 // indirect 57 | ) 58 | -------------------------------------------------------------------------------- /modules/aws-ecs-cluster/test/go.mod: -------------------------------------------------------------------------------- 1 | module aws-ecs-cluster 2 | 3 | go 1.20 4 | 5 | require github.com/gruntwork-io/terratest v0.43.9 6 | 7 | require ( 8 | cloud.google.com/go v0.105.0 // indirect 9 | cloud.google.com/go/compute v1.12.1 // indirect 10 | cloud.google.com/go/compute/metadata v0.2.1 // indirect 11 | cloud.google.com/go/iam v0.7.0 // indirect 12 | cloud.google.com/go/storage v1.27.0 // indirect 13 | github.com/agext/levenshtein v1.2.3 // indirect 14 | github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect 15 | github.com/aws/aws-sdk-go v1.44.122 // indirect 16 | github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect 17 | github.com/davecgh/go-spew v1.1.1 // indirect 18 | github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect 19 | github.com/golang/protobuf v1.5.3 // indirect 20 | github.com/google/go-cmp v0.5.9 // indirect 21 | github.com/google/uuid v1.3.0 // indirect 22 | github.com/googleapis/enterprise-certificate-proxy v0.2.0 // indirect 23 | github.com/googleapis/gax-go/v2 v2.7.0 // indirect 24 | github.com/hashicorp/errwrap v1.0.0 // indirect 25 | github.com/hashicorp/go-cleanhttp v0.5.2 // indirect 26 | github.com/hashicorp/go-getter v1.7.1 // indirect 27 | github.com/hashicorp/go-multierror v1.1.0 // indirect 28 | github.com/hashicorp/go-safetemp v1.0.0 // indirect 29 | github.com/hashicorp/go-version v1.6.0 // indirect 30 | github.com/hashicorp/hcl/v2 v2.9.1 // indirect 31 | github.com/hashicorp/terraform-json v0.13.0 // indirect 32 | github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a // indirect 33 | github.com/jmespath/go-jmespath v0.4.0 // indirect 34 | github.com/klauspost/compress v1.15.11 // indirect 35 | github.com/mattn/go-zglob v0.0.2-0.20190814121620-e3c945676326 // indirect 36 | github.com/mitchellh/go-homedir v1.1.0 // indirect 37 | github.com/mitchellh/go-testing-interface v1.14.1 // indirect 38 | github.com/mitchellh/go-wordwrap v1.0.1 // indirect 39 | github.com/pmezard/go-difflib v1.0.0 // indirect 40 | github.com/stretchr/testify v1.8.1 // indirect 41 | github.com/tmccombs/hcl2json v0.3.3 // indirect 42 | github.com/ulikunitz/xz v0.5.10 // indirect 43 | github.com/zclconf/go-cty v1.9.1 // indirect 44 | go.opencensus.io v0.24.0 // indirect 45 | golang.org/x/crypto v0.1.0 // indirect 46 | golang.org/x/net v0.8.0 // indirect 47 | golang.org/x/oauth2 v0.1.0 // indirect 48 | golang.org/x/sys v0.6.0 // indirect 49 | golang.org/x/text v0.8.0 // indirect 50 | golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect 51 | google.golang.org/api v0.103.0 // indirect 52 | google.golang.org/appengine v1.6.7 // indirect 53 | google.golang.org/genproto v0.0.0-20221201164419-0e50fba7f41c // indirect 54 | google.golang.org/grpc v1.51.0 // indirect 55 | google.golang.org/protobuf v1.31.0 // indirect 56 | gopkg.in/yaml.v3 v3.0.1 // indirect 57 | ) 58 | -------------------------------------------------------------------------------- /modules/bananalab-platform/test/go.mod: -------------------------------------------------------------------------------- 1 | module bananalab-platform 2 | 3 | go 1.20 4 | 5 | require github.com/gruntwork-io/terratest v0.43.10 6 | 7 | require ( 8 | cloud.google.com/go v0.105.0 // indirect 9 | cloud.google.com/go/compute v1.12.1 // indirect 10 | cloud.google.com/go/compute/metadata v0.2.1 // indirect 11 | cloud.google.com/go/iam v0.7.0 // indirect 12 | cloud.google.com/go/storage v1.27.0 // indirect 13 | github.com/agext/levenshtein v1.2.3 // indirect 14 | github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect 15 | github.com/aws/aws-sdk-go v1.44.122 // indirect 16 | github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect 17 | github.com/davecgh/go-spew v1.1.1 // indirect 18 | github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect 19 | github.com/golang/protobuf v1.5.3 // indirect 20 | github.com/google/go-cmp v0.5.9 // indirect 21 | github.com/google/uuid v1.3.0 // indirect 22 | github.com/googleapis/enterprise-certificate-proxy v0.2.0 // indirect 23 | github.com/googleapis/gax-go/v2 v2.7.0 // indirect 24 | github.com/hashicorp/errwrap v1.0.0 // indirect 25 | github.com/hashicorp/go-cleanhttp v0.5.2 // indirect 26 | github.com/hashicorp/go-getter v1.7.1 // indirect 27 | github.com/hashicorp/go-multierror v1.1.0 // indirect 28 | github.com/hashicorp/go-safetemp v1.0.0 // indirect 29 | github.com/hashicorp/go-version v1.6.0 // indirect 30 | github.com/hashicorp/hcl/v2 v2.9.1 // indirect 31 | github.com/hashicorp/terraform-json v0.13.0 // indirect 32 | github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a // indirect 33 | github.com/jmespath/go-jmespath v0.4.0 // indirect 34 | github.com/klauspost/compress v1.15.11 // indirect 35 | github.com/mattn/go-zglob v0.0.2-0.20190814121620-e3c945676326 // indirect 36 | github.com/mitchellh/go-homedir v1.1.0 // indirect 37 | github.com/mitchellh/go-testing-interface v1.14.1 // indirect 38 | github.com/mitchellh/go-wordwrap v1.0.1 // indirect 39 | github.com/pmezard/go-difflib v1.0.0 // indirect 40 | github.com/stretchr/testify v1.8.1 // indirect 41 | github.com/tmccombs/hcl2json v0.3.3 // indirect 42 | github.com/ulikunitz/xz v0.5.10 // indirect 43 | github.com/zclconf/go-cty v1.9.1 // indirect 44 | go.opencensus.io v0.24.0 // indirect 45 | golang.org/x/crypto v0.1.0 // indirect 46 | golang.org/x/net v0.8.0 // indirect 47 | golang.org/x/oauth2 v0.1.0 // indirect 48 | golang.org/x/sys v0.6.0 // indirect 49 | golang.org/x/text v0.8.0 // indirect 50 | golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect 51 | google.golang.org/api v0.103.0 // indirect 52 | google.golang.org/appengine v1.6.7 // indirect 53 | google.golang.org/genproto v0.0.0-20221201164419-0e50fba7f41c // indirect 54 | google.golang.org/grpc v1.51.0 // indirect 55 | google.golang.org/protobuf v1.31.0 // indirect 56 | gopkg.in/yaml.v3 v3.0.1 // indirect 57 | ) 58 | -------------------------------------------------------------------------------- /modules/bananalab-ecs-service/test/go.mod: -------------------------------------------------------------------------------- 1 | module empire-ecs-service 2 | 3 | go 1.20 4 | 5 | require github.com/gruntwork-io/terratest v0.43.11 6 | 7 | require ( 8 | cloud.google.com/go v0.105.0 // indirect 9 | cloud.google.com/go/compute v1.12.1 // indirect 10 | cloud.google.com/go/compute/metadata v0.2.1 // indirect 11 | cloud.google.com/go/iam v0.7.0 // indirect 12 | cloud.google.com/go/storage v1.27.0 // indirect 13 | github.com/agext/levenshtein v1.2.3 // indirect 14 | github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect 15 | github.com/aws/aws-sdk-go v1.44.122 // indirect 16 | github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect 17 | github.com/davecgh/go-spew v1.1.1 // indirect 18 | github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect 19 | github.com/golang/protobuf v1.5.3 // indirect 20 | github.com/google/go-cmp v0.5.9 // indirect 21 | github.com/google/uuid v1.3.0 // indirect 22 | github.com/googleapis/enterprise-certificate-proxy v0.2.0 // indirect 23 | github.com/googleapis/gax-go/v2 v2.7.0 // indirect 24 | github.com/hashicorp/errwrap v1.0.0 // indirect 25 | github.com/hashicorp/go-cleanhttp v0.5.2 // indirect 26 | github.com/hashicorp/go-getter v1.7.1 // indirect 27 | github.com/hashicorp/go-multierror v1.1.0 // indirect 28 | github.com/hashicorp/go-safetemp v1.0.0 // indirect 29 | github.com/hashicorp/go-version v1.6.0 // indirect 30 | github.com/hashicorp/hcl/v2 v2.9.1 // indirect 31 | github.com/hashicorp/terraform-json v0.13.0 // indirect 32 | github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a // indirect 33 | github.com/jmespath/go-jmespath v0.4.0 // indirect 34 | github.com/klauspost/compress v1.15.11 // indirect 35 | github.com/mattn/go-zglob v0.0.2-0.20190814121620-e3c945676326 // indirect 36 | github.com/mitchellh/go-homedir v1.1.0 // indirect 37 | github.com/mitchellh/go-testing-interface v1.14.1 // indirect 38 | github.com/mitchellh/go-wordwrap v1.0.1 // indirect 39 | github.com/pmezard/go-difflib v1.0.0 // indirect 40 | github.com/stretchr/testify v1.8.1 // indirect 41 | github.com/tmccombs/hcl2json v0.3.3 // indirect 42 | github.com/ulikunitz/xz v0.5.10 // indirect 43 | github.com/zclconf/go-cty v1.9.1 // indirect 44 | go.opencensus.io v0.24.0 // indirect 45 | golang.org/x/crypto v0.1.0 // indirect 46 | golang.org/x/net v0.8.0 // indirect 47 | golang.org/x/oauth2 v0.1.0 // indirect 48 | golang.org/x/sys v0.6.0 // indirect 49 | golang.org/x/text v0.8.0 // indirect 50 | golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect 51 | google.golang.org/api v0.103.0 // indirect 52 | google.golang.org/appengine v1.6.7 // indirect 53 | google.golang.org/genproto v0.0.0-20221201164419-0e50fba7f41c // indirect 54 | google.golang.org/grpc v1.51.0 // indirect 55 | google.golang.org/protobuf v1.31.0 // indirect 56 | gopkg.in/yaml.v3 v3.0.1 // indirect 57 | ) 58 | -------------------------------------------------------------------------------- /modules/aws-vpc/go.mod: -------------------------------------------------------------------------------- 1 | module aws-vpc 2 | 3 | go 1.19 4 | 5 | require github.com/gruntwork-io/terratest v0.41.0 6 | 7 | require ( 8 | cloud.google.com/go v0.83.0 // indirect 9 | cloud.google.com/go/storage v1.10.0 // indirect 10 | github.com/agext/levenshtein v1.2.3 // indirect 11 | github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect 12 | github.com/aws/aws-sdk-go v1.40.56 // indirect 13 | github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect 14 | github.com/davecgh/go-spew v1.1.1 // indirect 15 | github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect 16 | github.com/golang/protobuf v1.5.2 // indirect 17 | github.com/golang/snappy v0.0.3 // indirect 18 | github.com/googleapis/gax-go/v2 v2.0.5 // indirect 19 | github.com/hashicorp/errwrap v1.0.0 // indirect 20 | github.com/hashicorp/go-cleanhttp v0.5.2 // indirect 21 | github.com/hashicorp/go-getter v1.6.1 // indirect 22 | github.com/hashicorp/go-multierror v1.1.0 // indirect 23 | github.com/hashicorp/go-safetemp v1.0.0 // indirect 24 | github.com/hashicorp/go-version v1.3.0 // indirect 25 | github.com/hashicorp/hcl/v2 v2.9.1 // indirect 26 | github.com/hashicorp/terraform-json v0.13.0 // indirect 27 | github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a // indirect 28 | github.com/jmespath/go-jmespath v0.4.0 // indirect 29 | github.com/jstemmer/go-junit-report v0.9.1 // indirect 30 | github.com/klauspost/compress v1.13.0 // indirect 31 | github.com/mattn/go-zglob v0.0.2-0.20190814121620-e3c945676326 // indirect 32 | github.com/mitchellh/go-homedir v1.1.0 // indirect 33 | github.com/mitchellh/go-testing-interface v1.0.0 // indirect 34 | github.com/mitchellh/go-wordwrap v1.0.1 // indirect 35 | github.com/pmezard/go-difflib v1.0.0 // indirect 36 | github.com/stretchr/testify v1.7.0 // indirect 37 | github.com/tmccombs/hcl2json v0.3.3 // indirect 38 | github.com/ulikunitz/xz v0.5.8 // indirect 39 | github.com/zclconf/go-cty v1.9.1 // indirect 40 | go.opencensus.io v0.23.0 // indirect 41 | golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a // indirect 42 | golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 // indirect 43 | golang.org/x/mod v0.4.2 // indirect 44 | golang.org/x/net v0.0.0-20210614182718-04defd469f4e // indirect 45 | golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c // indirect 46 | golang.org/x/sys v0.0.0-20220517195934-5e4e11fc645e // indirect 47 | golang.org/x/text v0.3.6 // indirect 48 | golang.org/x/tools v0.1.2 // indirect 49 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect 50 | google.golang.org/api v0.47.0 // indirect 51 | google.golang.org/appengine v1.6.7 // indirect 52 | google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c // indirect 53 | google.golang.org/grpc v1.38.0 // indirect 54 | google.golang.org/protobuf v1.26.0 // indirect 55 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect 56 | ) 57 | -------------------------------------------------------------------------------- /modules/aws-vpc/test/go.mod: -------------------------------------------------------------------------------- 1 | module aws-vpc 2 | 3 | go 1.19 4 | 5 | require github.com/gruntwork-io/terratest v0.41.0 6 | 7 | require ( 8 | cloud.google.com/go v0.83.0 // indirect 9 | cloud.google.com/go/storage v1.10.0 // indirect 10 | github.com/agext/levenshtein v1.2.3 // indirect 11 | github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect 12 | github.com/aws/aws-sdk-go v1.40.56 // indirect 13 | github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect 14 | github.com/davecgh/go-spew v1.1.1 // indirect 15 | github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect 16 | github.com/golang/protobuf v1.5.2 // indirect 17 | github.com/golang/snappy v0.0.3 // indirect 18 | github.com/googleapis/gax-go/v2 v2.0.5 // indirect 19 | github.com/hashicorp/errwrap v1.0.0 // indirect 20 | github.com/hashicorp/go-cleanhttp v0.5.2 // indirect 21 | github.com/hashicorp/go-getter v1.6.1 // indirect 22 | github.com/hashicorp/go-multierror v1.1.0 // indirect 23 | github.com/hashicorp/go-safetemp v1.0.0 // indirect 24 | github.com/hashicorp/go-version v1.3.0 // indirect 25 | github.com/hashicorp/hcl/v2 v2.9.1 // indirect 26 | github.com/hashicorp/terraform-json v0.13.0 // indirect 27 | github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a // indirect 28 | github.com/jmespath/go-jmespath v0.4.0 // indirect 29 | github.com/jstemmer/go-junit-report v0.9.1 // indirect 30 | github.com/klauspost/compress v1.13.0 // indirect 31 | github.com/mattn/go-zglob v0.0.2-0.20190814121620-e3c945676326 // indirect 32 | github.com/mitchellh/go-homedir v1.1.0 // indirect 33 | github.com/mitchellh/go-testing-interface v1.0.0 // indirect 34 | github.com/mitchellh/go-wordwrap v1.0.1 // indirect 35 | github.com/pmezard/go-difflib v1.0.0 // indirect 36 | github.com/stretchr/testify v1.7.0 // indirect 37 | github.com/tmccombs/hcl2json v0.3.3 // indirect 38 | github.com/ulikunitz/xz v0.5.8 // indirect 39 | github.com/zclconf/go-cty v1.9.1 // indirect 40 | go.opencensus.io v0.23.0 // indirect 41 | golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a // indirect 42 | golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 // indirect 43 | golang.org/x/mod v0.4.2 // indirect 44 | golang.org/x/net v0.0.0-20210614182718-04defd469f4e // indirect 45 | golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c // indirect 46 | golang.org/x/sys v0.0.0-20220517195934-5e4e11fc645e // indirect 47 | golang.org/x/text v0.3.6 // indirect 48 | golang.org/x/tools v0.1.2 // indirect 49 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect 50 | google.golang.org/api v0.47.0 // indirect 51 | google.golang.org/appengine v1.6.7 // indirect 52 | google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c // indirect 53 | google.golang.org/grpc v1.38.0 // indirect 54 | google.golang.org/protobuf v1.26.0 // indirect 55 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect 56 | ) 57 | -------------------------------------------------------------------------------- /modules/aws-s3-bucket/test/go.mod: -------------------------------------------------------------------------------- 1 | module aws-s3-bucket 2 | 3 | go 1.19 4 | 5 | require github.com/gruntwork-io/terratest v0.40.19 6 | 7 | require ( 8 | cloud.google.com/go v0.83.0 // indirect 9 | cloud.google.com/go/storage v1.10.0 // indirect 10 | github.com/agext/levenshtein v1.2.3 // indirect 11 | github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect 12 | github.com/aws/aws-sdk-go v1.40.56 // indirect 13 | github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect 14 | github.com/davecgh/go-spew v1.1.1 // indirect 15 | github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect 16 | github.com/golang/protobuf v1.5.2 // indirect 17 | github.com/golang/snappy v0.0.3 // indirect 18 | github.com/googleapis/gax-go/v2 v2.0.5 // indirect 19 | github.com/hashicorp/errwrap v1.0.0 // indirect 20 | github.com/hashicorp/go-cleanhttp v0.5.2 // indirect 21 | github.com/hashicorp/go-getter v1.6.1 // indirect 22 | github.com/hashicorp/go-multierror v1.1.0 // indirect 23 | github.com/hashicorp/go-safetemp v1.0.0 // indirect 24 | github.com/hashicorp/go-version v1.3.0 // indirect 25 | github.com/hashicorp/hcl/v2 v2.9.1 // indirect 26 | github.com/hashicorp/terraform-json v0.13.0 // indirect 27 | github.com/jinzhu/copier v0.0.0-20190924061706-b57f9002281a // indirect 28 | github.com/jmespath/go-jmespath v0.4.0 // indirect 29 | github.com/jstemmer/go-junit-report v0.9.1 // indirect 30 | github.com/klauspost/compress v1.13.0 // indirect 31 | github.com/mattn/go-zglob v0.0.2-0.20190814121620-e3c945676326 // indirect 32 | github.com/mitchellh/go-homedir v1.1.0 // indirect 33 | github.com/mitchellh/go-testing-interface v1.0.0 // indirect 34 | github.com/mitchellh/go-wordwrap v1.0.1 // indirect 35 | github.com/pmezard/go-difflib v1.0.0 // indirect 36 | github.com/stretchr/testify v1.7.0 // indirect 37 | github.com/tmccombs/hcl2json v0.3.3 // indirect 38 | github.com/ulikunitz/xz v0.5.8 // indirect 39 | github.com/zclconf/go-cty v1.9.1 // indirect 40 | go.opencensus.io v0.23.0 // indirect 41 | golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a // indirect 42 | golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 // indirect 43 | golang.org/x/mod v0.4.2 // indirect 44 | golang.org/x/net v0.0.0-20210614182718-04defd469f4e // indirect 45 | golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c // indirect 46 | golang.org/x/sys v0.0.0-20220517195934-5e4e11fc645e // indirect 47 | golang.org/x/text v0.3.6 // indirect 48 | golang.org/x/tools v0.1.2 // indirect 49 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect 50 | google.golang.org/api v0.47.0 // indirect 51 | google.golang.org/appengine v1.6.7 // indirect 52 | google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c // indirect 53 | google.golang.org/grpc v1.38.0 // indirect 54 | google.golang.org/protobuf v1.26.0 // indirect 55 | gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect 56 | ) 57 | -------------------------------------------------------------------------------- /modules/bananalab-platform/main.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * 5 | */ 6 | 7 | locals { 8 | name = var.name 9 | ecs_agent_config = <<-EOT 10 | %{for k, v in merge({ ECS_CLUSTER = local.name }, var.ecs_agent_config)~} 11 | ${upper(k)}=${v} 12 | %{endfor~} 13 | EOT 14 | 15 | user_data_yaml = yamlencode( 16 | { 17 | write_files = [ 18 | { 19 | path = "/etc/ecs/ecs.config" 20 | content = local.ecs_agent_config 21 | } 22 | ], 23 | runcmd = [ 24 | var.boot_script 25 | ] 26 | } 27 | ) 28 | user_data = "#cloud-config\n${local.user_data_yaml}" 29 | } 30 | 31 | data "aws_caller_identity" "current" {} 32 | 33 | module "vpc" { 34 | source = "../aws-vpc" 35 | name = var.name 36 | availability_zones = var.availability_zones 37 | vpc_ip_address = "10.11.0.0" 38 | vpc_netmask_length = 16 39 | subnets_netmask_length = 20 40 | create_public_subnets = true 41 | create_nat_gateways = true 42 | } 43 | 44 | module "asg" { 45 | source = "../aws-ec2-asg" 46 | name = local.name 47 | subnet_ids = [for subnet in module.vpc.result.private_subnets : subnet.id] 48 | instance_type = var.asg_instance_type 49 | ami_ssm_parameter = "/aws/service/ecs/optimized-ami/amazon-linux-2/recommended" 50 | max_size = max(var.asg_max_instances, var.asg_min_instances) 51 | min_size = var.asg_min_instances 52 | root_volume_size = var.asg_root_volume_size 53 | instance_role_policies = [ 54 | "arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceforEC2Role", 55 | "arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy", 56 | "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore", 57 | "arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess", 58 | "arn:aws:iam::aws:policy/CloudWatchLogsFullAccess" 59 | ] 60 | user_data = local.user_data 61 | instance_tags = { 62 | AmazonECSManaged = true 63 | } 64 | } 65 | 66 | module "alb" { 67 | source = "../aws-https-alb" 68 | name = local.name 69 | vpc_id = module.vpc.result.vpc.id 70 | subnet_ids = [for subnet in module.vpc.result.public_subnets : subnet.id] 71 | application_host = local.name 72 | domain_name = var.domain_name 73 | log_bucket = module.log_bucket.result.bucket.bucket 74 | } 75 | 76 | module "ecs" { 77 | source = "../aws-ecs-cluster" 78 | name = local.name 79 | autoscaling_group_arn = module.asg.result.autoscaling_group.arn 80 | } 81 | 82 | module "log_bucket" { 83 | source = "../aws-s3-bucket" 84 | bucket = "${local.name}-${data.aws_caller_identity.current.account_id}" 85 | logging_enabled = false 86 | enable_replication = false 87 | } 88 | -------------------------------------------------------------------------------- /modules/aws-s3-bucket/main.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * 5 | * L1 Module to create an S3 bucket. 6 | * 7 | */ 8 | 9 | resource "aws_s3_bucket" "this" { 10 | # checkov:skip=CKV2_AWS_61: N/A 11 | # checkov:skip=CKV2_AWS_62: N/A 12 | bucket = var.bucket 13 | bucket_prefix = var.bucket_prefix 14 | force_destroy = var.force_destroy 15 | object_lock_enabled = var.object_lock_enabled 16 | tags = var.tags 17 | lifecycle { 18 | precondition { 19 | condition = !(var.bucket != null && var.bucket_prefix != null) 20 | error_message = "bucket and bucket_prefix cannot both be set." 21 | } 22 | } 23 | } 24 | 25 | resource "aws_s3_bucket_public_access_block" "this" { 26 | bucket = aws_s3_bucket.this.id 27 | block_public_acls = var.block_public_acls 28 | block_public_policy = var.block_public_policy 29 | ignore_public_acls = var.ignore_public_acls 30 | restrict_public_buckets = var.restrict_public_buckets 31 | } 32 | 33 | resource "aws_s3_bucket_versioning" "this" { 34 | bucket = aws_s3_bucket.this.id 35 | expected_bucket_owner = var.expected_bucket_owner 36 | versioning_configuration { 37 | status = var.versioning_enabled ? "Enabled" : "Suspended" 38 | } 39 | } 40 | 41 | resource "aws_s3_bucket_logging" "this" { 42 | count = var.logging_enabled ? 1 : 0 43 | bucket = aws_s3_bucket.this.id 44 | expected_bucket_owner = var.expected_bucket_owner 45 | target_bucket = var.logging_target_bucket 46 | target_prefix = var.logging_target_prefix 47 | lifecycle { 48 | precondition { 49 | condition = var.logging_target_bucket != null 50 | error_message = "If logging is enabled logging_target_bucket must be set." 51 | } 52 | precondition { 53 | condition = var.logging_target_prefix != null 54 | error_message = "If logging is enabled logging_target_prefix must be set." 55 | } 56 | } 57 | } 58 | 59 | resource "aws_s3_bucket_server_side_encryption_configuration" "this" { 60 | count = var.enable_server_side_encryption ? 1 : 0 61 | bucket = aws_s3_bucket.this.id 62 | expected_bucket_owner = var.expected_bucket_owner 63 | rule { 64 | bucket_key_enabled = true 65 | apply_server_side_encryption_by_default { 66 | sse_algorithm = "aws:kms" 67 | kms_master_key_id = var.kms_master_key_id 68 | } 69 | } 70 | } 71 | 72 | resource "aws_s3_bucket_replication_configuration" "this" { 73 | count = var.enable_replication ? 1 : 0 74 | bucket = aws_s3_bucket.this.id 75 | role = var.replication_role 76 | token = var.replication_token 77 | rule { 78 | status = "Enabled" 79 | destination { 80 | bucket = var.replication_target_bucket 81 | storage_class = "STANDARD" 82 | } 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /modules/aws-ipam/README.md: -------------------------------------------------------------------------------- 1 | # aws-ipam 2 | 3 | 4 | 5 | 8 | 9 | ## Example 10 | 11 | ```hcl 12 | /** 13 | * Examples should illustrate typical use cases. 14 | * For multiple examples each should have its own directory. 15 | * 16 | * > Running module examples uses a local state file. 17 | * > If you delete the .terraform directory the resources 18 | * > will be orphaned. 19 | */ 20 | 21 | provider "aws" { 22 | default_tags { 23 | tags = { 24 | terraformed = "true" 25 | example = "simple" 26 | module = "aws-ipam" 27 | } 28 | } 29 | } 30 | 31 | module "this" { 32 | source = "../../" 33 | root_cidr = "10.0.0.0/8" 34 | } 35 | 36 | output "result" { 37 | description = <<-EOT 38 | The result of the module. 39 | EOT 40 | value = module.this.result 41 | } 42 | ``` 43 | 44 | 45 | ## Modules 46 | 47 | No modules. 48 | 49 | ## Providers 50 | 51 | | Name | Version | 52 | |------|---------| 53 | | [aws](#provider\_aws) | ~>5.0 | 54 | 55 | ## Requirements 56 | 57 | | Name | Version | 58 | |------|---------| 59 | | [terraform](#requirement\_terraform) | ~>1.5 | 60 | | [aws](#requirement\_aws) | ~>5.0 | 61 | 62 | ## Resources 63 | 64 | | Name | Type | 65 | |------|------| 66 | | [aws_ram_principal_association.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ram_principal_association) | resource | 67 | | [aws_ram_resource_association.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ram_resource_association) | resource | 68 | | [aws_ram_resource_share.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ram_resource_share) | resource | 69 | | [aws_vpc_ipam.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc_ipam) | resource | 70 | | [aws_vpc_ipam_pool.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc_ipam_pool) | resource | 71 | | [aws_vpc_ipam_pool_cidr.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc_ipam_pool_cidr) | resource | 72 | | [aws_organizations_organization.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/organizations_organization) | data source | 73 | | [aws_region.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/region) | data source | 74 | 75 | ## Inputs 76 | 77 | | Name | Description | Type | Default | Required | 78 | |------|-------------|------|---------|:--------:| 79 | | [root\_cidr](#input\_root\_cidr) | Top level CIDR. | `string` | n/a | yes | 80 | | [ipam\_regions](#input\_ipam\_regions) | List of regions to enable the IPAM in. The region of the provider is
automatically included. | `list(string)` | `[]` | no | 81 | 82 | ## Outputs 83 | 84 | | Name | Description | 85 | |------|-------------| 86 | | [result](#output\_result) | The result of the module. | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /modules/aws-ec2-asg/variables.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * 5 | */ 6 | 7 | variable "name" { 8 | type = string 9 | description = <<-EOT 10 | The name of the ASG. 11 | This value is used as the basis for naming various other resources. 12 | If this value is not specified a random name will be generated. 13 | EOT 14 | } 15 | 16 | variable "instance_role_policies" { 17 | type = list(string) 18 | description = <<-EOT 19 | IAM Policy ARNs to attach to the instance profile. 20 | EOT 21 | default = [ 22 | "arn:aws:iam::aws:policy/service-role/AmazonEC2RoleforAWSCodeDeploy", 23 | "arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy", 24 | "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore", 25 | "arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess", 26 | "arn:aws:iam::aws:policy/CloudWatchLogsFullAccess" 27 | ] 28 | } 29 | 30 | variable "ami_id" { 31 | type = string 32 | description = <<-EOT 33 | AMI ID for instances created by the ASG. 34 | Conflicts with `ami_ssm_parameter`. 35 | EOT 36 | default = null 37 | } 38 | 39 | variable "ami_ssm_parameter" { 40 | type = string 41 | description = <<-EOT 42 | Name of SSM parameter that contains the AMI ID to use. 43 | ex. "/aws/service/ecs/optimized-ami/amazon-linux-2/recommended" 44 | Conflicts with `ami_id`. 45 | EOT 46 | default = null 47 | } 48 | 49 | variable "instance_type" { 50 | type = string 51 | description = <<-EOT 52 | Instance type 53 | EOT 54 | default = "t2.micro" 55 | } 56 | 57 | variable "user_data" { 58 | type = string 59 | description = <<-EOT 60 | Instance User Data. 61 | See: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/user-data.html 62 | EOT 63 | default = null 64 | } 65 | 66 | variable "security_group_ids" { 67 | type = list(string) 68 | description = <<-EOT 69 | Security groups to attach to the managed instances. 70 | EOT 71 | default = null 72 | } 73 | 74 | variable "aws_packages" { 75 | type = list(string) 76 | description = <<-EOT 77 | List of AWS packages to deploy via SSM. 78 | EOT 79 | default = [ 80 | "AWSCodeDeployAgent", 81 | "AmazonCloudWatchAgent" 82 | ] 83 | } 84 | 85 | variable "target_group_arns" { 86 | type = list(string) 87 | description = <<-EOT 88 | Load balancer targets to register with. 89 | EOT 90 | default = null 91 | } 92 | 93 | variable "subnet_ids" { 94 | type = list(string) 95 | description = <<-EOT 96 | Subnets to deploy instances in. 97 | EOT 98 | } 99 | 100 | variable "min_size" { 101 | type = number 102 | description = <<-EOT 103 | Minimum number of instances to create. 104 | EOT 105 | default = 1 106 | } 107 | 108 | variable "max_size" { 109 | type = number 110 | description = <<-EOT 111 | Maximum number of instances to create. 112 | EOT 113 | default = 1 114 | } 115 | 116 | variable "cloudwatch_config" { 117 | type = string 118 | description = <<-EOT 119 | Cloudwatch config file contents. 120 | EOT 121 | default = null 122 | } 123 | 124 | variable "root_volume_size" { 125 | type = number 126 | description = <<-EOT 127 | Size in GB of root volume size. 128 | EOT 129 | default = 100 130 | } 131 | 132 | variable "instance_tags" { 133 | type = map(string) 134 | description = <<-EOT 135 | Tags to apply to instances. 136 | Use the provider `default_tags` feature for more consistent tagging. 137 | EOT 138 | default = {} 139 | } 140 | -------------------------------------------------------------------------------- /.github/workflows/terratest.yaml: -------------------------------------------------------------------------------- 1 | name: Integration Tests 2 | on: 3 | push: 4 | branches: 5 | - '**' 6 | - '!main' 7 | jobs: 8 | get-changes: 9 | if: ${{ true }} # Set this to false to disable tests. 10 | name: Get Changed Modules 11 | runs-on: ubuntu-latest 12 | outputs: 13 | changed-modules: ${{ steps.set-matrix.outputs.matrix }} 14 | steps: 15 | - uses: actions/checkout@v1 16 | - name: Get changed modules 17 | id: changed-modules 18 | uses: tj-actions/changed-files@v23.1 19 | with: 20 | files: modules/ 21 | dir_names: true 22 | - name: Set Matrix 23 | id: set-matrix 24 | run: | 25 | export _changed="${{ steps.changed-modules.outputs.all_changed_files }}" 26 | echo "_changed=${_changed}" 27 | _matrix="{\"changed-modules\":[$(printf "\"%s\"," ${_changed[@]}|sed 's/,$//')]}" 28 | # Filter out subdirectories 29 | export _matrix=$(echo "${_matrix}" | jq -c '."changed-modules" | map(select(test("^modules\/[a-z0-9-]*$"))) | unique | {"changed-modules":.}') 30 | echo "${_matrix}" | jq 31 | echo "::set-output name=matrix::${_matrix}" 32 | run-tests: 33 | needs: [get-changes] 34 | if: toJSON(fromJSON(needs.get-changes.outputs.changed-modules).changed-modules) != '[]' 35 | name: Run Terratest Tests 36 | runs-on: ubuntu-latest 37 | permissions: 38 | contents: 'read' 39 | id-token: 'write' 40 | strategy: 41 | matrix: 42 | changed-modules: ${{ fromJSON(needs.get-changes.outputs.changed-modules).changed-modules }} 43 | terraform-versions: ["latest"] # Add versions here to test against them. 44 | steps: 45 | - uses: actions/checkout@v1 46 | - name: Check for Tests 47 | id: check-tests 48 | run: | 49 | echo "${{ matrix.changed-modules }}" 50 | if [[ -d "${{ matrix.changed-modules }}/test" ]]; then 51 | echo "::set-output name=tests-exist::true" 52 | else 53 | echo "No tests detected." 54 | echo "::set-output name=tests-exist::false" 55 | fi 56 | - uses: actions/setup-go@v1 57 | if: steps.check-tests.outputs.tests-exist == 'true' 58 | with: 59 | go-version: 1.13 60 | - name: Install tfenv 61 | uses: rhythmictech/actions-setup-tfenv@v0.0.3 62 | if: steps.check-tests.outputs.tests-exist == 'true' 63 | - name: Setup Terraform. 64 | if: steps.check-tests.outputs.tests-exist == 'true' 65 | run: | 66 | if [[ ${{matrix.terraform-versions}} == 'latest' ]]; then 67 | _latest=$(tfenv list-remote | head -n 1) 68 | tfenv install $_latest 69 | tfenv use $_latest 70 | else 71 | tfenv install ${{matrix.terraform-versions}} 72 | tfenv use ${{matrix.terraform-versions}} 73 | fi 74 | - name: Run Go Tests 75 | if: steps.check-tests.outputs.tests-exist == 'true' 76 | working-directory: ${{ matrix.changed-modules }}/test 77 | run: go test -v -tags integration 78 | success: 79 | needs: [run-tests] 80 | name: Check Success 81 | runs-on: ubuntu-latest 82 | if: always() 83 | steps: 84 | - id: report 85 | name: Report 86 | run: | 87 | case "${{ toJSON(needs.run-tests.result) }}" in 88 | "success") 89 | echo "Success: All tests passed." 90 | exit 0 91 | ;; 92 | "skipped") 93 | echo "Warning: Tests skipped." 94 | exit 0 95 | ;; 96 | *) 97 | echo "Error: Test status was $_status." 98 | exit 1 99 | ;; 100 | esac 101 | -------------------------------------------------------------------------------- /modules/aws-s3-bucket/variables.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * 5 | */ 6 | 7 | variable "bucket" { 8 | type = string 9 | description = <<-EOT 10 | The name of the S3 bucket to create 11 | EOT 12 | default = null 13 | } 14 | 15 | variable "bucket_prefix" { 16 | type = string 17 | description = <<-EOT 18 | The prefix to use for the S3 bucket name 19 | EOT 20 | default = null 21 | } 22 | 23 | variable "force_destroy" { 24 | type = bool 25 | description = <<-EOT 26 | Force destroy the bucket if it exists 27 | EOT 28 | default = false 29 | } 30 | 31 | variable "object_lock_enabled" { 32 | type = bool 33 | description = <<-EOT 34 | Enable object lock for the bucket 35 | EOT 36 | default = false 37 | } 38 | 39 | variable "tags" { 40 | type = map(any) 41 | description = <<-EOT 42 | Tags to apply to the bucket 43 | EOT 44 | default = null 45 | } 46 | variable "block_public_acls" { 47 | type = bool 48 | description = <<-EOT 49 | Block public access to the bucket 50 | EOT 51 | default = true 52 | } 53 | 54 | variable "block_public_policy" { 55 | type = bool 56 | description = <<-EOT 57 | Block public policy access to the bucket 58 | EOT 59 | default = true 60 | } 61 | 62 | variable "ignore_public_acls" { 63 | type = bool 64 | description = <<-EOT 65 | Ignore public acls for the bucket 66 | EOT 67 | default = true 68 | } 69 | 70 | variable "restrict_public_buckets" { 71 | type = bool 72 | description = <<-EOT 73 | Restrict public access to the bucket 74 | EOT 75 | default = true 76 | } 77 | 78 | variable "versioning_enabled" { 79 | type = bool 80 | description = <<-EOT 81 | Enable versioning for the bucket 82 | EOT 83 | default = true 84 | } 85 | 86 | variable "expected_bucket_owner" { 87 | type = string 88 | description = <<-EOT 89 | The expected owner of the bucket 90 | EOT 91 | default = null 92 | } 93 | 94 | variable "logging_enabled" { 95 | type = bool 96 | description = <<-EOT 97 | Enable logging for the bucket 98 | EOT 99 | default = true 100 | } 101 | 102 | variable "logging_target_bucket" { 103 | type = string 104 | description = <<-EOT 105 | The target bucket for the logging configuration 106 | EOT 107 | default = null 108 | } 109 | variable "logging_target_prefix" { 110 | type = string 111 | description = <<-EOT 112 | The target prefix for the logging configuration 113 | EOT 114 | default = null 115 | } 116 | 117 | variable "enable_server_side_encryption" { 118 | type = bool 119 | description = <<-EOT 120 | Enable server side encryption for the bucket 121 | EOT 122 | default = true 123 | } 124 | 125 | variable "kms_master_key_id" { 126 | type = string 127 | description = <<-EOT 128 | The KMS key id to use for encryption 129 | EOT 130 | default = null 131 | } 132 | 133 | variable "enable_replication" { 134 | type = bool 135 | description = <<-EOT 136 | Enable replication for the bucket 137 | EOT 138 | default = true 139 | } 140 | 141 | variable "replication_role" { 142 | type = string 143 | description = <<-EOT 144 | The role ARN to use for replication 145 | EOT 146 | default = null 147 | } 148 | 149 | variable "replication_target_bucket" { 150 | type = string 151 | description = <<-EOT 152 | The target bucket to use for replication 153 | EOT 154 | default = null 155 | } 156 | 157 | variable "replication_token" { 158 | type = string 159 | description = <<-EOT 160 | The token to use for replication 161 | EOT 162 | default = null 163 | } 164 | -------------------------------------------------------------------------------- /modules/aws-tgw/README.md: -------------------------------------------------------------------------------- 1 | # aws-tgw 2 | 3 | 4 | 5 | 8 | 9 | ## Example 10 | 11 | ```hcl 12 | 13 | provider "aws" { 14 | default_tags { 15 | tags = { 16 | Name = "aws-tgw-module-example" 17 | } 18 | } 19 | } 20 | 21 | data "aws_availability_zones" "available" { 22 | state = "available" 23 | } 24 | 25 | locals { 26 | availability_zones = slice(data.aws_availability_zones.available.names, 0, 2) 27 | } 28 | 29 | module "this" { 30 | source = "../../" 31 | vpc_cidr = "172.16.0.0/16" 32 | vpc_name = "example" 33 | client_cidrs = ["10.0.0.0/8"] 34 | availability_zones = local.availability_zones 35 | subnets_netmask_length = 20 36 | } 37 | 38 | output "result" { 39 | description = <<-EOT 40 | The result of the module. 41 | EOT 42 | value = module.this.result 43 | } 44 | ``` 45 | 46 | 47 | ## Modules 48 | 49 | | Name | Source | Version | 50 | |------|--------|---------| 51 | | [vpc](#module\_vpc) | ../aws-vpc | n/a | 52 | 53 | ## Providers 54 | 55 | | Name | Version | 56 | |------|---------| 57 | | [aws](#provider\_aws) | ~>5.0 | 58 | 59 | ## Requirements 60 | 61 | | Name | Version | 62 | |------|---------| 63 | | [terraform](#requirement\_terraform) | ~>1.5 | 64 | | [aws](#requirement\_aws) | ~>5.0 | 65 | 66 | ## Resources 67 | 68 | | Name | Type | 69 | |------|------| 70 | | [aws_ec2_transit_gateway.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ec2_transit_gateway) | resource | 71 | | [aws_ec2_transit_gateway_route.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ec2_transit_gateway_route) | resource | 72 | | [aws_ec2_transit_gateway_vpc_attachment.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ec2_transit_gateway_vpc_attachment) | resource | 73 | | [aws_ram_principal_association.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ram_principal_association) | resource | 74 | | [aws_ram_resource_association.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ram_resource_association) | resource | 75 | | [aws_ram_resource_share.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ram_resource_share) | resource | 76 | | [aws_route.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route) | resource | 77 | | [aws_organizations_organization.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/organizations_organization) | data source | 78 | 79 | ## Inputs 80 | 81 | | Name | Description | Type | Default | Required | 82 | |------|-------------|------|---------|:--------:| 83 | | [availability\_zones](#input\_availability\_zones) | Availability zones to create resources in. | `list(string)` | n/a | yes | 84 | | [client\_cidrs](#input\_client\_cidrs) | Client CIDR blocks to route. | `list(string)` | n/a | yes | 85 | | [subnets\_netmask\_length](#input\_subnets\_netmask\_length) | Number of subnet bits for subnets. | `number` | n/a | yes | 86 | | [vpc\_cidr](#input\_vpc\_cidr) | CIDR block for VPC | `string` | n/a | yes | 87 | | [vpc\_name](#input\_vpc\_name) | Name of the VPC. | `string` | n/a | yes | 88 | 89 | ## Outputs 90 | 91 | | Name | Description | 92 | |------|-------------| 93 | | [result](#output\_result) | The result of the module. | 94 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /modules/aws-ecs-cluster/README.md: -------------------------------------------------------------------------------- 1 | # aws-ecs-cluster 2 | 3 | 4 | 5 | 8 | 9 | ## Example 10 | 11 | ```hcl 12 | locals { 13 | name = "module-ecs-example" 14 | } 15 | 16 | provider "aws" { 17 | default_tags { 18 | tags = { 19 | Terraformed = true 20 | Environment = "test" 21 | Name = local.name 22 | } 23 | } 24 | } 25 | 26 | data "aws_availability_zones" "available" { 27 | state = "available" 28 | } 29 | 30 | locals { 31 | availability_zones = slice(data.aws_availability_zones.available.names, 0, 2) 32 | } 33 | 34 | module "vpc" { 35 | source = "../../../aws-vpc" 36 | name = local.name 37 | vpc_ip_address = "10.97.0.0" 38 | vpc_netmask_length = 16 39 | availability_zones = local.availability_zones 40 | subnets_netmask_length = 20 41 | create_public_subnets = true 42 | create_nat_gateways = true 43 | } 44 | 45 | module "asg" { 46 | source = "../../../aws-ec2-asg" 47 | name = local.name 48 | subnet_ids = [for subnet in module.vpc.result.private_subnets : subnet.id] 49 | ami_ssm_parameter = "/aws/service/ecs/optimized-ami/amazon-linux-2/recommended" 50 | instance_role_policies = [ 51 | "arn:aws:iam::aws:policy/service-role/AmazonEC2ContainerServiceforEC2Role", 52 | "arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy", 53 | "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore", 54 | "arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess", 55 | "arn:aws:iam::aws:policy/CloudWatchLogsFullAccess" 56 | ] 57 | user_data = templatefile("user_data.sh.tftpl", { name = local.name }) 58 | instance_tags = { 59 | AmazonECSManaged = true 60 | } 61 | } 62 | 63 | module "this" { 64 | source = "../.." 65 | name = local.name 66 | autoscaling_group_arn = module.asg.result.autoscaling_group.arn 67 | } 68 | 69 | output "result" { 70 | description = <<-EOT 71 | The result of the module. 72 | EOT 73 | value = module.this.result 74 | } 75 | ``` 76 | 77 | 78 | ## Modules 79 | 80 | No modules. 81 | 82 | ## Providers 83 | 84 | | Name | Version | 85 | |------|---------| 86 | | [aws](#provider\_aws) | ~>5.0 | 87 | 88 | ## Requirements 89 | 90 | | Name | Version | 91 | |------|---------| 92 | | [terraform](#requirement\_terraform) | ~>1.5 | 93 | | [aws](#requirement\_aws) | ~>5.0 | 94 | 95 | ## Resources 96 | 97 | | Name | Type | 98 | |------|------| 99 | | [aws_ecs_capacity_provider.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecs_capacity_provider) | resource | 100 | | [aws_ecs_cluster.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecs_cluster) | resource | 101 | | [aws_ecs_cluster_capacity_providers.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecs_cluster_capacity_providers) | resource | 102 | 103 | ## Inputs 104 | 105 | | Name | Description | Type | Default | Required | 106 | |------|-------------|------|---------|:--------:| 107 | | [autoscaling\_group\_arn](#input\_autoscaling\_group\_arn) | ARN of autoscaling group to associate with the cluster. | `string` | n/a | yes | 108 | | [name](#input\_name) | Name of ECS Cluster and other resources. | `string` | n/a | yes | 109 | 110 | ## Outputs 111 | 112 | | Name | Description | 113 | |------|-------------| 114 | | [result](#output\_result) | The result of the module. | 115 | 116 | 117 | 118 | -------------------------------------------------------------------------------- /modules/bananalab-ecs-service/variables.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * 5 | */ 6 | 7 | variable "name" { 8 | type = string 9 | description = <<-EOT 10 | The name of the resources created by this module. 11 | This value is used as the basis for naming various resources. 12 | EOT 13 | } 14 | 15 | variable "ecs_cluster_id" { 16 | type = string 17 | description = <<-EOT 18 | ECS Cluster to deploy to. 19 | EOT 20 | } 21 | 22 | variable "desired_count" { 23 | type = number 24 | description = <<-EOT 25 | The number of service replicas. 26 | EOT 27 | default = 2 28 | } 29 | 30 | variable "capacity_provider" { 31 | type = string 32 | description = <<-EOT 33 | ECS Capacity Provider to use. 34 | EOT 35 | } 36 | 37 | variable "container_definitions" { 38 | type = string 39 | description = <<-EOT 40 | A valid JSON document describing valid container definitions. 41 | See: http://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_ContainerDefinition.html 42 | EOT 43 | } 44 | 45 | variable "task_role_arn" { 46 | type = string 47 | description = <<-EOT 48 | The ARN of IAM role that allows your Amazon ECS container task to make 49 | calls to other AWS services. 50 | EOT 51 | default = null 52 | } 53 | 54 | variable "cpu" { 55 | type = number 56 | description = <<-EOT 57 | The number of cpu units used by the task. If the `requires_compatibilities` 58 | is "FARGATE" this field is required. 59 | EOT 60 | default = null 61 | } 62 | 63 | variable "memory" { 64 | type = number 65 | description = <<-EOT 66 | The amount (in MiB) of memory used by the task. If the 67 | `requires_compatibilities` is "FARGATE" this field is required. 68 | EOT 69 | default = null 70 | } 71 | 72 | variable "volumes" { 73 | type = map(any) 74 | description = <<-EOT 75 | List of volume configurations. 76 | EOT 77 | default = {} 78 | } 79 | 80 | variable "requires_compatibilities" { 81 | type = list(string) 82 | description = <<-EOT 83 | Set of launch types required by the task. The valid values are EC2 and 84 | FARGATE. 85 | EOT 86 | default = null 87 | } 88 | 89 | variable "task_tags" { 90 | type = map(string) 91 | description = <<-EOT 92 | Key-value map of resource tags. 93 | EOT 94 | default = null 95 | } 96 | 97 | variable "placement_constraints" { 98 | type = map(any) 99 | description = <<-EOT 100 | Configuration block for rules that are taken into consideration during task 101 | placement. Maximum number of `placement_constraints` is 10. 102 | EOT 103 | default = {} 104 | } 105 | 106 | variable "subnet_ids" { 107 | type = list(string) 108 | description = <<-EOT 109 | Subnets associated with the task or service. 110 | EOT 111 | } 112 | 113 | variable "load_balancer_arn" { 114 | type = string 115 | description = <<-EOT 116 | ARN of the loadbalancer to associate services with. 117 | EOT 118 | } 119 | 120 | variable "load_balancer_targets" { 121 | type = map(any) 122 | description = <<-EOT 123 | Load balancer target configs. 124 | EOT 125 | default = null 126 | } 127 | 128 | variable "fqdn" { 129 | type = string 130 | description = <<-EOT 131 | Fully qualified domain name of load balanced service. 132 | EOT 133 | } 134 | 135 | variable "url_rewrites" { 136 | type = map(any) 137 | description = <<-EOT 138 | A mapping of fqdns and rewrite rules. 139 | e.x.: 140 | { 141 | foo.dev-empire.com = "https://www.empi.re/listen/index.php?id=$1" 142 | } 143 | EOT 144 | default = {} 145 | } 146 | 147 | variable "dns_routing_weight" { 148 | type = number 149 | description = <<-EOT 150 | The weight can be a number between 0 and 255. If you specify 0, Route 53 151 | stops responding to DNS queries using this record. 152 | EOT 153 | default = 255 154 | } 155 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Terraform Modules 2 | 3 | This repository contains Terraform Modules for use in configurations. 4 | 5 | ## Developing a module 6 | 7 | ### Development Environment 8 | 9 | This project uses [devcontainers](https://containers.dev/) to provide a 10 | consistent developer experience. All required tools and settings are defined 11 | in the devcontainer config file `.devcontainer/devcontainer.json`. 12 | 13 | ### Create a new module 14 | 15 | From the project root run `make module `. The new module 16 | can be found under the `modules` directory. 17 | 18 | The make target creates a complete skeleton module for you. You can cd into 19 | the module directory and run `make test`. The example should run without error. 20 | Once you have verified that the skeleton project works you can begin coding 21 | it's functionality. 22 | 23 | #### Module Layout 24 | 25 | The template module is based on 26 | [this](https://www.terraform.io/language/modules/develop/structure) article. 27 | There are a few modifications (`test/` and `versions.tf`). This layout is the 28 | minimum... you may need to add to it. For example you might create a 29 | `modules/` directory to contain embedded submodules. 30 | 31 | ```text 32 | terraform-my-module 33 | ├── examples < - Example usage of the module goes here. 34 | │ └── simple All modules should include at least one. 35 | │ └── main.tf 36 | ├── main.tf < - The main functionality of the module goes here. 37 | ├── outputs.tf < - Module outputs. 38 | ├── test < - Terratest tests go here. 39 | │ ├── go.mod 40 | │ ├── go.sum 41 | │ └── integration_test.go 42 | ├── variables.tf < - Module variables go here. 43 | └── versions.tf < - Module requirements go here. 44 | ``` 45 | 46 | ### Documentation 47 | 48 | This repo uses `terraform-docs` via `pre-commit` to automatically generate 49 | documentation of variables, outputs, and requirements. Additionally you should 50 | provide guidance by editing the header section of the module's `main.tf` file. 51 | The skeleton includes a header comment that looks like this: 52 | 53 | ```text 54 | /** 55 | * 5 | */ 6 | 7 | locals { 8 | name = var.name 9 | ami_id = var.ami_id != null ? var.ami_id : jsondecode(data.aws_ssm_parameter.ami_id[0].value)["image_id"] 10 | user_data_b64 = var.user_data == null ? null : base64encode(var.user_data) 11 | subnet_ids = var.subnet_ids 12 | cloudwatch_config = var.cloudwatch_config != null ? var.cloudwatch_config : templatefile("${path.module}/cloudwatch-config.tftpl", { autoscaling_group_name = aws_autoscaling_group.this.name }) 13 | } 14 | 15 | data "aws_ssm_parameter" "ami_id" { 16 | count = var.ami_id == null ? 1 : 0 17 | name = var.ami_ssm_parameter 18 | } 19 | 20 | data "aws_iam_policy_document" "this" { 21 | statement { 22 | actions = ["sts:AssumeRole"] 23 | 24 | principals { 25 | type = "Service" 26 | identifiers = ["ec2.amazonaws.com"] 27 | } 28 | } 29 | } 30 | 31 | resource "aws_iam_role" "this" { 32 | name = "${local.name}-InstanceProfile" 33 | path = "/system/" 34 | assume_role_policy = data.aws_iam_policy_document.this.json 35 | } 36 | 37 | resource "aws_iam_role_policy_attachment" "this" { 38 | for_each = toset(var.instance_role_policies) 39 | role = aws_iam_role.this.name 40 | policy_arn = each.value 41 | } 42 | 43 | resource "aws_iam_instance_profile" "this" { 44 | role = aws_iam_role.this.name 45 | } 46 | 47 | resource "aws_launch_template" "this" { 48 | #checkov:skip=CKV_AWS_46:N/A 49 | image_id = local.ami_id 50 | instance_type = var.instance_type 51 | name = local.name 52 | user_data = local.user_data_b64 53 | 54 | vpc_security_group_ids = var.security_group_ids 55 | 56 | iam_instance_profile { 57 | arn = aws_iam_instance_profile.this.arn 58 | } 59 | 60 | block_device_mappings { 61 | device_name = "/dev/xvda" 62 | ebs { 63 | volume_size = var.root_volume_size 64 | } 65 | } 66 | 67 | metadata_options { 68 | http_endpoint = "enabled" 69 | http_tokens = "required" 70 | } 71 | } 72 | 73 | resource "aws_ssm_association" "configure_aws_packages" { 74 | for_each = toset(var.aws_packages) 75 | name = "AWS-ConfigureAWSPackage" 76 | schedule_expression = "cron(0 2 ? * SUN *)" 77 | targets { 78 | key = "tag:aws:autoscaling:groupName" 79 | values = [ 80 | aws_autoscaling_group.this.name 81 | ] 82 | } 83 | parameters = { 84 | "action" = "Install" 85 | "name" = each.value 86 | } 87 | } 88 | 89 | resource "aws_ssm_parameter" "cloudwatch_config" { 90 | #checkov:skip=CKV_AWS_337: TODO: Ensure SSM parameters are using KMS CMK. 91 | name = "/${local.name}/cloudwatch-config" 92 | type = "SecureString" 93 | value = local.cloudwatch_config 94 | } 95 | 96 | resource "aws_ssm_association" "cloudwatch_manage_agent" { 97 | # TODO: This tries to apply before the Cloudwatch Agent is installed 98 | # so it fails. It works at the next 30 minute interval but that 99 | # leaves a 30 minute gap every time a new instance launches. 100 | count = contains(var.aws_packages, "AmazonCloudWatchAgent") ? 1 : 0 101 | name = "AmazonCloudWatch-ManageAgent" 102 | schedule_expression = "rate(30 minutes)" 103 | targets { 104 | key = "tag:aws:autoscaling:groupName" 105 | values = [ 106 | aws_autoscaling_group.this.name 107 | ] 108 | } 109 | parameters = { 110 | "optionalConfigurationLocation" = aws_ssm_parameter.cloudwatch_config.name 111 | } 112 | } 113 | 114 | resource "aws_autoscaling_group" "this" { 115 | name = local.name 116 | max_size = var.max_size 117 | min_size = var.min_size 118 | vpc_zone_identifier = local.subnet_ids 119 | target_group_arns = var.target_group_arns 120 | protect_from_scale_in = false 121 | 122 | launch_template { 123 | id = aws_launch_template.this.id 124 | version = aws_launch_template.this.latest_version 125 | } 126 | 127 | dynamic "tag" { 128 | for_each = var.instance_tags 129 | content { 130 | key = tag.key 131 | value = tag.value 132 | propagate_at_launch = true 133 | } 134 | } 135 | 136 | tag { 137 | key = "Name" 138 | value = local.name 139 | propagate_at_launch = true 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /modules/bananalab-platform/README.md: -------------------------------------------------------------------------------- 1 | # bananalab-platform 2 | 3 | 4 | 5 | 8 | 9 | ## Example 10 | 11 | ```hcl 12 | /** 13 | * Examples should illustrate typical use cases. 14 | * For multiple examples each should have its own directory. 15 | * 16 | * > Running module examples uses a local state file. 17 | * > If you delete the .terraform directory the resources 18 | * > will be orphaned. 19 | */ 20 | 21 | locals { 22 | name = terraform.workspace 23 | domain_name = "bananalab.dev" 24 | availability_zones = slice(data.aws_availability_zones.available.names, 0, 2) 25 | asg_min_instances = length(local.availability_zones) 26 | } 27 | 28 | provider "aws" { 29 | default_tags { 30 | tags = { 31 | terraformed = "true" 32 | example = "simple" 33 | module = "bananalab-platform" 34 | } 35 | } 36 | } 37 | 38 | data "aws_availability_zones" "available" { 39 | state = "available" 40 | } 41 | 42 | module "this" { 43 | source = "../../" 44 | name = local.name 45 | availability_zones = local.availability_zones 46 | domain_name = local.domain_name 47 | asg_min_instances = local.asg_min_instances 48 | boot_script = templatefile("${path.module}/boot_script.sh.tftpl", {}) 49 | } 50 | 51 | output "result" { 52 | description = <<-EOT 53 | The result of the module. 54 | EOT 55 | value = module.this.result 56 | } 57 | ``` 58 | 59 | 60 | ## Modules 61 | 62 | | Name | Source | Version | 63 | |------|--------|---------| 64 | | [alb](#module\_alb) | ../aws-https-alb | n/a | 65 | | [asg](#module\_asg) | ../aws-ec2-asg | n/a | 66 | | [ecs](#module\_ecs) | ../aws-ecs-cluster | n/a | 67 | | [log\_bucket](#module\_log\_bucket) | ../aws-s3-bucket | n/a | 68 | | [vpc](#module\_vpc) | ../aws-vpc | n/a | 69 | 70 | ## Providers 71 | 72 | | Name | Version | 73 | |------|---------| 74 | | [aws](#provider\_aws) | ~>5.0 | 75 | 76 | ## Requirements 77 | 78 | | Name | Version | 79 | |------|---------| 80 | | [terraform](#requirement\_terraform) | ~>1.5.0 | 81 | | [aws](#requirement\_aws) | ~>5.0 | 82 | 83 | ## Resources 84 | 85 | | Name | Type | 86 | |------|------| 87 | | [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source | 88 | 89 | ## Inputs 90 | 91 | | Name | Description | Type | Default | Required | 92 | |------|-------------|------|---------|:--------:| 93 | | [availability\_zones](#input\_availability\_zones) | Availability zones to create resources in. | `list(string)` | n/a | yes | 94 | | [domain\_name](#input\_domain\_name) | Name of existing Route53 domain to use. | `string` | n/a | yes | 95 | | [name](#input\_name) | The name of the resources created by this module.
This value is used as the basis for naming various resources. | `string` | n/a | yes | 96 | | [asg\_instance\_type](#input\_asg\_instance\_type) | EC2 instance type to use in the autoscaling group. | `string` | `"m6i.4xlarge"` | no | 97 | | [asg\_max\_instances](#input\_asg\_max\_instances) | Maximum number of instances in the autoscaling group. If this is less than
`asg_min_instances` then `asg_min_instances` will be used. | `number` | `1` | no | 98 | | [asg\_min\_instances](#input\_asg\_min\_instances) | Minimum number of instances in the autoscaling group. | `number` | `1` | no | 99 | | [asg\_root\_volume\_size](#input\_asg\_root\_volume\_size) | Size in GB of root volume. | `number` | `1000` | no | 100 | | [boot\_script](#input\_boot\_script) | Content of shell script to execute at EC2 boot.
Do not include plain text secrets. | `string` | `null` | no | 101 | | [ecs\_agent\_config](#input\_ecs\_agent\_config) | Key / Value pairs of ECS Agent environment variables.
See: https://github.com/aws/amazon-ecs-agent/blob/master/README.md#environment-variables
For options.
ECS\_CLUSTER is set by default. | `map(string)` | `{}` | no | 102 | 103 | ## Outputs 104 | 105 | | Name | Description | 106 | |------|-------------| 107 | | [result](#output\_result) | The result of the module. | 108 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /modules/aws-vpc/main.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * 5 | */ 6 | 7 | 8 | locals { 9 | new_bits = var.subnets_netmask_length - var.vpc_netmask_length 10 | private_subnet_names = [for az in var.availability_zones : "${az}_private"] 11 | public_subnet_names = [for az in var.availability_zones : "${az}_public"] 12 | public_subnets = { for network in module.subnet_addrs.networks : trimsuffix(network.name, "_public") => network.cidr_block if endswith(network.name, "public") } 13 | private_subnets = { for network in module.subnet_addrs.networks : trimsuffix(network.name, "_private") => network.cidr_block if endswith(network.name, "private") } 14 | networks = [for subnet in concat(local.private_subnet_names, local.public_subnet_names) : { "new_bits" : local.new_bits, "name" : subnet }] 15 | base_cidr_block = var.ipam_pool_id == null ? "${var.vpc_ip_address}/${var.vpc_netmask_length}" : aws_vpc.this.cidr_block 16 | } 17 | 18 | module "subnet_addrs" { 19 | #checkov:skip=CKV_TF_1:Not applicable 20 | source = "hashicorp/subnets/cidr" 21 | version = "~> 1.0" 22 | base_cidr_block = local.base_cidr_block 23 | networks = local.networks 24 | } 25 | 26 | resource "aws_vpc" "this" { 27 | #checkov:skip=CKV2_AWS_11:TODO: Support flow logging 28 | #checkov:skip=CKV2_AWS_12:TODO: Restrict default SG 29 | cidr_block = var.ipam_pool_id == null ? "${var.vpc_ip_address}/${var.vpc_netmask_length}" : null 30 | ipv4_ipam_pool_id = var.ipam_pool_id == null ? null : var.ipam_pool_id 31 | ipv4_netmask_length = var.ipam_pool_id == null ? null : var.vpc_netmask_length 32 | tags = { 33 | Name = var.name 34 | } 35 | } 36 | 37 | resource "aws_internet_gateway" "this" { 38 | count = var.create_public_subnets ? 1 : 0 39 | vpc_id = aws_vpc.this.id 40 | } 41 | 42 | resource "aws_subnet" "public" { 43 | for_each = var.create_public_subnets ? local.public_subnets : {} 44 | vpc_id = aws_vpc.this.id 45 | cidr_block = each.value 46 | availability_zone = each.key 47 | #checkov:skip=CKV_AWS_130:Public subnet 48 | map_public_ip_on_launch = true 49 | tags = { 50 | Name = "${each.key}-public" 51 | Tier = "Public" 52 | } 53 | } 54 | 55 | resource "aws_route_table" "public" { 56 | count = var.create_public_subnets ? 1 : 0 57 | vpc_id = aws_vpc.this.id 58 | tags = { 59 | Tier = "Public" 60 | } 61 | } 62 | 63 | resource "aws_route" "public" { 64 | count = var.create_public_subnets ? 1 : 0 65 | route_table_id = aws_route_table.public[0].id 66 | destination_cidr_block = "0.0.0.0/0" 67 | gateway_id = aws_internet_gateway.this[0].id 68 | } 69 | 70 | resource "aws_route_table_association" "public" { 71 | for_each = var.create_public_subnets ? aws_subnet.public : {} 72 | subnet_id = each.value.id 73 | route_table_id = aws_route_table.public[0].id 74 | } 75 | 76 | resource "aws_nat_gateway" "this" { 77 | for_each = var.create_nat_gateways ? aws_subnet.public : {} 78 | allocation_id = aws_eip.nat[each.key].id 79 | subnet_id = each.value.id 80 | depends_on = [aws_internet_gateway.this] 81 | } 82 | 83 | resource "aws_eip" "nat" { 84 | # checkov:skip=CKV2_AWS_19: Attached using allocation_id in NAT GWs 85 | for_each = var.create_nat_gateways ? aws_subnet.public : {} 86 | domain = "vpc" 87 | } 88 | 89 | # Private subnet config 90 | 91 | resource "aws_subnet" "private" { 92 | for_each = local.private_subnets 93 | vpc_id = aws_vpc.this.id 94 | cidr_block = each.value 95 | availability_zone = each.key 96 | tags = { 97 | Name = "${each.key}-private" 98 | Tier = "Private" 99 | } 100 | } 101 | 102 | resource "aws_route_table" "private" { 103 | for_each = aws_subnet.private 104 | vpc_id = aws_vpc.this.id 105 | tags = { 106 | Tier = "Private" 107 | } 108 | } 109 | 110 | resource "aws_route" "nat_gw" { 111 | for_each = var.create_nat_gateways ? aws_route_table.private : {} 112 | route_table_id = each.value.id 113 | destination_cidr_block = "0.0.0.0/0" 114 | nat_gateway_id = aws_nat_gateway.this[each.key].id 115 | } 116 | 117 | resource "aws_route_table_association" "nat_gw" { 118 | for_each = var.create_nat_gateways ? aws_route.nat_gw : {} 119 | subnet_id = aws_subnet.private[each.key].id 120 | route_table_id = aws_route_table.private[each.key].id 121 | } 122 | 123 | resource "aws_ec2_transit_gateway_vpc_attachment" "this" { 124 | count = var.attach_transit_gateway ? 1 : 0 125 | subnet_ids = [for subnet in aws_subnet.private : subnet.id] 126 | transit_gateway_id = var.transit_gateway_id 127 | vpc_id = aws_vpc.this.id 128 | } 129 | 130 | resource "aws_route" "transit_gw" { 131 | for_each = var.attach_transit_gateway ? aws_route_table.private : {} 132 | route_table_id = each.value.id 133 | destination_cidr_block = "0.0.0.0/0" 134 | transit_gateway_id = var.transit_gateway_id 135 | } 136 | 137 | resource "aws_route_table_association" "transit_gw" { 138 | for_each = var.attach_transit_gateway ? aws_route.transit_gw : {} 139 | subnet_id = aws_subnet.private[each.key].id 140 | route_table_id = aws_route_table.private[each.key].id 141 | } 142 | -------------------------------------------------------------------------------- /modules/aws-https-alb/main.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * 5 | */ 6 | 7 | locals { 8 | fqdn = "${var.application_host}.${var.domain_name}" 9 | } 10 | 11 | resource "aws_security_group" "alb" { 12 | # checkov:skip=CKV_AWS_260: N/A 13 | name = "${var.name}-allow_web_ports" 14 | description = "Allow web ports" 15 | vpc_id = var.vpc_id 16 | } 17 | 18 | resource "aws_vpc_security_group_ingress_rule" "http" { 19 | # checkov:skip=CKV_AWS_260: N/A 20 | security_group_id = aws_security_group.alb.id 21 | description = "HTTP from public" 22 | from_port = 80 23 | to_port = 80 24 | ip_protocol = "tcp" 25 | cidr_ipv4 = "0.0.0.0/0" 26 | } 27 | 28 | resource "aws_vpc_security_group_ingress_rule" "https" { 29 | security_group_id = aws_security_group.alb.id 30 | description = "HTTPS from public" 31 | from_port = 443 32 | to_port = 443 33 | ip_protocol = "tcp" 34 | cidr_ipv4 = "0.0.0.0/0" 35 | } 36 | 37 | resource "aws_vpc_security_group_ingress_rule" "intragroup" { 38 | security_group_id = aws_security_group.alb.id 39 | description = "Allow intragroup" 40 | ip_protocol = "-1" 41 | referenced_security_group_id = aws_security_group.alb.id 42 | } 43 | 44 | resource "aws_vpc_security_group_egress_rule" "allow_all" { 45 | security_group_id = aws_security_group.alb.id 46 | description = "Allow egress" 47 | ip_protocol = "-1" 48 | cidr_ipv4 = "0.0.0.0/0" 49 | } 50 | 51 | resource "aws_lb" "this" { 52 | # checkov:skip=CKV_AWS_150: N/A 53 | # checkov:skip=CKV2_AWS_28: Deletion protection isn't desired here 54 | name = var.name 55 | internal = false 56 | load_balancer_type = "application" 57 | security_groups = [aws_security_group.alb.id] 58 | subnets = var.subnet_ids 59 | drop_invalid_header_fields = true 60 | enable_deletion_protection = false 61 | idle_timeout = var.idle_timeout 62 | 63 | access_logs { 64 | bucket = var.log_bucket 65 | prefix = "${var.name}/alb" 66 | enabled = true 67 | } 68 | } 69 | 70 | resource "aws_lb_listener" "this" { 71 | load_balancer_arn = aws_lb.this.arn 72 | port = "80" 73 | protocol = "HTTP" 74 | 75 | default_action { 76 | type = "redirect" 77 | 78 | redirect { 79 | port = "443" 80 | protocol = "HTTPS" 81 | status_code = "HTTP_301" 82 | } 83 | } 84 | } 85 | 86 | resource "aws_lb_listener" "https" { 87 | load_balancer_arn = aws_lb.this.id 88 | port = 443 89 | protocol = "HTTPS" 90 | certificate_arn = aws_acm_certificate_validation.this.certificate_arn 91 | ssl_policy = "ELBSecurityPolicy-FS-1-2-Res-2020-10" 92 | 93 | default_action { 94 | type = "fixed-response" 95 | 96 | fixed_response { 97 | content_type = "text/html" 98 | message_body = "Not Found." 99 | status_code = "404" 100 | } 101 | } 102 | 103 | lifecycle { 104 | replace_triggered_by = [aws_acm_certificate.this] 105 | } 106 | } 107 | 108 | data "aws_route53_zone" "this" { 109 | name = var.domain_name 110 | } 111 | 112 | resource "aws_route53_record" "alb" { 113 | zone_id = data.aws_route53_zone.this.zone_id 114 | name = local.fqdn 115 | type = "A" 116 | 117 | alias { 118 | name = aws_lb.this.dns_name 119 | zone_id = aws_lb.this.zone_id 120 | evaluate_target_health = true 121 | } 122 | } 123 | 124 | resource "aws_acm_certificate" "this" { 125 | domain_name = local.fqdn 126 | validation_method = "DNS" 127 | 128 | lifecycle { 129 | create_before_destroy = true 130 | } 131 | } 132 | 133 | resource "aws_route53_record" "validation" { 134 | for_each = { 135 | for dvo in aws_acm_certificate.this.domain_validation_options : dvo.domain_name => { 136 | name = dvo.resource_record_name 137 | record = dvo.resource_record_value 138 | type = dvo.resource_record_type 139 | } 140 | } 141 | 142 | allow_overwrite = true 143 | name = each.value.name 144 | records = [each.value.record] 145 | ttl = 60 146 | type = each.value.type 147 | zone_id = data.aws_route53_zone.this.zone_id 148 | } 149 | 150 | resource "aws_acm_certificate_validation" "this" { 151 | certificate_arn = aws_acm_certificate.this.arn 152 | validation_record_fqdns = [for record in aws_route53_record.validation : record.fqdn] 153 | } 154 | /* 155 | module "log_bucket" { 156 | source = "../aws-s3-bucket" 157 | bucket_prefix = "${var.name}-lb-logs" 158 | enable_replication = false 159 | logging_enabled = false 160 | } 161 | */ 162 | data "aws_iam_policy_document" "log_access" { 163 | statement { 164 | sid = "" 165 | effect = "Allow" 166 | resources = ["arn:aws:s3:::${var.log_bucket}/*"] 167 | actions = ["s3:PutObject"] 168 | 169 | principals { 170 | type = "AWS" 171 | # TODO: Allow other regions 172 | # See: https://docs.aws.amazon.com/elasticloadbalancing/latest/application/enable-access-logging.html#attach-bucket-policy 173 | identifiers = [ 174 | "arn:aws:iam::027434742980:root", # us-west-1 175 | "arn:aws:iam::797873946194:root" # us-west-2 176 | ] 177 | } 178 | } 179 | } 180 | 181 | resource "aws_s3_bucket_policy" "this" { 182 | bucket = var.log_bucket 183 | policy = data.aws_iam_policy_document.log_access.json 184 | } 185 | -------------------------------------------------------------------------------- /modules/aws-vpc/README.md: -------------------------------------------------------------------------------- 1 | # aws-vpc 2 | 3 | 4 | 5 | 8 | 9 | ## Example 10 | 11 | ```hcl 12 | provider "aws" { 13 | default_tags { 14 | tags = { 15 | Terraformed = true 16 | Environment = "test" 17 | Name = "vpc-module-test" 18 | } 19 | } 20 | } 21 | 22 | data "aws_availability_zones" "available" { 23 | state = "available" 24 | } 25 | 26 | locals { 27 | availability_zones = slice(data.aws_availability_zones.available.names, 0, 2) 28 | } 29 | 30 | module "this" { 31 | source = "../../" 32 | name = "example" 33 | availability_zones = local.availability_zones 34 | vpc_ip_address = "10.11.0.0" 35 | vpc_netmask_length = 16 36 | subnets_netmask_length = 20 37 | create_public_subnets = true 38 | create_nat_gateways = true 39 | } 40 | ``` 41 | 42 | 43 | ## Modules 44 | 45 | | Name | Source | Version | 46 | |------|--------|---------| 47 | | [subnet\_addrs](#module\_subnet\_addrs) | hashicorp/subnets/cidr | ~> 1.0 | 48 | 49 | ## Providers 50 | 51 | | Name | Version | 52 | |------|---------| 53 | | [aws](#provider\_aws) | ~>5.0 | 54 | 55 | ## Requirements 56 | 57 | | Name | Version | 58 | |------|---------| 59 | | [terraform](#requirement\_terraform) | ~>1.5 | 60 | | [aws](#requirement\_aws) | ~>5.0 | 61 | 62 | ## Resources 63 | 64 | | Name | Type | 65 | |------|------| 66 | | [aws_ec2_transit_gateway_vpc_attachment.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ec2_transit_gateway_vpc_attachment) | resource | 67 | | [aws_eip.nat](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/eip) | resource | 68 | | [aws_internet_gateway.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/internet_gateway) | resource | 69 | | [aws_nat_gateway.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/nat_gateway) | resource | 70 | | [aws_route.nat_gw](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route) | resource | 71 | | [aws_route.public](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route) | resource | 72 | | [aws_route.transit_gw](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route) | resource | 73 | | [aws_route_table.private](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table) | resource | 74 | | [aws_route_table.public](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table) | resource | 75 | | [aws_route_table_association.nat_gw](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table_association) | resource | 76 | | [aws_route_table_association.public](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table_association) | resource | 77 | | [aws_route_table_association.transit_gw](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table_association) | resource | 78 | | [aws_subnet.private](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/subnet) | resource | 79 | | [aws_subnet.public](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/subnet) | resource | 80 | | [aws_vpc.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc) | resource | 81 | 82 | ## Inputs 83 | 84 | | Name | Description | Type | Default | Required | 85 | |------|-------------|------|---------|:--------:| 86 | | [availability\_zones](#input\_availability\_zones) | Availability zones to create resources in. | `list(string)` | n/a | yes | 87 | | [name](#input\_name) | Name of the VPC. Used to name various other resources. | `string` | n/a | yes | 88 | | [subnets\_netmask\_length](#input\_subnets\_netmask\_length) | The netmask length of the IPv4 CIDR you want to allocate to subnets.
Must be greater than `vpc_netmask_lengthh` | `string` | n/a | yes | 89 | | [vpc\_netmask\_length](#input\_vpc\_netmask\_length) | The netmask length of the IPv4 CIDR to allocate to this VPC. | `number` | n/a | yes | 90 | | [attach\_transit\_gateway](#input\_attach\_transit\_gateway) | Toggle Transit Gateway attachment.
Requires `transit_gateway_id`. | `bool` | `false` | no | 91 | | [create\_nat\_gateways](#input\_create\_nat\_gateways) | Toggle nat gateway creation.
Conflicts with `transit_gateway_id`.
Requires `create_public_subnets`. | `bool` | `false` | no | 92 | | [create\_public\_subnets](#input\_create\_public\_subnets) | Toggle public subnet creation. | `bool` | `false` | no | 93 | | [ipam\_pool\_id](#input\_ipam\_pool\_id) | The ID of an IPv4 IPAM pool you want to use for allocating this VPC's CIDR.
Conflicts with `vpc_ip_address`. | `string` | `null` | no | 94 | | [transit\_gateway\_id](#input\_transit\_gateway\_id) | Transit gateway to connect to.
Requires `attach_transit_gateway`.
Conflicts with `create_nat_gateways`. | `string` | `null` | no | 95 | | [vpc\_ip\_address](#input\_vpc\_ip\_address) | Base IP address block for VPC. Combined with `vpc_netmask_length` to form
CIDR for the VPC.
Conflicts with `ipam_pool_id`. | `string` | `null` | no | 96 | 97 | ## Outputs 98 | 99 | | Name | Description | 100 | |------|-------------| 101 | | [result](#output\_result) | The result of the module. | 102 | 103 | 104 | 105 | -------------------------------------------------------------------------------- /modules/aws-ec2-asg/README.md: -------------------------------------------------------------------------------- 1 | # aws-ec2-asg 2 | 3 | 4 | 5 | 8 | 9 | ## Example 10 | 11 | ```hcl 12 | provider "aws" { 13 | default_tags { 14 | tags = { 15 | Terraformed = true 16 | Environment = "test" 17 | Name = "asg-module-test" 18 | } 19 | } 20 | } 21 | 22 | data "aws_subnets" "private" { 23 | tags = { 24 | Tier = "Private" 25 | } 26 | } 27 | 28 | module "this" { 29 | source = "../../" 30 | name = "asg-module-example" 31 | user_data = templatefile("user_data.sh", {}) 32 | subnet_ids = data.aws_subnets.private.ids 33 | ami_ssm_parameter = "/aws/service/ecs/optimized-ami/amazon-linux-2/recommended" 34 | } 35 | 36 | output "result" { 37 | description = <<-EOT 38 | The result of the module. 39 | EOT 40 | value = module.this.result 41 | } 42 | ``` 43 | 44 | 45 | ## Modules 46 | 47 | No modules. 48 | 49 | ## Providers 50 | 51 | | Name | Version | 52 | |------|---------| 53 | | [aws](#provider\_aws) | ~>5.0 | 54 | 55 | ## Requirements 56 | 57 | | Name | Version | 58 | |------|---------| 59 | | [terraform](#requirement\_terraform) | ~>1.5 | 60 | | [aws](#requirement\_aws) | ~>5.0 | 61 | | [random](#requirement\_random) | ~>3.0 | 62 | 63 | ## Resources 64 | 65 | | Name | Type | 66 | |------|------| 67 | | [aws_autoscaling_group.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/autoscaling_group) | resource | 68 | | [aws_iam_instance_profile.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_instance_profile) | resource | 69 | | [aws_iam_role.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | 70 | | [aws_iam_role_policy_attachment.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | 71 | | [aws_launch_template.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/launch_template) | resource | 72 | | [aws_ssm_association.cloudwatch_manage_agent](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ssm_association) | resource | 73 | | [aws_ssm_association.configure_aws_packages](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ssm_association) | resource | 74 | | [aws_ssm_parameter.cloudwatch_config](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ssm_parameter) | resource | 75 | | [aws_iam_policy_document.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | 76 | | [aws_ssm_parameter.ami_id](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/ssm_parameter) | data source | 77 | 78 | ## Inputs 79 | 80 | | Name | Description | Type | Default | Required | 81 | |------|-------------|------|---------|:--------:| 82 | | [name](#input\_name) | The name of the ASG.
This value is used as the basis for naming various other resources.
If this value is not specified a random name will be generated. | `string` | n/a | yes | 83 | | [subnet\_ids](#input\_subnet\_ids) | Subnets to deploy instances in. | `list(string)` | n/a | yes | 84 | | [ami\_id](#input\_ami\_id) | AMI ID for instances created by the ASG.
Conflicts with `ami_ssm_parameter`. | `string` | `null` | no | 85 | | [ami\_ssm\_parameter](#input\_ami\_ssm\_parameter) | Name of SSM parameter that contains the AMI ID to use.
ex. "/aws/service/ecs/optimized-ami/amazon-linux-2/recommended"
Conflicts with `ami_id`. | `string` | `null` | no | 86 | | [aws\_packages](#input\_aws\_packages) | List of AWS packages to deploy via SSM. | `list(string)` |
[
"AWSCodeDeployAgent",
"AmazonCloudWatchAgent"
]
| no | 87 | | [cloudwatch\_config](#input\_cloudwatch\_config) | Cloudwatch config file contents. | `string` | `null` | no | 88 | | [instance\_role\_policies](#input\_instance\_role\_policies) | IAM Policy ARNs to attach to the instance profile. | `list(string)` |
[
"arn:aws:iam::aws:policy/service-role/AmazonEC2RoleforAWSCodeDeploy",
"arn:aws:iam::aws:policy/CloudWatchAgentServerPolicy",
"arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore",
"arn:aws:iam::aws:policy/AmazonS3ReadOnlyAccess",
"arn:aws:iam::aws:policy/CloudWatchLogsFullAccess"
]
| no | 89 | | [instance\_tags](#input\_instance\_tags) | Tags to apply to instances.
Use the provider `default_tags` feature for more consistent tagging. | `map(string)` | `{}` | no | 90 | | [instance\_type](#input\_instance\_type) | Instance type | `string` | `"t2.micro"` | no | 91 | | [max\_size](#input\_max\_size) | Maximum number of instances to create. | `number` | `1` | no | 92 | | [min\_size](#input\_min\_size) | Minimum number of instances to create. | `number` | `1` | no | 93 | | [root\_volume\_size](#input\_root\_volume\_size) | Size in GB of root volume size. | `number` | `100` | no | 94 | | [security\_group\_ids](#input\_security\_group\_ids) | Security groups to attach to the managed instances. | `list(string)` | `null` | no | 95 | | [target\_group\_arns](#input\_target\_group\_arns) | Load balancer targets to register with. | `list(string)` | `null` | no | 96 | | [user\_data](#input\_user\_data) | Instance User Data.
See: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/user-data.html | `string` | `null` | no | 97 | 98 | ## Outputs 99 | 100 | | Name | Description | 101 | |------|-------------| 102 | | [result](#output\_result) | The result of the module. | 103 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /modules/aws-https-alb/README.md: -------------------------------------------------------------------------------- 1 | # aws-https-alb 2 | 3 | 4 | 5 | 8 | 9 | ## Example 10 | 11 | ```hcl 12 | variable "name" { 13 | default = "aws-https-module-example" 14 | } 15 | 16 | variable "domain_name" { 17 | default = "bananalab.dev" 18 | } 19 | 20 | data "aws_vpc" "default" { 21 | default = true 22 | } 23 | 24 | data "aws_subnets" "default" { 25 | filter { 26 | name = "vpc-id" 27 | values = [data.aws_vpc.default.id] 28 | } 29 | filter { 30 | name = "default-for-az" 31 | values = ["true"] 32 | } 33 | } 34 | 35 | module "this" { 36 | source = "../../" 37 | name = var.name 38 | vpc_id = data.aws_vpc.default.id 39 | subnet_ids = data.aws_subnets.default.ids 40 | application_host = var.name 41 | domain_name = var.domain_name 42 | } 43 | 44 | output "result" { 45 | description = <<-EOT 46 | The result of the module. 47 | EOT 48 | value = module.this.result 49 | } 50 | ``` 51 | 52 | 53 | ## Modules 54 | 55 | No modules. 56 | 57 | ## Providers 58 | 59 | | Name | Version | 60 | |------|---------| 61 | | [aws](#provider\_aws) | ~>5.0 | 62 | 63 | ## Requirements 64 | 65 | | Name | Version | 66 | |------|---------| 67 | | [terraform](#requirement\_terraform) | ~>1.5.0 | 68 | | [aws](#requirement\_aws) | ~>5.0 | 69 | | [random](#requirement\_random) | ~>3.0 | 70 | 71 | ## Resources 72 | 73 | | Name | Type | 74 | |------|------| 75 | | [aws_acm_certificate.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/acm_certificate) | resource | 76 | | [aws_acm_certificate_validation.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/acm_certificate_validation) | resource | 77 | | [aws_cloudwatch_log_group.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_group) | resource | 78 | | [aws_lb.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lb) | resource | 79 | | [aws_lb_listener.https](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lb_listener) | resource | 80 | | [aws_lb_listener.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lb_listener) | resource | 81 | | [aws_route53_record.alb](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53_record) | resource | 82 | | [aws_route53_record.validation](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53_record) | resource | 83 | | [aws_s3_bucket_policy.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_policy) | resource | 84 | | [aws_security_group.alb](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group) | resource | 85 | | [aws_vpc_security_group_egress_rule.allow_all](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc_security_group_egress_rule) | resource | 86 | | [aws_vpc_security_group_ingress_rule.http](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc_security_group_ingress_rule) | resource | 87 | | [aws_vpc_security_group_ingress_rule.https](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc_security_group_ingress_rule) | resource | 88 | | [aws_vpc_security_group_ingress_rule.intragroup](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc_security_group_ingress_rule) | resource | 89 | | [aws_wafv2_web_acl.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/wafv2_web_acl) | resource | 90 | | [aws_wafv2_web_acl_association.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/wafv2_web_acl_association) | resource | 91 | | [aws_wafv2_web_acl_logging_configuration.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/wafv2_web_acl_logging_configuration) | resource | 92 | | [aws_iam_policy_document.log_access](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | 93 | | [aws_route53_zone.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/route53_zone) | data source | 94 | 95 | ## Inputs 96 | 97 | | Name | Description | Type | Default | Required | 98 | |------|-------------|------|---------|:--------:| 99 | | [application\_host](#input\_application\_host) | Hostname where the application will be reachable. | `string` | n/a | yes | 100 | | [domain\_name](#input\_domain\_name) | DNS domain.
This will be combined with application\_host to form the fqdn.
This should already exist as a route53 hosted domain. | `string` | n/a | yes | 101 | | [log\_bucket](#input\_log\_bucket) | S3 bucket to store logs. | `string` | n/a | yes | 102 | | [name](#input\_name) | The name of the ALB.
This value is used as the basis for naming various other resources. | `string` | n/a | yes | 103 | | [subnet\_ids](#input\_subnet\_ids) | Subnets to deploy Load Balancer in. | `list(string)` | n/a | yes | 104 | | [vpc\_id](#input\_vpc\_id) | ID of VPC. | `string` | n/a | yes | 105 | | [enable\_waf](#input\_enable\_waf) | Enable or disable WAF. | `bool` | `true` | no | 106 | | [idle\_timeout](#input\_idle\_timeout) | The time in seconds that the connection is allowed to be idle. | `number` | `600` | no | 107 | | [waf\_log\_retention\_days](#input\_waf\_log\_retention\_days) | Number of days to retain WAF logs | `number` | `90` | no | 108 | | [waf\_managed\_rules](#input\_waf\_managed\_rules) | List of WAF managed rules. |
map(object({
rule_action_overrides = optional(map(string), {})
}))
|
{
"AWSManagedRulesAmazonIpReputationList": {},
"AWSManagedRulesAnonymousIpList": {},
"AWSManagedRulesCommonRuleSet": {
"rule_action_overrides": {
"SizeRestrictions_BODY": "allow"
}
},
"AWSManagedRulesKnownBadInputsRuleSet": {},
"AWSManagedRulesLinuxRuleSet": {},
"AWSManagedRulesPHPRuleSet": {},
"AWSManagedRulesSQLiRuleSet": {}
}
| no | 109 | 110 | ## Outputs 111 | 112 | | Name | Description | 113 | |------|-------------| 114 | | [result](#output\_result) | The result of the module. | 115 | 116 | 117 | 118 | -------------------------------------------------------------------------------- /modules/aws-s3-bucket/README.md: -------------------------------------------------------------------------------- 1 | 2 | # aws-s3-bucket 3 | 4 | 5 | 6 | 9 | L1 Module to create an S3 bucket. 10 | 11 | ## Example 12 | 13 | ```hcl 14 | # tflint-ignore: all 15 | 16 | variable "bucket" { default = null } 17 | variable "bucket_prefix" { default = null } 18 | variable "force_destroy" { default = false } 19 | variable "object_lock_enabled" { default = false } 20 | variable "tags" { default = null } 21 | variable "block_public_acls" { default = true } 22 | variable "block_public_policy" { default = true } 23 | variable "ignore_public_acls" { default = true } 24 | variable "restrict_public_buckets" { default = true } 25 | variable "versioning_enabled" { default = true } 26 | variable "expected_bucket_owner" { default = null } 27 | variable "logging_enabled" { default = false } 28 | variable "logging_target_bucket" { default = null } 29 | variable "logging_target_prefix" { default = null } 30 | variable "enable_server_side_encryption" { default = true } 31 | variable "kms_master_key_id" { default = null } 32 | variable "enable_replication" { default = false } 33 | variable "replication_role" { default = null } 34 | variable "replication_target_bucket" { default = null } 35 | 36 | 37 | 38 | module "this" { 39 | source = "../../" 40 | bucket = var.bucket 41 | bucket_prefix = var.bucket_prefix 42 | force_destroy = var.force_destroy 43 | object_lock_enabled = var.object_lock_enabled 44 | tags = var.tags 45 | block_public_acls = var.block_public_acls 46 | block_public_policy = var.block_public_policy 47 | ignore_public_acls = var.ignore_public_acls 48 | versioning_enabled = var.versioning_enabled 49 | logging_enabled = var.logging_enabled 50 | logging_target_bucket = var.logging_target_bucket 51 | logging_target_prefix = var.logging_target_prefix 52 | expected_bucket_owner = var.expected_bucket_owner 53 | restrict_public_buckets = var.restrict_public_buckets 54 | enable_server_side_encryption = var.enable_server_side_encryption 55 | kms_master_key_id = var.kms_master_key_id 56 | enable_replication = var.enable_replication 57 | replication_role = var.replication_role 58 | replication_target_bucket = var.replication_target_bucket 59 | } 60 | 61 | output "result" { 62 | description = <<-EOT 63 | The result of the module. 64 | EOT 65 | value = module.this.result 66 | } 67 | ``` 68 | 69 | 70 | ## Modules 71 | 72 | No modules. 73 | 74 | ## Providers 75 | 76 | | Name | Version | 77 | |------|---------| 78 | | [aws](#provider\_aws) | ~>5.0 | 79 | 80 | ## Requirements 81 | 82 | | Name | Version | 83 | |------|---------| 84 | | [terraform](#requirement\_terraform) | >= 1.3.0 | 85 | | [aws](#requirement\_aws) | ~>5.0 | 86 | 87 | ## Resources 88 | 89 | | Name | Type | 90 | |------|------| 91 | | [aws_s3_bucket.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket) | resource | 92 | | [aws_s3_bucket_logging.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_logging) | resource | 93 | | [aws_s3_bucket_public_access_block.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_public_access_block) | resource | 94 | | [aws_s3_bucket_replication_configuration.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_replication_configuration) | resource | 95 | | [aws_s3_bucket_server_side_encryption_configuration.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_server_side_encryption_configuration) | resource | 96 | | [aws_s3_bucket_versioning.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_versioning) | resource | 97 | 98 | ## Inputs 99 | 100 | | Name | Description | Type | Default | Required | 101 | |------|-------------|------|---------|:--------:| 102 | | [block\_public\_acls](#input\_block\_public\_acls) | Block public access to the bucket | `bool` | `true` | no | 103 | | [block\_public\_policy](#input\_block\_public\_policy) | Block public policy access to the bucket | `bool` | `true` | no | 104 | | [bucket](#input\_bucket) | The name of the S3 bucket to create | `string` | `null` | no | 105 | | [bucket\_prefix](#input\_bucket\_prefix) | The prefix to use for the S3 bucket name | `string` | `null` | no | 106 | | [enable\_replication](#input\_enable\_replication) | Enable replication for the bucket | `bool` | `true` | no | 107 | | [enable\_server\_side\_encryption](#input\_enable\_server\_side\_encryption) | Enable server side encryption for the bucket | `bool` | `true` | no | 108 | | [expected\_bucket\_owner](#input\_expected\_bucket\_owner) | The expected owner of the bucket | `string` | `null` | no | 109 | | [force\_destroy](#input\_force\_destroy) | Force destroy the bucket if it exists | `bool` | `false` | no | 110 | | [ignore\_public\_acls](#input\_ignore\_public\_acls) | Ignore public acls for the bucket | `bool` | `true` | no | 111 | | [kms\_master\_key\_id](#input\_kms\_master\_key\_id) | The KMS key id to use for encryption | `string` | `null` | no | 112 | | [logging\_enabled](#input\_logging\_enabled) | Enable logging for the bucket | `bool` | `true` | no | 113 | | [logging\_target\_bucket](#input\_logging\_target\_bucket) | The target bucket for the logging configuration | `string` | `null` | no | 114 | | [logging\_target\_prefix](#input\_logging\_target\_prefix) | The target prefix for the logging configuration | `string` | `null` | no | 115 | | [object\_lock\_enabled](#input\_object\_lock\_enabled) | Enable object lock for the bucket | `bool` | `false` | no | 116 | | [replication\_role](#input\_replication\_role) | The role ARN to use for replication | `string` | `null` | no | 117 | | [replication\_target\_bucket](#input\_replication\_target\_bucket) | The target bucket to use for replication | `string` | `null` | no | 118 | | [replication\_token](#input\_replication\_token) | The token to use for replication | `string` | `null` | no | 119 | | [restrict\_public\_buckets](#input\_restrict\_public\_buckets) | Restrict public access to the bucket | `bool` | `true` | no | 120 | | [tags](#input\_tags) | Tags to apply to the bucket | `map(any)` | `null` | no | 121 | | [versioning\_enabled](#input\_versioning\_enabled) | Enable versioning for the bucket | `bool` | `true` | no | 122 | 123 | ## Outputs 124 | 125 | | Name | Description | 126 | |------|-------------| 127 | | [result](#output\_result) | The result of the module. | 128 | 129 | 130 | 131 | -------------------------------------------------------------------------------- /modules/bananalab-ecs-service/main.tf: -------------------------------------------------------------------------------- 1 | /** 2 | * 5 | */ 6 | 7 | locals { 8 | fqdn = var.fqdn 9 | domain_parts = split(".", local.fqdn) 10 | domain = length(local.domain_parts) == 2 ? var.fqdn : join(".", slice(split(".", local.fqdn), 1, length(split(".", local.fqdn)))) 11 | vpc_id = data.aws_subnet.this.vpc_id 12 | } 13 | 14 | resource "aws_ecs_task_definition" "this" { 15 | family = var.name 16 | container_definitions = var.container_definitions 17 | task_role_arn = var.task_role_arn 18 | execution_role_arn = aws_iam_role.ecs_execution.arn 19 | network_mode = "awsvpc" 20 | cpu = var.cpu 21 | memory = var.memory 22 | requires_compatibilities = var.requires_compatibilities 23 | tags = var.task_tags 24 | dynamic "placement_constraints" { 25 | for_each = var.placement_constraints 26 | content { 27 | type = placement_constraints.value.type 28 | expression = lookup(placement_constraints.value.expression, null) 29 | } 30 | } 31 | 32 | dynamic "volume" { 33 | # TODO: Support EFS volumes 34 | for_each = var.volumes 35 | content { 36 | name = volume.key 37 | docker_volume_configuration { 38 | scope = lookup(volume.value.docker_volume_configuration, "scope", null) 39 | autoprovision = lookup(volume.value.docker_volume_configuration, "autoprovision", null) 40 | driver = lookup(volume.value.docker_volume_configuration, "driver", null) 41 | driver_opts = lookup(volume.value.docker_volume_configuration, "driver_opts", null) 42 | labels = lookup(volume.value.docker_volume_configuration, "labels", null) 43 | } 44 | } 45 | } 46 | } 47 | 48 | resource "aws_ecs_service" "this" { 49 | name = var.name 50 | cluster = var.ecs_cluster_id 51 | task_definition = aws_ecs_task_definition.this.arn 52 | desired_count = var.desired_count 53 | capacity_provider_strategy { 54 | base = 1 55 | capacity_provider = var.capacity_provider 56 | weight = 100 57 | } 58 | network_configuration { 59 | subnets = var.subnet_ids 60 | assign_public_ip = false 61 | security_groups = [aws_security_group.service.id] 62 | } 63 | 64 | dynamic "load_balancer" { 65 | for_each = var.load_balancer_targets 66 | content { 67 | target_group_arn = aws_lb_target_group.this[load_balancer.key].arn 68 | container_port = lookup(load_balancer.value, "port", 80) 69 | container_name = load_balancer.key 70 | } 71 | } 72 | } 73 | 74 | data "aws_subnet" "this" { 75 | id = var.subnet_ids[0] 76 | } 77 | 78 | resource "aws_lb_target_group" "this" { 79 | # checkov:skip=CKV_AWS_261 80 | for_each = var.load_balancer_targets 81 | port = lookup(each.value, "port", 80) 82 | protocol = lookup(each.value, "protocol", "HTTP") 83 | target_type = "ip" 84 | vpc_id = local.vpc_id 85 | } 86 | 87 | data "aws_lb_listener" "selected443" { 88 | load_balancer_arn = var.load_balancer_arn 89 | port = 443 90 | } 91 | 92 | data "aws_route53_zone" "selected" { 93 | name = local.domain 94 | private_zone = false 95 | } 96 | 97 | data "aws_lb" "this" { 98 | arn = var.load_balancer_arn 99 | } 100 | 101 | resource "aws_acm_certificate" "this" { 102 | domain_name = local.fqdn 103 | validation_method = "DNS" 104 | subject_alternative_names = keys(var.url_rewrites) 105 | 106 | lifecycle { 107 | create_before_destroy = true 108 | } 109 | } 110 | 111 | resource "aws_route53_record" "validation" { 112 | for_each = { 113 | for dvo in aws_acm_certificate.this.domain_validation_options : dvo.domain_name => { 114 | name = dvo.resource_record_name 115 | record = dvo.resource_record_value 116 | type = dvo.resource_record_type 117 | } 118 | } 119 | 120 | allow_overwrite = true 121 | name = each.value.name 122 | records = [each.value.record] 123 | ttl = 60 124 | type = each.value.type 125 | zone_id = data.aws_route53_zone.selected.zone_id 126 | } 127 | 128 | resource "aws_acm_certificate_validation" "this" { 129 | certificate_arn = aws_acm_certificate.this.arn 130 | validation_record_fqdns = [for record in aws_route53_record.validation : record.fqdn] 131 | } 132 | 133 | resource "aws_lb_listener_certificate" "this" { 134 | listener_arn = data.aws_lb_listener.selected443.arn 135 | certificate_arn = aws_acm_certificate_validation.this.certificate_arn 136 | } 137 | 138 | resource "aws_route53_record" "this" { 139 | for_each = toset(concat([var.fqdn], keys(var.url_rewrites))) 140 | zone_id = data.aws_route53_zone.selected.zone_id 141 | name = each.value 142 | type = "A" 143 | alias { 144 | name = data.aws_lb.this.dns_name 145 | zone_id = data.aws_lb.this.zone_id 146 | evaluate_target_health = true 147 | } 148 | weighted_routing_policy { 149 | weight = var.dns_routing_weight 150 | } 151 | set_identifier = "${var.name}-${each.value}" 152 | } 153 | 154 | resource "aws_lb_listener_rule" "this" { 155 | for_each = aws_lb_target_group.this 156 | listener_arn = data.aws_lb_listener.selected443.arn 157 | 158 | action { 159 | type = "forward" 160 | target_group_arn = each.value.arn 161 | } 162 | 163 | condition { 164 | host_header { 165 | values = [var.fqdn] 166 | } 167 | } 168 | } 169 | 170 | resource "aws_lb_listener_rule" "rewrite" { 171 | for_each = var.url_rewrites 172 | listener_arn = data.aws_lb_listener.selected443.arn 173 | 174 | action { 175 | type = "redirect" 176 | redirect { 177 | host = lookup(each.value, "host", var.fqdn) 178 | path = lookup(each.value, "path", "") 179 | query = lookup(each.value, "query", "") 180 | status_code = "HTTP_301" 181 | } 182 | } 183 | 184 | condition { 185 | host_header { 186 | values = [each.key] 187 | } 188 | } 189 | } 190 | 191 | resource "aws_security_group" "service" { 192 | name = "${var.name}_allow_lb_traffic" 193 | description = "Allow LB traffic" 194 | vpc_id = local.vpc_id 195 | 196 | dynamic "ingress" { 197 | for_each = var.load_balancer_targets 198 | content { 199 | description = "Allow service traffic" 200 | from_port = lookup(ingress.value, "port", 80) 201 | to_port = lookup(ingress.value, "port", 80) 202 | protocol = "tcp" 203 | security_groups = data.aws_lb.this.security_groups 204 | } 205 | } 206 | 207 | egress { 208 | description = "Allow all." 209 | from_port = 0 210 | to_port = 0 211 | protocol = "-1" 212 | cidr_blocks = ["0.0.0.0/0"] 213 | ipv6_cidr_blocks = ["::/0"] 214 | } 215 | } 216 | 217 | data "aws_iam_policy_document" "ecs_execution_policy" { 218 | # checkov:skip=CKV_AWS_356 219 | # checkov:skip=CKV_AWS_111 220 | statement { 221 | effect = "Allow" 222 | actions = [ 223 | "ecr:GetAuthorizationToken", 224 | "ecr:BatchCheckLayerAvailability", 225 | "ecr:GetDownloadUrlForLayer", 226 | "ecr:BatchGetImage", 227 | "logs:CreateLogStream", 228 | "logs:PutLogEvents", 229 | "logs:CreateLogGroup" 230 | ] 231 | 232 | resources = [ 233 | "*" 234 | ] 235 | } 236 | } 237 | 238 | resource "aws_iam_policy" "ecs_execution" { 239 | name = "${var.name}_default_ecs_execution_policy" 240 | path = "/" 241 | policy = data.aws_iam_policy_document.ecs_execution_policy.json 242 | } 243 | 244 | data "aws_iam_policy_document" "ecs_execution_role_policy" { 245 | statement { 246 | actions = ["sts:AssumeRole"] 247 | 248 | principals { 249 | type = "Service" 250 | identifiers = ["ecs-tasks.amazonaws.com"] 251 | } 252 | } 253 | } 254 | 255 | resource "aws_iam_role" "ecs_execution" { 256 | name = "${var.name}EcsExecutionRole" 257 | path = "/system/" 258 | assume_role_policy = data.aws_iam_policy_document.ecs_execution_role_policy.json 259 | } 260 | 261 | resource "aws_iam_role_policy_attachment" "ecs_task" { 262 | role = aws_iam_role.ecs_execution.name 263 | policy_arn = aws_iam_policy.ecs_execution.arn 264 | } 265 | -------------------------------------------------------------------------------- /modules/bananalab-ecs-service/README.md: -------------------------------------------------------------------------------- 1 | # bananalab-ecs-service 2 | 3 | 4 | 5 | 8 | 9 | ## Example 10 | 11 | ```hcl 12 | /** 13 | * Examples should illustrate typical use cases. 14 | * For multiple examples each should have its own directory. 15 | * 16 | * > Running module examples uses a local state file. 17 | * > If you delete the .terraform directory the resources 18 | * > will be orphaned. 19 | */ 20 | 21 | provider "aws" { 22 | default_tags { 23 | tags = { 24 | terraformed = "true" 25 | example = "simple" 26 | module = local.name 27 | } 28 | } 29 | } 30 | 31 | data "aws_vpc" "this" { 32 | tags = { 33 | Name = local.platform_id 34 | } 35 | } 36 | 37 | data "aws_subnets" "private" { 38 | filter { 39 | name = "vpc-id" 40 | values = [data.aws_vpc.this.id] 41 | } 42 | 43 | tags = { 44 | Tier = "Private" 45 | } 46 | } 47 | 48 | data "aws_ecs_cluster" "this" { 49 | cluster_name = local.platform_id 50 | } 51 | 52 | data "aws_lb" "this" { 53 | name = local.platform_id 54 | } 55 | 56 | locals { 57 | name = "bananalab-ecs-service-example" 58 | domain_name = "bananalab.dev" 59 | platform_id = "default" 60 | container_definitions = file("container-definitions.json") 61 | volumes = {} 62 | 63 | load_balancer_targets = { 64 | "nginx" = { port = 80 } 65 | } 66 | 67 | url_rewrites = {} 68 | 69 | } 70 | 71 | module "this" { 72 | source = "../../" 73 | name = local.name 74 | fqdn = "${local.name}.${local.domain_name}" 75 | ecs_cluster_id = data.aws_ecs_cluster.this.id 76 | capacity_provider = local.platform_id 77 | subnet_ids = data.aws_subnets.private.ids 78 | load_balancer_arn = data.aws_lb.this.arn 79 | container_definitions = local.container_definitions 80 | volumes = local.volumes 81 | load_balancer_targets = local.load_balancer_targets 82 | url_rewrites = local.url_rewrites 83 | } 84 | 85 | output "result" { 86 | description = <<-EOT 87 | The result of the module. 88 | EOT 89 | value = module.this.result 90 | } 91 | ``` 92 | 93 | 94 | ## Modules 95 | 96 | No modules. 97 | 98 | ## Providers 99 | 100 | | Name | Version | 101 | |------|---------| 102 | | [aws](#provider\_aws) | ~>5.0 | 103 | 104 | ## Requirements 105 | 106 | | Name | Version | 107 | |------|---------| 108 | | [terraform](#requirement\_terraform) | ~>1.5 | 109 | | [aws](#requirement\_aws) | ~>5.0 | 110 | 111 | ## Resources 112 | 113 | | Name | Type | 114 | |------|------| 115 | | [aws_acm_certificate.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/acm_certificate) | resource | 116 | | [aws_acm_certificate_validation.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/acm_certificate_validation) | resource | 117 | | [aws_ecs_service.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecs_service) | resource | 118 | | [aws_ecs_task_definition.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/ecs_task_definition) | resource | 119 | | [aws_iam_policy.ecs_execution](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_policy) | resource | 120 | | [aws_iam_role.ecs_execution](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource | 121 | | [aws_iam_role_policy_attachment.ecs_task](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy_attachment) | resource | 122 | | [aws_lb_listener_certificate.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lb_listener_certificate) | resource | 123 | | [aws_lb_listener_rule.rewrite](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lb_listener_rule) | resource | 124 | | [aws_lb_listener_rule.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lb_listener_rule) | resource | 125 | | [aws_lb_target_group.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lb_target_group) | resource | 126 | | [aws_route53_record.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53_record) | resource | 127 | | [aws_route53_record.validation](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route53_record) | resource | 128 | | [aws_security_group.service](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group) | resource | 129 | | [aws_iam_policy_document.ecs_execution_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | 130 | | [aws_iam_policy_document.ecs_execution_role_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | 131 | | [aws_lb.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/lb) | data source | 132 | | [aws_lb_listener.selected443](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/lb_listener) | data source | 133 | | [aws_route53_zone.selected](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/route53_zone) | data source | 134 | | [aws_subnet.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/subnet) | data source | 135 | 136 | ## Inputs 137 | 138 | | Name | Description | Type | Default | Required | 139 | |------|-------------|------|---------|:--------:| 140 | | [capacity\_provider](#input\_capacity\_provider) | ECS Capacity Provider to use. | `string` | n/a | yes | 141 | | [container\_definitions](#input\_container\_definitions) | A valid JSON document describing valid container definitions.
See: http://docs.aws.amazon.com/AmazonECS/latest/APIReference/API_ContainerDefinition.html | `string` | n/a | yes | 142 | | [ecs\_cluster\_id](#input\_ecs\_cluster\_id) | ECS Cluster to deploy to. | `string` | n/a | yes | 143 | | [fqdn](#input\_fqdn) | Fully qualified domain name of load balanced service. | `string` | n/a | yes | 144 | | [load\_balancer\_arn](#input\_load\_balancer\_arn) | ARN of the loadbalancer to associate services with. | `string` | n/a | yes | 145 | | [name](#input\_name) | The name of the resources created by this module.
This value is used as the basis for naming various resources. | `string` | n/a | yes | 146 | | [subnet\_ids](#input\_subnet\_ids) | Subnets associated with the task or service. | `list(string)` | n/a | yes | 147 | | [cpu](#input\_cpu) | The number of cpu units used by the task. If the `requires_compatibilities`
is "FARGATE" this field is required. | `number` | `null` | no | 148 | | [desired\_count](#input\_desired\_count) | The number of service replicas. | `number` | `2` | no | 149 | | [dns\_routing\_weight](#input\_dns\_routing\_weight) | The weight can be a number between 0 and 255. If you specify 0, Route 53
stops responding to DNS queries using this record. | `number` | `255` | no | 150 | | [load\_balancer\_targets](#input\_load\_balancer\_targets) | Load balancer target configs. | `map(any)` | `null` | no | 151 | | [memory](#input\_memory) | The amount (in MiB) of memory used by the task. If the
`requires_compatibilities` is "FARGATE" this field is required. | `number` | `null` | no | 152 | | [placement\_constraints](#input\_placement\_constraints) | Configuration block for rules that are taken into consideration during task
placement. Maximum number of `placement_constraints` is 10. | `map(any)` | `{}` | no | 153 | | [requires\_compatibilities](#input\_requires\_compatibilities) | Set of launch types required by the task. The valid values are EC2 and
FARGATE. | `list(string)` | `null` | no | 154 | | [task\_role\_arn](#input\_task\_role\_arn) | The ARN of IAM role that allows your Amazon ECS container task to make
calls to other AWS services. | `string` | `null` | no | 155 | | [task\_tags](#input\_task\_tags) | Key-value map of resource tags. | `map(string)` | `null` | no | 156 | | [url\_rewrites](#input\_url\_rewrites) | A mapping of fqdns and rewrite rules.
e.x.:
{
foo.dev-empire.com = "https://www.empi.re/listen/index.php?id=$1"
} | `map(any)` | `{}` | no | 157 | | [volumes](#input\_volumes) | List of volume configurations. | `map(any)` | `{}` | no | 158 | 159 | ## Outputs 160 | 161 | | Name | Description | 162 | |------|-------------| 163 | | [result](#output\_result) | The result of the module. | 164 | 165 | 166 | 167 | --------------------------------------------------------------------------------