From b80e6ebd89b0aeed0652b4678102378598865a3e Mon Sep 17 00:00:00 2001 From: alismx Date: Tue, 8 Oct 2024 20:54:29 -0400 Subject: [PATCH 1/9] update private subnets so they can pull from ecr --- terraform/implementation/ecs/README.md | 7 ++++--- terraform/implementation/ecs/_variable.tf | 10 ++++++++-- terraform/implementation/ecs/main.tf | 8 +++++--- terraform/implementation/setup/README.md | 6 +++--- terraform/modules/ecs/README.md | 7 +++++-- terraform/modules/ecs/_data.tf | 5 +++++ terraform/modules/ecs/_local.tf | 10 ++++++++++ terraform/modules/ecs/_variable.tf | 4 ++-- terraform/modules/ecs/alb.tf | 24 +++++++++++++++++++++-- terraform/modules/oidc/_data.tf | 1 + 10 files changed, 65 insertions(+), 17 deletions(-) diff --git a/terraform/implementation/ecs/README.md b/terraform/implementation/ecs/README.md index 42c09a7..e78e653 100644 --- a/terraform/implementation/ecs/README.md +++ b/terraform/implementation/ecs/README.md @@ -9,7 +9,7 @@ | Name | Version | |------|---------| -| [aws](#provider\_aws) | =5.56.1 | +| [aws](#provider\_aws) | 5.56.1 | ## Modules @@ -29,17 +29,18 @@ | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| | [availability\_zones](#input\_availability\_zones) | The availability zones to use | `list(string)` |
[
"us-east-1a",
"us-east-1b",
"us-east-1c"
]
| no | +| [create\_internet\_gateway](#input\_create\_internet\_gateway) | Flag to determine if an internet gateway should be created | `bool` | `false` | no | | [ecr\_viewer\_database\_schema](#input\_ecr\_viewer\_database\_schema) | The database schema used for the eCR data tables | `string` | `"core"` | no | | [ecr\_viewer\_database\_type](#input\_ecr\_viewer\_database\_type) | The SQL variant used for the eCR data tables | `string` | `"postgres"` | no | | [ecs\_alb\_sg](#input\_ecs\_alb\_sg) | The security group for the Application Load Balancer | `string` | `"ecs-albsg"` | no | -| [enable\_nat\_gateway](#input\_enable\_nat\_gateway) | Enable NAT Gateway | `bool` | `true` | no | +| [enable\_nat\_gateway](#input\_enable\_nat\_gateway) | Enable NAT Gateway | `bool` | `false` | no | | [owner](#input\_owner) | The owner of the infrastructure | `string` | `"skylight"` | no | | [phdi\_version](#input\_phdi\_version) | PHDI container image version | `string` | `"v1.4.4"` | no | | [private\_subnets](#input\_private\_subnets) | The private subnets | `list(string)` |
[
"176.24.1.0/24",
"176.24.3.0/24"
]
| no | | [project](#input\_project) | The project name | `string` | `"dibbs-ce"` | no | | [public\_subnets](#input\_public\_subnets) | The public subnets | `list(string)` |
[
"176.24.2.0/24",
"176.24.4.0/24"
]
| no | | [region](#input\_region) | AWS region | `string` | `"us-east-1"` | no | -| [single\_nat\_gateway](#input\_single\_nat\_gateway) | Single NAT Gateway | `bool` | `true` | no | +| [single\_nat\_gateway](#input\_single\_nat\_gateway) | Single NAT Gateway | `bool` | `false` | no | | [vpc](#input\_vpc) | The name of the VPC | `string` | `"ecs-vpc"` | no | | [vpc\_cidr](#input\_vpc\_cidr) | The CIDR block for the VPC | `string` | `"176.24.0.0/16"` | no | diff --git a/terraform/implementation/ecs/_variable.tf b/terraform/implementation/ecs/_variable.tf index fe108a8..c09f967 100644 --- a/terraform/implementation/ecs/_variable.tf +++ b/terraform/implementation/ecs/_variable.tf @@ -4,6 +4,12 @@ variable "availability_zones" { default = ["us-east-1a", "us-east-1b", "us-east-1c"] } +variable "create_internet_gateway" { + type = bool + description = "Flag to determine if an internet gateway should be created" + default = false +} + variable "ecs_alb_sg" { description = "The security group for the Application Load Balancer" type = string @@ -13,7 +19,7 @@ variable "ecs_alb_sg" { variable "enable_nat_gateway" { description = "Enable NAT Gateway" type = bool - default = true + default = false } variable "owner" { @@ -56,7 +62,7 @@ variable "region" { variable "single_nat_gateway" { description = "Single NAT Gateway" type = bool - default = true + default = false } variable "vpc" { diff --git a/terraform/implementation/ecs/main.tf b/terraform/implementation/ecs/main.tf index 254f717..858cddf 100644 --- a/terraform/implementation/ecs/main.tf +++ b/terraform/implementation/ecs/main.tf @@ -8,6 +8,7 @@ module "vpc" { public_subnets = var.public_subnets enable_nat_gateway = var.enable_nat_gateway single_nat_gateway = var.single_nat_gateway + create_igw = var.create_internet_gateway tags = local.tags } @@ -18,14 +19,15 @@ module "ecs" { private_subnet_ids = flatten(module.vpc.private_subnets) vpc_id = module.vpc.vpc_id region = var.region - alb_internal = false owner = var.owner project = var.project tags = local.tags - + # If intent is to pull from the phdi GHCR, set disable_ecr to true (default is false) # disable_ecr = true - # If intent is to use the non-integrated viewer, set non_integrated_viewer to true (default is false) + # If intent is to use the non-integrated viewer, set non_integrated_viewer to "true" (default is false) # non_integrated_viewer = "true" + # If the intent is to make the ecr-viewer availabble on the public internet, set internal to false (default is true) This requires an internet gateway to be present in the VPC. + # internal = false } diff --git a/terraform/implementation/setup/README.md b/terraform/implementation/setup/README.md index 4c2655d..1c95943 100644 --- a/terraform/implementation/setup/README.md +++ b/terraform/implementation/setup/README.md @@ -7,9 +7,9 @@ No requirements. | Name | Version | |------|---------| -| [aws](#provider\_aws) | n/a | -| [local](#provider\_local) | n/a | -| [random](#provider\_random) | n/a | +| [aws](#provider\_aws) | 5.70.0 | +| [local](#provider\_local) | 2.5.2 | +| [random](#provider\_random) | 3.6.3 | ## Modules diff --git a/terraform/modules/ecs/README.md b/terraform/modules/ecs/README.md index 996be1c..5ec2d8f 100644 --- a/terraform/modules/ecs/README.md +++ b/terraform/modules/ecs/README.md @@ -51,6 +51,8 @@ No modules. | [aws_security_group_rule.ecs_all_egress](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource | | [aws_security_group_rule.ecs_ecs_ingress](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule) | resource | | [aws_service_discovery_private_dns_namespace.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/service_discovery_private_dns_namespace) | resource | +| [aws_vpc_endpoint.endpoints](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc_endpoint) | resource | +| [aws_vpc_endpoint.s3](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc_endpoint) | resource | | [dockerless_remote_image.dibbs](https://registry.terraform.io/providers/nullstone-io/dockerless/0.1.1/docs/resources/remote_image) | resource | | [null_resource.target_groups](https://registry.terraform.io/providers/hashicorp/null/latest/docs/resources/resource) | resource | | [random_string.s3_viewer](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/string) | resource | @@ -60,12 +62,12 @@ No modules. | [aws_iam_policy.ecs_task_execution](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy) | data source | | [aws_iam_policy_document.assume_role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | | [aws_iam_policy_document.ecr_viewer_s3](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source | +| [aws_route_table.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/route_table) | data source | ## Inputs | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| -| [alb\_internal](#input\_alb\_internal) | Flag to determine if the ALB is public (intended for external access) or private (only intended to be accessed within your AWS VPC). | `bool` | `true` | no | | [appmesh\_name](#input\_appmesh\_name) | Name of the AWS App Mesh | `string` | `""` | no | | [cloudmap\_namespace\_name](#input\_cloudmap\_namespace\_name) | Name of the AWS Cloud Map namespace | `string` | `""` | no | | [cloudmap\_service\_name](#input\_cloudmap\_service\_name) | Name of the AWS Cloud Map service | `string` | `""` | no | @@ -81,9 +83,10 @@ No modules. | [ecs\_cluster\_name](#input\_ecs\_cluster\_name) | Name of the ECS Cluster | `string` | `""` | no | | [ecs\_task\_execution\_role\_name](#input\_ecs\_task\_execution\_role\_name) | Name of the ECS Task Execution Role | `string` | `""` | no | | [ecs\_task\_role\_name](#input\_ecs\_task\_role\_name) | Name of the ECS Task Role | `string` | `""` | no | +| [internal](#input\_internal) | Flag to determine if the several AWS resources are public (intended for external access, public internet) or private (only intended to be accessed within your AWS VPC or avaiable with other means, a transit gateway for example). | `bool` | `true` | no | | [non\_integrated\_viewer](#input\_non\_integrated\_viewer) | A flag to determine if the viewer is the non-integrated version | `string` | `"false"` | no | | [owner](#input\_owner) | Owner of the resources | `string` | `"CDC"` | no | -| [phdi\_version](#input\_phdi\_version) | Version of the PHDI application | `string` | `"v1.6.4"` | no | +| [phdi\_version](#input\_phdi\_version) | Version of the PHDI application | `string` | `"v1.6.9"` | no | | [private\_subnet\_ids](#input\_private\_subnet\_ids) | List of private subnet IDs | `list(string)` | n/a | yes | | [project](#input\_project) | The project name | `string` | `"dibbs"` | no | | [public\_subnet\_ids](#input\_public\_subnet\_ids) | List of public subnet IDs | `list(string)` | n/a | yes | diff --git a/terraform/modules/ecs/_data.tf b/terraform/modules/ecs/_data.tf index 84b5df3..41965d3 100644 --- a/terraform/modules/ecs/_data.tf +++ b/terraform/modules/ecs/_data.tf @@ -33,3 +33,8 @@ data "aws_iam_policy" "ecs_task_execution" { data "aws_iam_policy" "amazon_ec2_container_service_for_ec2_role" { name = "AmazonEC2ContainerServiceforEC2Role" } + +data "aws_route_table" "this" { + for_each = local.private_subnet_kvs + subnet_id = each.key +} \ No newline at end of file diff --git a/terraform/modules/ecs/_local.tf b/terraform/modules/ecs/_local.tf index af599ac..8cac0d5 100644 --- a/terraform/modules/ecs/_local.tf +++ b/terraform/modules/ecs/_local.tf @@ -183,4 +183,14 @@ locals { s3_viewer_bucket_name = var.s3_viewer_bucket_name == "" ? "${local.local_name}-${random_string.s3_viewer.result}" : var.s3_viewer_bucket_name s3_viewer_bucket_role_name = var.s3_viewer_bucket_role_name == "" ? "${local.local_name}-ecrv" : var.s3_viewer_bucket_role_name tags = var.tags + vpc_endpoints = [ + "com.amazonaws.${var.region}.ecr.dkr", + "com.amazonaws.${var.region}.ecr.api", + "com.amazonaws.${var.region}.ecs", + "com.amazonaws.${var.region}.ecs-telemetry", + "com.amazonaws.${var.region}.logs", + "com.amazonaws.${var.region}.secretsmanager", + ] + s3_service_name = "com.amazonaws.${var.region}.s3" + private_subnet_kvs = { for rt in var.private_subnet_ids : rt => rt } } diff --git a/terraform/modules/ecs/_variable.tf b/terraform/modules/ecs/_variable.tf index 04f8834..14ad01f 100644 --- a/terraform/modules/ecs/_variable.tf +++ b/terraform/modules/ecs/_variable.tf @@ -1,6 +1,6 @@ -variable "alb_internal" { +variable "internal" { type = bool - description = "Flag to determine if the ALB is public (intended for external access) or private (only intended to be accessed within your AWS VPC)." + description = "Flag to determine if the several AWS resources are public (intended for external access, public internet) or private (only intended to be accessed within your AWS VPC or avaiable with other means, a transit gateway for example)." default = true } variable "appmesh_name" { diff --git a/terraform/modules/ecs/alb.tf b/terraform/modules/ecs/alb.tf index 31bbe12..bbcd289 100644 --- a/terraform/modules/ecs/alb.tf +++ b/terraform/modules/ecs/alb.tf @@ -2,9 +2,9 @@ # trivy:ignore:AVD-AWS-0053 resource "aws_alb" "ecs" { name = local.ecs_alb_name - internal = var.alb_internal + internal = var.internal load_balancer_type = "application" - subnets = flatten([var.public_subnet_ids]) + subnets = var.internal == true ? flatten([var.private_subnet_ids]) : flatten([var.public_subnet_ids]) security_groups = [aws_security_group.alb.id] drop_invalid_header_fields = true @@ -36,6 +36,26 @@ resource "aws_alb_target_group" "this" { tags = local.tags } +resource "aws_vpc_endpoint" "endpoints" { + count = var.internal == true ? length(local.vpc_endpoints) : 0 + vpc_id = var.vpc_id + vpc_endpoint_type = "Interface" + private_dns_enabled = true + service_name = local.vpc_endpoints[count.index] + security_group_ids = [aws_security_group.ecs.id] + subnet_ids = flatten([var.private_subnet_ids]) + tags = local.tags +} + +resource "aws_vpc_endpoint" "s3" { + count = var.internal == true ? 1 : 0 + vpc_id = var.vpc_id + vpc_endpoint_type = "Gateway" + route_table_ids = [for rt in data.aws_route_table.this : rt.id] + service_name = local.s3_service_name + tags = local.tags +} + # The aws_alb_listener and aws_alb_listener_rule resources are not depended on by other resources so # they can be implemented via a loop or hard coded depending ease of maintenance # I've chosen the ways that reduce duplicated resource blocks: hard coded listener (i.e. http), looped listener rule (i.e. this) diff --git a/terraform/modules/oidc/_data.tf b/terraform/modules/oidc/_data.tf index 5cda2aa..61e2651 100644 --- a/terraform/modules/oidc/_data.tf +++ b/terraform/modules/oidc/_data.tf @@ -41,6 +41,7 @@ data "aws_iam_policy_document" "storage" { "${var.state_bucket_arn}", "${var.state_bucket_arn}/*", "${var.dynamodb_table_arn}", + "arn:aws:s3:::prod-region-starport-layer-bucket/*" ] } } From 0798ca3c2f1a17d9ea7440bd9ca95e438afe14df Mon Sep 17 00:00:00 2001 From: alismx Date: Thu, 10 Oct 2024 12:03:45 -0400 Subject: [PATCH 2/9] add tfstate module --- terraform/implementation/ecs/main.tf | 8 ++++- terraform/implementation/setup/_local.tf | 8 +++++ terraform/modules/ecs/_data.tf | 2 +- terraform/modules/ecs/_local.tf | 4 +-- terraform/modules/oidc/_data.tf | 15 ++++++-- terraform/modules/tfstate/_output.tf | 7 ++++ terraform/modules/tfstate/_variable.tf | 22 ++++++++++++ terraform/modules/tfstate/main.tf | 45 ++++++++++++++++++++++++ 8 files changed, 104 insertions(+), 7 deletions(-) create mode 100644 terraform/implementation/setup/_local.tf create mode 100644 terraform/modules/tfstate/_output.tf create mode 100644 terraform/modules/tfstate/_variable.tf create mode 100644 terraform/modules/tfstate/main.tf diff --git a/terraform/implementation/ecs/main.tf b/terraform/implementation/ecs/main.tf index 858cddf..9c2fd7e 100644 --- a/terraform/implementation/ecs/main.tf +++ b/terraform/implementation/ecs/main.tf @@ -26,8 +26,14 @@ module "ecs" { # If intent is to pull from the phdi GHCR, set disable_ecr to true (default is false) # disable_ecr = true + # If intent is to use the non-integrated viewer, set non_integrated_viewer to "true" (default is false) # non_integrated_viewer = "true" - # If the intent is to make the ecr-viewer availabble on the public internet, set internal to false (default is true) This requires an internet gateway to be present in the VPC. + + # If the intent is to make the ecr-viewer availabble on the public internet, set internal to false (default is true) + # This requires an internet gateway to be present in the VPC. # internal = false + + # If the intent is to disable authentication, set ecr_viewer_app_env to "test" (default is "prod") + # ecr_viewer_app_env = "test" } diff --git a/terraform/implementation/setup/_local.tf b/terraform/implementation/setup/_local.tf new file mode 100644 index 0000000..8e1dc94 --- /dev/null +++ b/terraform/implementation/setup/_local.tf @@ -0,0 +1,8 @@ +locals { + vpc_name = "${var.project}-${var.owner}-${terraform.workspace}" + tags = { + project = var.project + owner = var.owner + workspace = terraform.workspace + } +} diff --git a/terraform/modules/ecs/_data.tf b/terraform/modules/ecs/_data.tf index 41965d3..4a51084 100644 --- a/terraform/modules/ecs/_data.tf +++ b/terraform/modules/ecs/_data.tf @@ -36,5 +36,5 @@ data "aws_iam_policy" "amazon_ec2_container_service_for_ec2_role" { data "aws_route_table" "this" { for_each = local.private_subnet_kvs - subnet_id = each.key + subnet_id = each.value } \ No newline at end of file diff --git a/terraform/modules/ecs/_local.tf b/terraform/modules/ecs/_local.tf index 8cac0d5..ab92c98 100644 --- a/terraform/modules/ecs/_local.tf +++ b/terraform/modules/ecs/_local.tf @@ -191,6 +191,6 @@ locals { "com.amazonaws.${var.region}.logs", "com.amazonaws.${var.region}.secretsmanager", ] - s3_service_name = "com.amazonaws.${var.region}.s3" - private_subnet_kvs = { for rt in var.private_subnet_ids : rt => rt } + s3_service_name = "com.amazonaws.${var.region}.s3" + private_subnet_kvs = { for index, rt in var.private_subnet_ids : index => rt } } diff --git a/terraform/modules/oidc/_data.tf b/terraform/modules/oidc/_data.tf index 61e2651..8c5e361 100644 --- a/terraform/modules/oidc/_data.tf +++ b/terraform/modules/oidc/_data.tf @@ -41,7 +41,6 @@ data "aws_iam_policy_document" "storage" { "${var.state_bucket_arn}", "${var.state_bucket_arn}/*", "${var.dynamodb_table_arn}", - "arn:aws:s3:::prod-region-starport-layer-bucket/*" ] } } @@ -52,6 +51,8 @@ data "aws_iam_policy_document" "wildcard" { statement { actions = [ "ec2:DescribeAddresses", + "ec2:DescribeVpcEndpoints", + "ec2:DescribePrefixLists", "ec2:DescribeAddressesAttribute", "ec2:DescribeFlowLogs", "ec2:DescribeInternetGateways", @@ -135,6 +136,7 @@ data "aws_iam_policy_document" "scoped_one" { data "aws_iam_policy_document" "scoped_two" { statement { actions = [ + "ec2:createVpcEndpoint", "ec2:CreateFlowLogs", "ec2:CreateNatGateway", "ec2:CreateNetworkAclEntry", @@ -156,6 +158,7 @@ data "aws_iam_policy_document" "scoped_two" { "arn:aws:ec2:${var.region}:${data.aws_caller_identity.current.account_id}:natgateway/*", "arn:aws:ecr:${var.region}:${data.aws_caller_identity.current.account_id}:repository/*", "arn:aws:iam::${data.aws_caller_identity.current.account_id}:role/${local.project_owner_workspace}*", + "arn:aws:ec2:${var.region}:${data.aws_caller_identity.current.account_id}:vpc-endpoint/*", ] } } @@ -165,6 +168,7 @@ data "aws_iam_policy_document" "request_tags_create_actions" { statement { actions = [ "appmesh:CreateMesh", + "ec2:createVpcEndpoint", "appmesh:CreateVirtualNode", "appmesh:DeleteMesh", "appmesh:DeleteVirtualNode", @@ -185,12 +189,14 @@ data "aws_iam_policy_document" "request_tags_create_actions" { "iam:CreateRole", "logs:CreateLogDelivery", "logs:CreateLogGroup", + "logs:TagResource", "servicediscovery:CreatePrivateDnsNamespace", ] resources = [ "arn:aws:appmesh:${var.region}:${data.aws_caller_identity.current.account_id}:mesh/${local.project_owner_workspace}", - "arn:aws:appmesh:${var.region}:${data.aws_caller_identity.current.account_id}:mesh/${local.project_owner_workspace}/*", + "arn:aws:appmesh:${var.region}:${data.aws_caller_identity.current.account_id}:mesh/${local.project_owner_workspace}/*", "arn:aws:ec2:${var.region}:${data.aws_caller_identity.current.account_id}:vpc/${local.vpc_id}", + "arn:aws:ec2:${var.region}:${data.aws_caller_identity.current.account_id}:vpc-endpoint/*", "arn:aws:ec2:${var.region}:${data.aws_caller_identity.current.account_id}:vpc-flow-log/*", "arn:aws:ec2:${var.region}:${data.aws_caller_identity.current.account_id}:subnet/*", "arn:aws:ec2:${var.region}:${data.aws_caller_identity.current.account_id}:route-table/*", @@ -256,6 +262,7 @@ data "aws_iam_policy_document" "resource_tags_update_actions" { "iam:TagPolicy", "iam:UntagPolicy", "logs:PutRetentionPolicy", + "logs:UntagResource", "servicediscovery:TagResource", ] resources = [ @@ -305,6 +312,7 @@ data "aws_iam_policy_document" "resource_tags_delete_actions" { "ecs:DeleteCluster", "ecs:DeleteService", "ec2:DeleteVpc", + "ec2:DeleteVpcEndpoints", "ec2:DeleteTags", "ec2:DisassociateRouteTable", "ec2:DeleteRouteTable", @@ -332,6 +340,7 @@ data "aws_iam_policy_document" "resource_tags_delete_actions" { "arn:aws:ec2:${var.region}:${data.aws_caller_identity.current.account_id}:natgateway/*", "arn:aws:ec2:${var.region}:${data.aws_caller_identity.current.account_id}:security-group/*", "arn:aws:ec2:${var.region}:${data.aws_caller_identity.current.account_id}:vpc-flow-log/*", + "arn:aws:ec2:${var.region}:${data.aws_caller_identity.current.account_id}:vpc-endpoint/*", "arn:aws:ec2:${var.region}:${data.aws_caller_identity.current.account_id}:internet-gateway/*", "arn:aws:ec2:${var.region}:${data.aws_caller_identity.current.account_id}:elastic-ip/*", "arn:aws:ec2:${var.region}:${data.aws_caller_identity.current.account_id}:network-interface/*", @@ -357,4 +366,4 @@ data "aws_iam_policy_document" "resource_tags_delete_actions" { ] } } -} +} \ No newline at end of file diff --git a/terraform/modules/tfstate/_output.tf b/terraform/modules/tfstate/_output.tf new file mode 100644 index 0000000..c86c10a --- /dev/null +++ b/terraform/modules/tfstate/_output.tf @@ -0,0 +1,7 @@ +output "state_bucket" { + value = aws_s3_bucket.tfstate +} + +output "dynamodb_table" { + value = aws_dynamodb_table.tfstate_lock +} \ No newline at end of file diff --git a/terraform/modules/tfstate/_variable.tf b/terraform/modules/tfstate/_variable.tf new file mode 100644 index 0000000..2bc7a1b --- /dev/null +++ b/terraform/modules/tfstate/_variable.tf @@ -0,0 +1,22 @@ +variable "owner" { + description = "The owner of the project" + type = string + default = "skylight" +} + +variable "project" { + description = "The name of the project" + type = string + default = "dibbs-ce" +} + +variable "region" { + type = string + description = "The AWS region where resources are created" + default = "us-east-1" +} + +variable "identifier" { + type = string + default = "" +} \ No newline at end of file diff --git a/terraform/modules/tfstate/main.tf b/terraform/modules/tfstate/main.tf new file mode 100644 index 0000000..de4e477 --- /dev/null +++ b/terraform/modules/tfstate/main.tf @@ -0,0 +1,45 @@ +resource "aws_s3_bucket" "tfstate" { + bucket = "${var.project}-tfstate-${var.owner}-${var.identifier}" + + force_destroy = true +} + +resource "aws_s3_bucket_public_access_block" "default" { + bucket = aws_s3_bucket.tfstate.id + + block_public_acls = true + block_public_policy = true + ignore_public_acls = true + restrict_public_buckets = true +} + +# https://avd.aquasec.com/misconfig/aws/s3/avd-aws-0132/ +# trivy:ignore:AVD-AWS-0132 +resource "aws_s3_bucket_server_side_encryption_configuration" "default" { + bucket = aws_s3_bucket.tfstate.bucket + + rule { + apply_server_side_encryption_by_default { + sse_algorithm = "aws:kms" + } + } +} + +resource "aws_s3_bucket_versioning" "default" { + bucket = aws_s3_bucket.tfstate.id + versioning_configuration { + status = "Enabled" + } +} + +# Create a DynamoDB table for locking the state file +resource "aws_dynamodb_table" "tfstate_lock" { + name = "${var.project}-tfstate-lock-${var.owner}-${var.identifier}" + hash_key = "LockID" + billing_mode = "PAY_PER_REQUEST" + + attribute { + name = "LockID" + type = "S" + } +} From 8282e9751bf1f693978a2b83d07e9892eac9cf3a Mon Sep 17 00:00:00 2001 From: Alis Akers Date: Tue, 15 Oct 2024 14:44:51 -0700 Subject: [PATCH 3/9] update setup to use a module for state and oidc management additions --- .github/workflows/deployment.yaml | 2 +- terraform/implementation/ecs/deploy.sh | 4 +- terraform/implementation/ecs/main.tf | 2 +- terraform/implementation/setup/_local.tf | 8 -- terraform/implementation/setup/backend.tf | 16 ++++ terraform/implementation/setup/main.tf | 95 +++++------------------ terraform/implementation/setup/setup.sh | 42 +++++++--- terraform/modules/oidc/_data.tf | 2 +- terraform/modules/oidc/_variable.tf | 14 +++- terraform/modules/tfstate/_variable.tf | 16 +++- 10 files changed, 98 insertions(+), 103 deletions(-) delete mode 100644 terraform/implementation/setup/_local.tf diff --git a/.github/workflows/deployment.yaml b/.github/workflows/deployment.yaml index 2c43faa..f9fe4e4 100644 --- a/.github/workflows/deployment.yaml +++ b/.github/workflows/deployment.yaml @@ -23,7 +23,7 @@ env: aws_region: us-east-1 environment: ${{ github.event.inputs.environment }} owner: "skylight" - project: "dibbs-ce" + project: "dibbs" jobs: terraform: diff --git a/terraform/implementation/ecs/deploy.sh b/terraform/implementation/ecs/deploy.sh index 3bd0827..10a3ba2 100755 --- a/terraform/implementation/ecs/deploy.sh +++ b/terraform/implementation/ecs/deploy.sh @@ -94,8 +94,8 @@ if [ "$CI" = false ]; then fi if ! grep -q "project" "$ENVIRONMENT.tfvars"; then - read -p "What is this project called? ( default=dibbs-ce ): " project_choice - project_choice=${project_choice:-dibbs-ce} + read -p "What is this project called? ( default=dibbs ): " project_choice + project_choice=${project_choice:-dibbs} echo "project = \"$project_choice\"" >> "$ENVIRONMENT.tfvars" fi diff --git a/terraform/implementation/ecs/main.tf b/terraform/implementation/ecs/main.tf index 9c2fd7e..e396440 100644 --- a/terraform/implementation/ecs/main.tf +++ b/terraform/implementation/ecs/main.tf @@ -35,5 +35,5 @@ module "ecs" { # internal = false # If the intent is to disable authentication, set ecr_viewer_app_env to "test" (default is "prod") - # ecr_viewer_app_env = "test" + ecr_viewer_app_env = "test" } diff --git a/terraform/implementation/setup/_local.tf b/terraform/implementation/setup/_local.tf deleted file mode 100644 index 8e1dc94..0000000 --- a/terraform/implementation/setup/_local.tf +++ /dev/null @@ -1,8 +0,0 @@ -locals { - vpc_name = "${var.project}-${var.owner}-${terraform.workspace}" - tags = { - project = var.project - owner = var.owner - workspace = terraform.workspace - } -} diff --git a/terraform/implementation/setup/backend.tf b/terraform/implementation/setup/backend.tf index 12c0dbe..17efe2e 100644 --- a/terraform/implementation/setup/backend.tf +++ b/terraform/implementation/setup/backend.tf @@ -1,3 +1,19 @@ terraform { backend "s3" {} + required_providers { + aws = { + source = "hashicorp/aws" + version = "=5.70.0" + } + } +} +provider "aws" { + region = "us-east-1" + default_tags { + tags = { + owner = "skylight" + environment = "tfstate" + project = "dibbs" + } + } } diff --git a/terraform/implementation/setup/main.tf b/terraform/implementation/setup/main.tf index e46a5ef..35c6574 100644 --- a/terraform/implementation/setup/main.tf +++ b/terraform/implementation/setup/main.tf @@ -1,14 +1,15 @@ -# Credentials should be provided by using the AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY environment variables. -provider "aws" { +resource "random_string" "setup" { + length = 8 + special = false + upper = false +} + +module "tfstate" { + source = "../../modules/tfstate" + identifier = random_string.setup.result + owner = var.owner + project = var.project region = var.region - default_tags { - tags = { - owner = var.owner - workspace = terraform.workspace - project = var.project - id = random_string.setup.result - } - } } # GitHub OIDC for prod @@ -26,79 +27,19 @@ module "oidc" { # This variable must match the name of the terraform workspace that you'll be using for your ECS module call in the /ecs module workspace = "prod" - state_bucket_arn = aws_s3_bucket.tfstate.arn - dynamodb_table_arn = aws_dynamodb_table.tfstate_lock.arn -} - -resource "random_string" "setup" { - length = 8 - special = false - upper = false -} - -resource "aws_s3_bucket" "tfstate" { - bucket = "${var.project}-tfstate-${var.owner}-${random_string.setup.result}" - - force_destroy = true -} - -resource "aws_s3_bucket_public_access_block" "default" { - bucket = aws_s3_bucket.tfstate.id - - block_public_acls = true - block_public_policy = true - ignore_public_acls = true - restrict_public_buckets = true -} - -# https://avd.aquasec.com/misconfig/aws/s3/avd-aws-0132/ -# trivy:ignore:AVD-AWS-0132 -resource "aws_s3_bucket_server_side_encryption_configuration" "default" { - bucket = aws_s3_bucket.tfstate.bucket - - rule { - apply_server_side_encryption_by_default { - sse_algorithm = "aws:kms" - } - } -} - -resource "aws_s3_bucket_versioning" "default" { - bucket = aws_s3_bucket.tfstate.id - versioning_configuration { - status = "Enabled" - } -} - -# Create a DynamoDB table for locking the state file -resource "aws_dynamodb_table" "tfstate_lock" { - name = "${var.project}-tfstate-lock-${var.owner}-${random_string.setup.result}" - hash_key = "LockID" - billing_mode = "PAY_PER_REQUEST" - - attribute { - name = "LockID" - type = "S" - } + # state_bucket_arn = module.tfstate.aws_s3_bucket.tfstate.arn + state_bucket_arn = module.tfstate.state_bucket.arn + # dynamodb_table_arn = aws_dynamodb_table.tfstate_lock.arn + dynamodb_table_arn = module.tfstate.dynamodb_table.arn } resource "local_file" "setup_env" { content = <<-EOT WORKSPACE="${terraform.workspace}" - BUCKET="${aws_s3_bucket.tfstate.bucket}" - DYNAMODB_TABLE="${aws_dynamodb_table.tfstate_lock.id}" + BUCKET="${module.tfstate.state_bucket.bucket}" + DYNAMODB_TABLE="${module.tfstate.dynamodb_table.arn}" REGION="${var.region}" TERRAFORM_ROLE="${module.oidc.role.arn}" EOT filename = ".env" -} - -resource "local_file" "ecs_env" { - content = <<-EOT - BUCKET="${aws_s3_bucket.tfstate.bucket}" - DYNAMODB_TABLE="${aws_dynamodb_table.tfstate_lock.id}" - REGION="${var.region}" - TERRAFORM_ROLE="${module.oidc.role.arn}" - EOT - filename = "../ecs/.env" -} +} \ No newline at end of file diff --git a/terraform/implementation/setup/setup.sh b/terraform/implementation/setup/setup.sh index f9800b2..0221e84 100755 --- a/terraform/implementation/setup/setup.sh +++ b/terraform/implementation/setup/setup.sh @@ -2,6 +2,34 @@ WORKSPACE=tfstate +# write a function with aruments to set the backend +set_backend () { + region=$(grep "region" "$WORKSPACE.tfvars" | cut -d'=' -f2 | tr -d ' "') + owner=$(grep "owner" "$WORKSPACE.tfvars" | cut -d'=' -f2 | tr -d ' "') + project=$(grep "project" "$WORKSPACE.tfvars" | cut -d'=' -f2 | tr -d ' "') +cat > backend.tf <> "$WORKSPACE.tfvars" fi @@ -72,9 +100,7 @@ if [ "$USE_S3_BACKEND" == "true" ]; then -backend-config "dynamodb_table=$DYNAMODB_TABLE" \ -backend-config "region=$REGION" else -echo "terraform { - backend \"local\" {} -}" > backend.tf + set_backend "local" terraform init -var-file="$WORKSPACE.tfvars" fi @@ -92,13 +118,9 @@ terraform apply -var-file="$WORKSPACE.tfvars" if [ "$USE_S3_BACKEND" == "false" ]; then echo "Setting up your s3 terraform backend" if [ -f .env ]; then - export $(cat ../ecs/.env | xargs) + export $(cat .env | xargs) fi - -echo "terraform { - backend \"s3\" {} -}" > backend.tf - + set_backend "s3" terraform init \ -var-file="$WORKSPACE.tfvars" \ -migrate-state \ diff --git a/terraform/modules/oidc/_data.tf b/terraform/modules/oidc/_data.tf index 8c5e361..3081936 100644 --- a/terraform/modules/oidc/_data.tf +++ b/terraform/modules/oidc/_data.tf @@ -194,7 +194,7 @@ data "aws_iam_policy_document" "request_tags_create_actions" { ] resources = [ "arn:aws:appmesh:${var.region}:${data.aws_caller_identity.current.account_id}:mesh/${local.project_owner_workspace}", - "arn:aws:appmesh:${var.region}:${data.aws_caller_identity.current.account_id}:mesh/${local.project_owner_workspace}/*", + "arn:aws:appmesh:${var.region}:${data.aws_caller_identity.current.account_id}:mesh/${local.project_owner_workspace}/*", "arn:aws:ec2:${var.region}:${data.aws_caller_identity.current.account_id}:vpc/${local.vpc_id}", "arn:aws:ec2:${var.region}:${data.aws_caller_identity.current.account_id}:vpc-endpoint/*", "arn:aws:ec2:${var.region}:${data.aws_caller_identity.current.account_id}:vpc-flow-log/*", diff --git a/terraform/modules/oidc/_variable.tf b/terraform/modules/oidc/_variable.tf index 91b2d7e..4ba5a50 100644 --- a/terraform/modules/oidc/_variable.tf +++ b/terraform/modules/oidc/_variable.tf @@ -2,24 +2,36 @@ variable "oidc_github_repo" { description = "The GitHub repository for OIDC" type = string default = "" + validation { + condition = length(var.oidc_github_repo) == 0 || can(regex("^[a-zA-Z0-9-]+/[a-zA-Z0-9-]+$", var.oidc_github_repo)) + error_message = "oidc_github_repo must be set with 'org/repo' format or blank" + } } variable "owner" { description = "The owner of the project" type = string default = "skylight" + validation { + condition = can(regex("^[[:alnum:]]{1,8}$", var.owner)) + error_message = "owner must be 8 characters or less, all lowerspace with no special characters or spaces" + } } variable "project" { description = "The name of the project" type = string - default = "dibbs-ce" + default = "dibbs" } variable "region" { type = string description = "The AWS region where resources are created" default = "" + validation { + condition = can(regex("^(us|eu|ap|sa|ca|cn|af|me|eu)-[[:alnum:]]{2,10}-[0-9]$", var.region)) + error_message = "region must be a valid AWS region" + } } variable "workspace" { diff --git a/terraform/modules/tfstate/_variable.tf b/terraform/modules/tfstate/_variable.tf index 2bc7a1b..1c3f694 100644 --- a/terraform/modules/tfstate/_variable.tf +++ b/terraform/modules/tfstate/_variable.tf @@ -2,21 +2,33 @@ variable "owner" { description = "The owner of the project" type = string default = "skylight" + validation { + condition = can(regex("^[[:alnum:]]{1,8}$", var.owner)) + error_message = "owner must be 8 characters/numbers or less, all lowerspace with no special characters or spaces" + } } variable "project" { description = "The name of the project" type = string - default = "dibbs-ce" + default = "dibbs" } variable "region" { type = string description = "The AWS region where resources are created" - default = "us-east-1" + default = "" + validation { + condition = can(regex("^(us)-[[:alnum:]]{2,10}-[0-9]$", var.region)) + error_message = "region must be a valid AWS region" + } } variable "identifier" { type = string default = "" + validation { + condition = can(regex("^[[:alnum:]]{1,8}$", var.identifier)) + error_message = "identifier must be 8 characters or less, all lowercase with no special characters or spaces" + } } \ No newline at end of file From 6f74a20632ca80280d146ae009148f0874c52e86 Mon Sep 17 00:00:00 2001 From: Alis Akers Date: Tue, 15 Oct 2024 14:45:50 -0700 Subject: [PATCH 4/9] update docs --- terraform/implementation/ecs/README.md | 10 +++++----- terraform/implementation/ecs/_variable.tf | 2 +- terraform/implementation/setup/README.md | 14 +++++--------- terraform/implementation/setup/_variable.tf | 2 +- terraform/implementation/setup/main.tf | 10 +++++----- terraform/modules/ecs/README.md | 2 +- terraform/modules/oidc/_variable.tf | 2 +- terraform/modules/tfstate/_variable.tf | 2 +- 8 files changed, 20 insertions(+), 24 deletions(-) diff --git a/terraform/implementation/ecs/README.md b/terraform/implementation/ecs/README.md index e78e653..44450b6 100644 --- a/terraform/implementation/ecs/README.md +++ b/terraform/implementation/ecs/README.md @@ -9,7 +9,7 @@ | Name | Version | |------|---------| -| [aws](#provider\_aws) | 5.56.1 | +| [aws](#provider\_aws) | =5.56.1 | ## Modules @@ -28,7 +28,7 @@ | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| -| [availability\_zones](#input\_availability\_zones) | The availability zones to use | `list(string)` |
[
"us-east-1a",
"us-east-1b",
"us-east-1c"
]
| no | +| [availability\_zones](#input\_availability\_zones) | The availability zones to use | `list(string)` |
[
"us-east-1a",
"us-east-1b",
"us-east-1c"
]
| no | | [create\_internet\_gateway](#input\_create\_internet\_gateway) | Flag to determine if an internet gateway should be created | `bool` | `false` | no | | [ecr\_viewer\_database\_schema](#input\_ecr\_viewer\_database\_schema) | The database schema used for the eCR data tables | `string` | `"core"` | no | | [ecr\_viewer\_database\_type](#input\_ecr\_viewer\_database\_type) | The SQL variant used for the eCR data tables | `string` | `"postgres"` | no | @@ -36,9 +36,9 @@ | [enable\_nat\_gateway](#input\_enable\_nat\_gateway) | Enable NAT Gateway | `bool` | `false` | no | | [owner](#input\_owner) | The owner of the infrastructure | `string` | `"skylight"` | no | | [phdi\_version](#input\_phdi\_version) | PHDI container image version | `string` | `"v1.4.4"` | no | -| [private\_subnets](#input\_private\_subnets) | The private subnets | `list(string)` |
[
"176.24.1.0/24",
"176.24.3.0/24"
]
| no | -| [project](#input\_project) | The project name | `string` | `"dibbs-ce"` | no | -| [public\_subnets](#input\_public\_subnets) | The public subnets | `list(string)` |
[
"176.24.2.0/24",
"176.24.4.0/24"
]
| no | +| [private\_subnets](#input\_private\_subnets) | The private subnets | `list(string)` |
[
"176.24.1.0/24",
"176.24.3.0/24"
]
| no | +| [project](#input\_project) | The project name | `string` | `"dibbs"` | no | +| [public\_subnets](#input\_public\_subnets) | The public subnets | `list(string)` |
[
"176.24.2.0/24",
"176.24.4.0/24"
]
| no | | [region](#input\_region) | AWS region | `string` | `"us-east-1"` | no | | [single\_nat\_gateway](#input\_single\_nat\_gateway) | Single NAT Gateway | `bool` | `false` | no | | [vpc](#input\_vpc) | The name of the VPC | `string` | `"ecs-vpc"` | no | diff --git a/terraform/implementation/ecs/_variable.tf b/terraform/implementation/ecs/_variable.tf index c09f967..6eef68e 100644 --- a/terraform/implementation/ecs/_variable.tf +++ b/terraform/implementation/ecs/_variable.tf @@ -44,7 +44,7 @@ variable "private_subnets" { variable "project" { description = "The project name" type = string - default = "dibbs-ce" + default = "dibbs" } variable "public_subnets" { diff --git a/terraform/implementation/setup/README.md b/terraform/implementation/setup/README.md index 1c95943..da50e74 100644 --- a/terraform/implementation/setup/README.md +++ b/terraform/implementation/setup/README.md @@ -1,13 +1,14 @@ ## Requirements -No requirements. +| Name | Version | +|------|---------| +| [aws](#requirement\_aws) | =5.70.0 | ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | 5.70.0 | | [local](#provider\_local) | 2.5.2 | | [random](#provider\_random) | 3.6.3 | @@ -16,17 +17,12 @@ No requirements. | Name | Source | Version | |------|--------|---------| | [oidc](#module\_oidc) | ../../modules/oidc | n/a | +| [tfstate](#module\_tfstate) | ../../modules/tfstate | n/a | ## Resources | Name | Type | |------|------| -| [aws_dynamodb_table.tfstate_lock](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/dynamodb_table) | resource | -| [aws_s3_bucket.tfstate](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket) | resource | -| [aws_s3_bucket_public_access_block.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_public_access_block) | resource | -| [aws_s3_bucket_server_side_encryption_configuration.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_server_side_encryption_configuration) | resource | -| [aws_s3_bucket_versioning.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_bucket_versioning) | resource | -| [local_file.ecs_env](https://registry.terraform.io/providers/hashicorp/local/latest/docs/resources/file) | resource | | [local_file.setup_env](https://registry.terraform.io/providers/hashicorp/local/latest/docs/resources/file) | resource | | [random_string.setup](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/string) | resource | @@ -36,7 +32,7 @@ No requirements. |------|-------------|------|---------|:--------:| | [oidc\_github\_repo](#input\_oidc\_github\_repo) | The GitHub repository for OIDC | `string` | `""` | no | | [owner](#input\_owner) | The owner of the project | `string` | `"skylight"` | no | -| [project](#input\_project) | The name of the project | `string` | `"dibbs-ce"` | no | +| [project](#input\_project) | The name of the project | `string` | `"dibbs"` | no | | [region](#input\_region) | The AWS region where resources are created | `string` | `"us-east-1"` | no | ## Outputs diff --git a/terraform/implementation/setup/_variable.tf b/terraform/implementation/setup/_variable.tf index 1f33a4b..48d81c0 100644 --- a/terraform/implementation/setup/_variable.tf +++ b/terraform/implementation/setup/_variable.tf @@ -13,7 +13,7 @@ variable "owner" { variable "project" { description = "The name of the project" type = string - default = "dibbs-ce" + default = "dibbs" } variable "region" { diff --git a/terraform/implementation/setup/main.tf b/terraform/implementation/setup/main.tf index 35c6574..2d25ae0 100644 --- a/terraform/implementation/setup/main.tf +++ b/terraform/implementation/setup/main.tf @@ -5,11 +5,11 @@ resource "random_string" "setup" { } module "tfstate" { - source = "../../modules/tfstate" + source = "../../modules/tfstate" identifier = random_string.setup.result - owner = var.owner - project = var.project - region = var.region + owner = var.owner + project = var.project + region = var.region } # GitHub OIDC for prod @@ -28,7 +28,7 @@ module "oidc" { workspace = "prod" # state_bucket_arn = module.tfstate.aws_s3_bucket.tfstate.arn - state_bucket_arn = module.tfstate.state_bucket.arn + state_bucket_arn = module.tfstate.state_bucket.arn # dynamodb_table_arn = aws_dynamodb_table.tfstate_lock.arn dynamodb_table_arn = module.tfstate.dynamodb_table.arn } diff --git a/terraform/modules/ecs/README.md b/terraform/modules/ecs/README.md index 5ec2d8f..afe73bb 100644 --- a/terraform/modules/ecs/README.md +++ b/terraform/modules/ecs/README.md @@ -93,7 +93,7 @@ No modules. | [region](#input\_region) | The AWS region where resources are created | `string` | n/a | yes | | [s3\_viewer\_bucket\_name](#input\_s3\_viewer\_bucket\_name) | Name of the S3 bucket for the viewer | `string` | `""` | no | | [s3\_viewer\_bucket\_role\_name](#input\_s3\_viewer\_bucket\_role\_name) | Name of the IAM role for the ecr-viewer bucket | `string` | `""` | no | -| [service\_data](#input\_service\_data) | Data for the DIBBS services |
map(object({
short_name = string
fargate_cpu = number
fargate_memory = number
app_count = number
app_image = string
app_version = string
container_port = number
host_port = number
public = bool
registry_url = string
env_vars = list(object({
name = string
value = string
}))
}))
| `{}` | no | +| [service\_data](#input\_service\_data) | Data for the DIBBS services |
map(object({
short_name = string
fargate_cpu = number
fargate_memory = number
app_count = number
app_image = string
app_version = string
container_port = number
host_port = number
public = bool
registry_url = string
env_vars = list(object({
name = string
value = string
}))
}))
| `{}` | no | | [tags](#input\_tags) | Tags to apply to resources | `map(string)` | `{}` | no | | [vpc\_id](#input\_vpc\_id) | ID of the VPC | `string` | n/a | yes | diff --git a/terraform/modules/oidc/_variable.tf b/terraform/modules/oidc/_variable.tf index 4ba5a50..90dfc8c 100644 --- a/terraform/modules/oidc/_variable.tf +++ b/terraform/modules/oidc/_variable.tf @@ -28,7 +28,7 @@ variable "region" { type = string description = "The AWS region where resources are created" default = "" - validation { + validation { condition = can(regex("^(us|eu|ap|sa|ca|cn|af|me|eu)-[[:alnum:]]{2,10}-[0-9]$", var.region)) error_message = "region must be a valid AWS region" } diff --git a/terraform/modules/tfstate/_variable.tf b/terraform/modules/tfstate/_variable.tf index 1c3f694..6973431 100644 --- a/terraform/modules/tfstate/_variable.tf +++ b/terraform/modules/tfstate/_variable.tf @@ -18,7 +18,7 @@ variable "region" { type = string description = "The AWS region where resources are created" default = "" - validation { + validation { condition = can(regex("^(us)-[[:alnum:]]{2,10}-[0-9]$", var.region)) error_message = "region must be a valid AWS region" } From 41f77a92d6c0803586e5903ea4b3cca221193aac Mon Sep 17 00:00:00 2001 From: Alis Akers Date: Tue, 15 Oct 2024 15:15:33 -0700 Subject: [PATCH 5/9] update deployment to be more configurable via secrets and variables --- .github/workflows/deployment.yaml | 34 ++++++++-------- terraform/implementation/ecs/deploy.sh | 54 +++++++++++++------------- terraform/implementation/ecs/main.tf | 2 +- 3 files changed, 44 insertions(+), 46 deletions(-) diff --git a/.github/workflows/deployment.yaml b/.github/workflows/deployment.yaml index f9fe4e4..04ade52 100644 --- a/.github/workflows/deployment.yaml +++ b/.github/workflows/deployment.yaml @@ -1,10 +1,11 @@ -name: Deploy to ECS +name: Deploy +run-name: Deploy to ${{ inputs.workspace }} by @${{ github.actor }} on: workflow_dispatch: inputs: - environment: - description: 'The environment to deploy to' + workspace: + description: 'The workspace to deploy to' required: true type: choice options: @@ -12,7 +13,7 @@ on: - prod concurrency: - group: ${{ github.event.inputs.environment }}-deploy + group: ${{ github.event.inputs.workspace }}-deploy cancel-in-progress: false permissions: @@ -20,10 +21,7 @@ permissions: contents: read env: - aws_region: us-east-1 - environment: ${{ github.event.inputs.environment }} - owner: "skylight" - project: "dibbs" + workspace: ${{ github.event.inputs.workspace }} jobs: terraform: @@ -45,23 +43,23 @@ jobs: with: role-to-assume: ${{ secrets.AWS_ROLE_ARN }} role-session-name: githubDeploymentWorkflow - aws-region: ${{ env.aws_region }} + aws-region: ${{ secrets.AWS_REGION }} - name: Terraform env: - ENVIRONMENT: ${{ env.environment }} + WORKSPACE: ${{ env.workspace }} BUCKET: ${{ secrets.TFSTATE_BUCKET }} DYNAMODB_TABLE: ${{ secrets.TFSTATE_DYNAMODB_TABLE }} - REGION: ${{ env.aws_region }} - OWNER: ${{ env.owner }} - PROJECT: ${{ env.project }} + REGION: ${{ secrets.AWS_REGION }} + OWNER: ${{ vars.OWNER }} + PROJECT: ${{ vars.PROJECT }} shell: bash run: | - echo "ENVIRONMENT=$ENVIRONMENT" >> .env + echo "WORKSPACE=$WORKSPACE" >> .env echo "BUCKET=$BUCKET" >> .env echo "DYNAMODB_TABLE=$DYNAMODB_TABLE" >> .env echo "REGION=$REGION" >> .env - echo "owner = \"$OWNER\"" >> $ENVIRONMENT.tfvars - echo "project = \"$PROJECT\"" >> $ENVIRONMENT.tfvars - echo "region = \"$REGION\"" >> $ENVIRONMENT.tfvars - ./deploy.sh -e $ENVIRONMENT --ci + echo "owner = \"$OWNER\"" >> $WORKSPACE.tfvars + echo "project = \"$PROJECT\"" >> $WORKSPACE.tfvars + echo "region = \"$REGION\"" >> $WORKSPACE.tfvars + ./deploy.sh -e $WORKSPACE --ci diff --git a/terraform/implementation/ecs/deploy.sh b/terraform/implementation/ecs/deploy.sh index 10a3ba2..d41e8b9 100755 --- a/terraform/implementation/ecs/deploy.sh +++ b/terraform/implementation/ecs/deploy.sh @@ -6,7 +6,7 @@ if [ -f .env ]; then fi # set default values -ENVIRONMENT="${ENVIRONMENT:-}" +WORKSPACE="${WORKSPACE:-}" BUCKET="${BUCKET:-}" DYNAMODB_TABLE="${DYNAMODB_TABLE:-}" REGION="${REGION:-}" @@ -20,7 +20,7 @@ do case $key in -env|--env|-e) - ENVIRONMENT="$2" + WORKSPACE="$2" shift shift ;; @@ -71,9 +71,9 @@ if ! command -v terraform &> /dev/null; then exit 1 fi -if [ -z "$ENVIRONMENT" ] || [ -z "$BUCKET" ] || [ -z "$DYNAMODB_TABLE" ] || [ -z "$REGION" ]; then +if [ -z "$WORKSPACE" ] || [ -z "$BUCKET" ] || [ -z "$DYNAMODB_TABLE" ] || [ -z "$REGION" ]; then echo "Missing required arguments. Please provide all the required arguments." - echo "ENVIRONMENT: $ENVIRONMENT" + echo "WORKSPACE: $WORKSPACE" echo "BUCKET: $BUCKET" echo "DYNAMODB_TABLE: $DYNAMODB_TABLE" echo "REGION: $REGION" @@ -82,41 +82,41 @@ if [ -z "$ENVIRONMENT" ] || [ -z "$BUCKET" ] || [ -z "$DYNAMODB_TABLE" ] || [ -z fi if [ "$CI" = false ]; then - if [ ! -f "$ENVIRONMENT.tfvars" ]; then - echo "Creating $ENVIRONMENT.tfvars" - touch "$ENVIRONMENT.tfvars" + if [ ! -f "$WORKSPACE.tfvars" ]; then + echo "Creating $WORKSPACE.tfvars" + touch "$WORKSPACE.tfvars" fi - if ! grep -q "owner" "$ENVIRONMENT.tfvars"; then + if ! grep -q "owner" "$WORKSPACE.tfvars"; then read -p "Who is the owner of this infrastructure? ( default=skylight ): " owner_choice owner_choice=${owner_choice:-skylight} - echo "owner = \"$owner_choice\"" >> "$ENVIRONMENT.tfvars" + echo "owner = \"$owner_choice\"" >> "$WORKSPACE.tfvars" fi - if ! grep -q "project" "$ENVIRONMENT.tfvars"; then + if ! grep -q "project" "$WORKSPACE.tfvars"; then read -p "What is this project called? ( default=dibbs ): " project_choice project_choice=${project_choice:-dibbs} - echo "project = \"$project_choice\"" >> "$ENVIRONMENT.tfvars" + echo "project = \"$project_choice\"" >> "$WORKSPACE.tfvars" fi - if ! grep -q "region" "$ENVIRONMENT.tfvars"; then + if ! grep -q "region" "$WORKSPACE.tfvars"; then read -p "What aws region are you setting up in? ( default=us-east-1 ): " region_choice region_choice=${region_choice:-us-east-1} - echo "region = \"$region_choice\"" >> "$ENVIRONMENT.tfvars" + echo "region = \"$region_choice\"" >> "$WORKSPACE.tfvars" fi fi echo "Running Terraform with the following variables:" -echo "Environment: $ENVIRONMENT" -echo "Terraform Workspace: $ENVIRONMENT" +echo "Environment: $WORKSPACE" +echo "Terraform Workspace: $WORKSPACE" echo "Bucket: $BUCKET" echo "DynamoDB Table: $DYNAMODB_TABLE" echo "Region: $REGION" -cat "$ENVIRONMENT.tfvars" +cat "$WORKSPACE.tfvars" echo "" terraform init \ - -var-file="$ENVIRONMENT.tfvars" \ + -var-file="$WORKSPACE.tfvars" \ -backend-config "bucket=$BUCKET" \ -backend-config "dynamodb_table=$DYNAMODB_TABLE" \ -backend-config "region=$REGION" \ @@ -124,27 +124,27 @@ terraform init \ # Check if workspace exists -if terraform workspace list | grep -q "$ENVIRONMENT"; then - echo "Selecting $ENVIRONMENT terraform workspace" - terraform workspace select "$ENVIRONMENT" +if terraform workspace list | grep -q "$WORKSPACE"; then + echo "Selecting $WORKSPACE terraform workspace" + terraform workspace select "$WORKSPACE" else if [ "$CI" = false ]; then - read -p "Workspace '$ENVIRONMENT' does not exist. Do you want to create it? (y/n): " choice + read -p "Workspace '$WORKSPACE' does not exist. Do you want to create it? (y/n): " choice if [[ $choice =~ ^[Yy]$ ]]; then - echo "Creating '$ENVIRONMENT' terraform workspace" - terraform workspace new "$ENVIRONMENT" + echo "Creating '$WORKSPACE' terraform workspace" + terraform workspace new "$WORKSPACE" else echo "Workspace creation cancelled." exit 1 fi else - echo "Creating '$ENVIRONMENT' terraform workspace" - terraform workspace new "$ENVIRONMENT" + echo "Creating '$WORKSPACE' terraform workspace" + terraform workspace new "$WORKSPACE" fi fi if [ "$CI" = false ]; then - terraform apply -var-file="$ENVIRONMENT.tfvars" + terraform apply -var-file="$WORKSPACE.tfvars" else - terraform apply -auto-approve -var-file="$ENVIRONMENT.tfvars" + terraform apply -auto-approve -var-file="$WORKSPACE.tfvars" fi diff --git a/terraform/implementation/ecs/main.tf b/terraform/implementation/ecs/main.tf index e396440..9c2fd7e 100644 --- a/terraform/implementation/ecs/main.tf +++ b/terraform/implementation/ecs/main.tf @@ -35,5 +35,5 @@ module "ecs" { # internal = false # If the intent is to disable authentication, set ecr_viewer_app_env to "test" (default is "prod") - ecr_viewer_app_env = "test" + # ecr_viewer_app_env = "test" } From 27d72e8f6acd2fdfb52844d60c9b8d133e222d3b Mon Sep 17 00:00:00 2001 From: Alis Akers Date: Wed, 16 Oct 2024 12:49:23 -0700 Subject: [PATCH 6/9] add a plan workflow --- .github/workflows/deployment.yaml | 39 ++++++++++++++++------- terraform/implementation/ecs/README.md | 1 + terraform/implementation/ecs/_variable.tf | 5 +++ terraform/implementation/ecs/main.tf | 19 +++++------ 4 files changed, 44 insertions(+), 20 deletions(-) diff --git a/.github/workflows/deployment.yaml b/.github/workflows/deployment.yaml index 04ade52..06cc0a1 100644 --- a/.github/workflows/deployment.yaml +++ b/.github/workflows/deployment.yaml @@ -1,19 +1,26 @@ -name: Deploy -run-name: Deploy to ${{ inputs.workspace }} by @${{ github.actor }} +name: Terraform (Plan||Apply) +run-name: Terraform ${{ inputs.terraform_action }} ${{ inputs.workspace }} by @${{ github.actor }} on: workflow_dispatch: inputs: workspace: - description: 'The workspace to deploy to' + description: 'The workspace to terraform against' required: true type: choice options: - "" - prod + terraform_action: + description: 'The terraform action to perform' + required: true + type: choice + options: + - plan + - apply concurrency: - group: ${{ github.event.inputs.workspace }}-deploy + group: ${{ github.event.inputs.workspace }}-terraform cancel-in-progress: false permissions: @@ -22,6 +29,7 @@ permissions: env: workspace: ${{ github.event.inputs.workspace }} + terraform_action: ${{ github.event.inputs.terraform_action }} jobs: terraform: @@ -47,19 +55,28 @@ jobs: - name: Terraform env: - WORKSPACE: ${{ env.workspace }} + ACTION: ${{ env.terraform_action }} BUCKET: ${{ secrets.TFSTATE_BUCKET }} DYNAMODB_TABLE: ${{ secrets.TFSTATE_DYNAMODB_TABLE }} - REGION: ${{ secrets.AWS_REGION }} OWNER: ${{ vars.OWNER }} PROJECT: ${{ vars.PROJECT }} + REGION: ${{ secrets.AWS_REGION }} + WORKSPACE: ${{ env.workspace }} shell: bash run: | - echo "WORKSPACE=$WORKSPACE" >> .env - echo "BUCKET=$BUCKET" >> .env - echo "DYNAMODB_TABLE=$DYNAMODB_TABLE" >> .env - echo "REGION=$REGION" >> .env echo "owner = \"$OWNER\"" >> $WORKSPACE.tfvars echo "project = \"$PROJECT\"" >> $WORKSPACE.tfvars echo "region = \"$REGION\"" >> $WORKSPACE.tfvars - ./deploy.sh -e $WORKSPACE --ci + terraform init \ + -var-file="$WORKSPACE.tfvars" \ + -backend-config "bucket=$BUCKET" \ + -backend-config "dynamodb_table=$DYNAMODB_TABLE" \ + -backend-config "region=$REGION" \ + || (echo "terraform init failed, exiting..." && exit 1) + terraform workspace select "$WORKSPACE" + if [ "$ACTION" == "plan" ]; then + terraform plan -var-file="$WORKSPACE.tfvars" + fi + if [ "$ACTION" == "apply" ]; then + terraform apply -auto-approve -var-file="$WORKSPACE.tfvars" + fi diff --git a/terraform/implementation/ecs/README.md b/terraform/implementation/ecs/README.md index 44450b6..8bf44c0 100644 --- a/terraform/implementation/ecs/README.md +++ b/terraform/implementation/ecs/README.md @@ -34,6 +34,7 @@ | [ecr\_viewer\_database\_type](#input\_ecr\_viewer\_database\_type) | The SQL variant used for the eCR data tables | `string` | `"postgres"` | no | | [ecs\_alb\_sg](#input\_ecs\_alb\_sg) | The security group for the Application Load Balancer | `string` | `"ecs-albsg"` | no | | [enable\_nat\_gateway](#input\_enable\_nat\_gateway) | Enable NAT Gateway | `bool` | `false` | no | +| [internal](#input\_internal) | Internal | `bool` | `true` | no | | [owner](#input\_owner) | The owner of the infrastructure | `string` | `"skylight"` | no | | [phdi\_version](#input\_phdi\_version) | PHDI container image version | `string` | `"v1.4.4"` | no | | [private\_subnets](#input\_private\_subnets) | The private subnets | `list(string)` |
[
"176.24.1.0/24",
"176.24.3.0/24"
]
| no | diff --git a/terraform/implementation/ecs/_variable.tf b/terraform/implementation/ecs/_variable.tf index 6eef68e..3743de6 100644 --- a/terraform/implementation/ecs/_variable.tf +++ b/terraform/implementation/ecs/_variable.tf @@ -4,6 +4,11 @@ variable "availability_zones" { default = ["us-east-1a", "us-east-1b", "us-east-1c"] } +variable "internal" { + description = "Internal" + type = bool + default = true +} variable "create_internet_gateway" { type = bool description = "Flag to determine if an internet gateway should be created" diff --git a/terraform/implementation/ecs/main.tf b/terraform/implementation/ecs/main.tf index 9c2fd7e..b77ffbb 100644 --- a/terraform/implementation/ecs/main.tf +++ b/terraform/implementation/ecs/main.tf @@ -1,14 +1,15 @@ module "vpc" { source = "terraform-aws-modules/vpc/aws" - name = local.vpc_name - cidr = var.vpc_cidr - azs = var.availability_zones - private_subnets = var.private_subnets - public_subnets = var.public_subnets - enable_nat_gateway = var.enable_nat_gateway - single_nat_gateway = var.single_nat_gateway - create_igw = var.create_internet_gateway + name = local.vpc_name + cidr = var.vpc_cidr + azs = var.availability_zones + private_subnets = var.private_subnets + public_subnets = var.public_subnets + # if internal is true, then the VPC will not have a NAT or internet gateway + enable_nat_gateway = var.internal ? false : true + single_nat_gateway = var.internal ? false : true + create_igw = var.internal ? false : true tags = local.tags } @@ -32,7 +33,7 @@ module "ecs" { # If the intent is to make the ecr-viewer availabble on the public internet, set internal to false (default is true) # This requires an internet gateway to be present in the VPC. - # internal = false + internal = var.internal # If the intent is to disable authentication, set ecr_viewer_app_env to "test" (default is "prod") # ecr_viewer_app_env = "test" From e0393f9cc36b444eda16f2b8ce9912332c74ed01 Mon Sep 17 00:00:00 2001 From: Alis Akers Date: Thu, 17 Oct 2024 11:15:06 -0700 Subject: [PATCH 7/9] Add max and min capacity for future autoscaling options --- terraform/modules/ecs/README.md | 2 ++ terraform/modules/ecs/_local.tf | 21 ++++++++++++++------- terraform/modules/ecs/ecs.tf | 7 ++++++- 3 files changed, 22 insertions(+), 8 deletions(-) diff --git a/terraform/modules/ecs/README.md b/terraform/modules/ecs/README.md index afe73bb..5d0a154 100644 --- a/terraform/modules/ecs/README.md +++ b/terraform/modules/ecs/README.md @@ -26,6 +26,8 @@ No modules. | [aws_alb_listener.http](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/alb_listener) | resource | | [aws_alb_listener_rule.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/alb_listener_rule) | resource | | [aws_alb_target_group.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/alb_target_group) | resource | +| [aws_appautoscaling_policy.ecs_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/appautoscaling_policy) | resource | +| [aws_appautoscaling_target.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/appautoscaling_target) | resource | | [aws_appmesh_mesh.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/appmesh_mesh) | resource | | [aws_appmesh_virtual_node.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/appmesh_virtual_node) | resource | | [aws_cloudwatch_log_group.ecs_cloudwatch_logs](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_group) | resource | diff --git a/terraform/modules/ecs/_local.tf b/terraform/modules/ecs/_local.tf index ab92c98..6d2c78d 100644 --- a/terraform/modules/ecs/_local.tf +++ b/terraform/modules/ecs/_local.tf @@ -14,7 +14,8 @@ locals { short_name = "ecrv", fargate_cpu = 1024, fargate_memory = 2048, - app_count = 1 + min_capacity = 1 + max_capacity = 5 app_image = var.disable_ecr == false ? "${terraform.workspace}-ecr-viewer" : "ecr-viewer", app_version = var.phdi_version, container_port = 3000, @@ -60,7 +61,8 @@ locals { short_name = "fhirc", fargate_cpu = 1024, fargate_memory = 2048, - app_count = 1 + min_capacity = 1 + max_capacity = 5 app_image = var.disable_ecr == false ? "${terraform.workspace}-fhir-converter" : "fhir-converter", app_version = var.phdi_version, container_port = 8080, @@ -73,7 +75,8 @@ locals { short_name = "inge", fargate_cpu = 1024, fargate_memory = 2048, - app_count = 1 + min_capacity = 1 + max_capacity = 5 app_image = var.disable_ecr == false ? "${terraform.workspace}-ingestion" : "ingestion", app_version = var.phdi_version, container_port = 8080, @@ -86,7 +89,8 @@ locals { short_name = "vali", fargate_cpu = 1024, fargate_memory = 2048, - app_count = 1 + min_capacity = 1 + max_capacity = 5 app_image = var.disable_ecr == false ? "${terraform.workspace}-validation" : "validation", app_version = var.phdi_version, container_port = 8080, @@ -99,7 +103,8 @@ locals { short_name = "trigcr", fargate_cpu = 1024, fargate_memory = 2048, - app_count = 1 + min_capacity = 1 + max_capacity = 5 app_image = var.disable_ecr == false ? "${terraform.workspace}-trigger-code-reference" : "trigger-code-reference", app_version = var.phdi_version, container_port = 8080, @@ -112,7 +117,8 @@ locals { short_name = "msgp", fargate_cpu = 1024, fargate_memory = 2048, - app_count = 1 + min_capacity = 1 + max_capacity = 5 app_image = var.disable_ecr == false ? "${terraform.workspace}-message-parser" : "message-parser", app_version = var.phdi_version, container_port = 8080, @@ -125,7 +131,8 @@ locals { short_name = "orch", fargate_cpu = 1024, fargate_memory = 2048, - app_count = 1 + min_capacity = 1 + max_capacity = 5 app_image = var.disable_ecr == false ? "${terraform.workspace}-orchestration" : "orchestration", app_version = var.phdi_version, container_port = 8080, diff --git a/terraform/modules/ecs/ecs.tf b/terraform/modules/ecs/ecs.tf index a09785f..a3ba35b 100644 --- a/terraform/modules/ecs/ecs.tf +++ b/terraform/modules/ecs/ecs.tf @@ -43,7 +43,7 @@ resource "aws_ecs_service" "this" { name = each.key cluster = aws_ecs_cluster.dibbs_app_cluster.id task_definition = each.value.arn - desired_count = local.service_data[each.key].app_count + desired_count = local.service_data[each.key].min_capacity launch_type = "FARGATE" scheduling_strategy = "REPLICA" @@ -108,5 +108,10 @@ resource "aws_ecs_service" "this" { } } } + + lifecycle { + ignore_changes = [desired_count] + } + tags = local.tags } From a7cf09c091a3095ab20d18cf3c92bb3825b615fd Mon Sep 17 00:00:00 2001 From: Alis Akers Date: Mon, 4 Nov 2024 11:50:48 -0800 Subject: [PATCH 8/9] separate out github workflows, typo and description updates --- ...{deployment.yaml => deployment_apply.yaml} | 22 ++---- .github/workflows/deployment_plan.yaml | 70 +++++++++++++++++++ terraform/implementation/ecs/README.md | 5 +- terraform/implementation/ecs/SERVICEDATA.md | 68 +++++++++++++----- terraform/implementation/ecs/_variable.tf | 19 +---- terraform/implementation/setup/setup.sh | 2 +- terraform/modules/ecs/README.md | 2 - terraform/modules/ecs/alb.tf | 2 - terraform/modules/oidc/_variable.tf | 2 +- terraform/modules/tfstate/_variable.tf | 2 +- 10 files changed, 131 insertions(+), 63 deletions(-) rename .github/workflows/{deployment.yaml => deployment_apply.yaml} (76%) create mode 100644 .github/workflows/deployment_plan.yaml diff --git a/.github/workflows/deployment.yaml b/.github/workflows/deployment_apply.yaml similarity index 76% rename from .github/workflows/deployment.yaml rename to .github/workflows/deployment_apply.yaml index 06cc0a1..b9f885e 100644 --- a/.github/workflows/deployment.yaml +++ b/.github/workflows/deployment_apply.yaml @@ -1,4 +1,4 @@ -name: Terraform (Plan||Apply) +name: Terraform Apply run-name: Terraform ${{ inputs.terraform_action }} ${{ inputs.workspace }} by @${{ github.actor }} on: @@ -11,13 +11,6 @@ on: options: - "" - prod - terraform_action: - description: 'The terraform action to perform' - required: true - type: choice - options: - - plan - - apply concurrency: group: ${{ github.event.inputs.workspace }}-terraform @@ -29,7 +22,7 @@ permissions: env: workspace: ${{ github.event.inputs.workspace }} - terraform_action: ${{ github.event.inputs.terraform_action }} + terraform_action: apply jobs: terraform: @@ -51,7 +44,7 @@ jobs: with: role-to-assume: ${{ secrets.AWS_ROLE_ARN }} role-session-name: githubDeploymentWorkflow - aws-region: ${{ secrets.AWS_REGION }} + aws-region: ${{ vars.AWS_REGION }} - name: Terraform env: @@ -60,7 +53,7 @@ jobs: DYNAMODB_TABLE: ${{ secrets.TFSTATE_DYNAMODB_TABLE }} OWNER: ${{ vars.OWNER }} PROJECT: ${{ vars.PROJECT }} - REGION: ${{ secrets.AWS_REGION }} + REGION: ${{ vars.AWS_REGION }} WORKSPACE: ${{ env.workspace }} shell: bash run: | @@ -74,9 +67,4 @@ jobs: -backend-config "region=$REGION" \ || (echo "terraform init failed, exiting..." && exit 1) terraform workspace select "$WORKSPACE" - if [ "$ACTION" == "plan" ]; then - terraform plan -var-file="$WORKSPACE.tfvars" - fi - if [ "$ACTION" == "apply" ]; then - terraform apply -auto-approve -var-file="$WORKSPACE.tfvars" - fi + terraform apply -auto-approve -var-file="$WORKSPACE.tfvars" diff --git a/.github/workflows/deployment_plan.yaml b/.github/workflows/deployment_plan.yaml new file mode 100644 index 0000000..9519cea --- /dev/null +++ b/.github/workflows/deployment_plan.yaml @@ -0,0 +1,70 @@ +name: Terraform Plan +run-name: Terraform ${{ inputs.terraform_action }} ${{ inputs.workspace }} by @${{ github.actor }} + +on: + workflow_dispatch: + inputs: + workspace: + description: 'The workspace to terraform against' + required: true + type: choice + options: + - "" + - prod + +concurrency: + group: ${{ github.event.inputs.workspace }}-terraform + cancel-in-progress: false + +permissions: + id-token: write + contents: read + +env: + workspace: ${{ github.event.inputs.workspace }} + terraform_action: plan + +jobs: + terraform: + name: Run Terraform + runs-on: ubuntu-latest + defaults: + run: + shell: bash + working-directory: ./terraform/implementation/ecs + steps: + - name: Check Out Changes + uses: actions/checkout@v4 + + - name: Setup Terraform + uses: hashicorp/setup-terraform@v3 + + - name: configure aws credentials + uses: aws-actions/configure-aws-credentials@v4 + with: + role-to-assume: ${{ secrets.AWS_ROLE_ARN }} + role-session-name: githubDeploymentWorkflow + aws-region: ${{ vars.AWS_REGION }} + + - name: Terraform + env: + ACTION: ${{ env.terraform_action }} + BUCKET: ${{ secrets.TFSTATE_BUCKET }} + DYNAMODB_TABLE: ${{ secrets.TFSTATE_DYNAMODB_TABLE }} + OWNER: ${{ vars.OWNER }} + PROJECT: ${{ vars.PROJECT }} + REGION: ${{ vars.AWS_REGION }} + WORKSPACE: ${{ env.workspace }} + shell: bash + run: | + echo "owner = \"$OWNER\"" >> $WORKSPACE.tfvars + echo "project = \"$PROJECT\"" >> $WORKSPACE.tfvars + echo "region = \"$REGION\"" >> $WORKSPACE.tfvars + terraform init \ + -var-file="$WORKSPACE.tfvars" \ + -backend-config "bucket=$BUCKET" \ + -backend-config "dynamodb_table=$DYNAMODB_TABLE" \ + -backend-config "region=$REGION" \ + || (echo "terraform init failed, exiting..." && exit 1) + terraform workspace select "$WORKSPACE" + terraform plan -var-file="$WORKSPACE.tfvars" diff --git a/terraform/implementation/ecs/README.md b/terraform/implementation/ecs/README.md index 8bf44c0..7a66cfa 100644 --- a/terraform/implementation/ecs/README.md +++ b/terraform/implementation/ecs/README.md @@ -29,19 +29,16 @@ | Name | Description | Type | Default | Required | |------|-------------|------|---------|:--------:| | [availability\_zones](#input\_availability\_zones) | The availability zones to use | `list(string)` |
[
"us-east-1a",
"us-east-1b",
"us-east-1c"
]
| no | -| [create\_internet\_gateway](#input\_create\_internet\_gateway) | Flag to determine if an internet gateway should be created | `bool` | `false` | no | | [ecr\_viewer\_database\_schema](#input\_ecr\_viewer\_database\_schema) | The database schema used for the eCR data tables | `string` | `"core"` | no | | [ecr\_viewer\_database\_type](#input\_ecr\_viewer\_database\_type) | The SQL variant used for the eCR data tables | `string` | `"postgres"` | no | | [ecs\_alb\_sg](#input\_ecs\_alb\_sg) | The security group for the Application Load Balancer | `string` | `"ecs-albsg"` | no | -| [enable\_nat\_gateway](#input\_enable\_nat\_gateway) | Enable NAT Gateway | `bool` | `false` | no | -| [internal](#input\_internal) | Internal | `bool` | `true` | no | +| [internal](#input\_internal) | Flag to determine if the several AWS resources are public (intended for external access, public internet) or private (only intended to be accessed within your AWS VPC or avaiable with other means, a transit gateway for example). | `bool` | `true` | no | | [owner](#input\_owner) | The owner of the infrastructure | `string` | `"skylight"` | no | | [phdi\_version](#input\_phdi\_version) | PHDI container image version | `string` | `"v1.4.4"` | no | | [private\_subnets](#input\_private\_subnets) | The private subnets | `list(string)` |
[
"176.24.1.0/24",
"176.24.3.0/24"
]
| no | | [project](#input\_project) | The project name | `string` | `"dibbs"` | no | | [public\_subnets](#input\_public\_subnets) | The public subnets | `list(string)` |
[
"176.24.2.0/24",
"176.24.4.0/24"
]
| no | | [region](#input\_region) | AWS region | `string` | `"us-east-1"` | no | -| [single\_nat\_gateway](#input\_single\_nat\_gateway) | Single NAT Gateway | `bool` | `false` | no | | [vpc](#input\_vpc) | The name of the VPC | `string` | `"ecs-vpc"` | no | | [vpc\_cidr](#input\_vpc\_cidr) | The CIDR block for the VPC | `string` | `"176.24.0.0/16"` | no | diff --git a/terraform/implementation/ecs/SERVICEDATA.md b/terraform/implementation/ecs/SERVICEDATA.md index 2550905..a28d0ea 100644 --- a/terraform/implementation/ecs/SERVICEDATA.md +++ b/terraform/implementation/ecs/SERVICEDATA.md @@ -6,12 +6,14 @@ service_data = { short_name = "ecrv", fargate_cpu = 1024, fargate_memory = 2048, - app_count = 1 - app_image = "${data.aws_caller_identity.current.account_id}.dkr.ecr.${var.region}.amazonaws.com/${terraform.workspace}-ecr-viewer", + min_capacity = 1 + max_capacity = 5 + app_image = var.disable_ecr == false ? "${terraform.workspace}-ecr-viewer" : "ecr-viewer", app_version = var.phdi_version, container_port = 3000, host_port = 3000, public = true + registry_url = local.registry_url env_vars = [ { name = "AWS_REGION", @@ -24,6 +26,26 @@ service_data = { { name = "HOSTNAME", value = "0.0.0.0" + }, + { + name = "NEXT_PUBLIC_NON_INTEGRATED_VIEWER", + value = var.non_integrated_viewer + }, + { + name = "SOURCE", + value = "s3" + }, + { + name = "APP_ENV", + value = var.ecr_viewer_app_env + }, + { + name = "NBS_PUB_KEY", + value = var.ecr_viewer_auth_pub_key + }, + { + name = "NEXT_PUBLIC_BASEPATH", + value = var.ecr_viewer_basepath } ] }, @@ -31,79 +53,91 @@ service_data = { short_name = "fhirc", fargate_cpu = 1024, fargate_memory = 2048, - app_count = 1 - app_image = "${data.aws_caller_identity.current.account_id}.dkr.ecr.${var.region}.amazonaws.com/${terraform.workspace}-fhir-converter", + min_capacity = 1 + max_capacity = 5 + app_image = var.disable_ecr == false ? "${terraform.workspace}-fhir-converter" : "fhir-converter", app_version = var.phdi_version, container_port = 8080, host_port = 8080, public = false + registry_url = local.registry_url env_vars = [] }, ingestion = { short_name = "inge", fargate_cpu = 1024, fargate_memory = 2048, - app_count = 1 - app_image = "${data.aws_caller_identity.current.account_id}.dkr.ecr.${var.region}.amazonaws.com/${terraform.workspace}-ingestion", + min_capacity = 1 + max_capacity = 5 + app_image = var.disable_ecr == false ? "${terraform.workspace}-ingestion" : "ingestion", app_version = var.phdi_version, container_port = 8080, host_port = 8080, public = false + registry_url = local.registry_url env_vars = [] }, validation = { short_name = "vali", fargate_cpu = 1024, fargate_memory = 2048, - app_count = 1 - app_image = "${data.aws_caller_identity.current.account_id}.dkr.ecr.${var.region}.amazonaws.com/${terraform.workspace}-validation", + min_capacity = 1 + max_capacity = 5 + app_image = var.disable_ecr == false ? "${terraform.workspace}-validation" : "validation", app_version = var.phdi_version, container_port = 8080, host_port = 8080, public = false + registry_url = local.registry_url env_vars = [] }, trigger-code-reference = { short_name = "trigcr", fargate_cpu = 1024, fargate_memory = 2048, - app_count = 1 - app_image = "${data.aws_caller_identity.current.account_id}.dkr.ecr.${var.region}.amazonaws.com/${terraform.workspace}-trigger-code-reference", + min_capacity = 1 + max_capacity = 5 + app_image = var.disable_ecr == false ? "${terraform.workspace}-trigger-code-reference" : "trigger-code-reference", app_version = var.phdi_version, container_port = 8080, host_port = 8080, public = false + registry_url = local.registry_url env_vars = [] }, message-parser = { short_name = "msgp", fargate_cpu = 1024, fargate_memory = 2048, - app_count = 1 - app_image = "${data.aws_caller_identity.current.account_id}.dkr.ecr.${var.region}.amazonaws.com/${terraform.workspace}-message-parser", + min_capacity = 1 + max_capacity = 5 + app_image = var.disable_ecr == false ? "${terraform.workspace}-message-parser" : "message-parser", app_version = var.phdi_version, container_port = 8080, host_port = 8080, public = false + registry_url = local.registry_url env_vars = [] }, orchestration = { short_name = "orch", fargate_cpu = 1024, fargate_memory = 2048, - app_count = 1 - app_image = "${data.aws_caller_identity.current.account_id}.dkr.ecr.${var.region}.amazonaws.com/${terraform.workspace}-orchestration", + min_capacity = 1 + max_capacity = 5 + app_image = var.disable_ecr == false ? "${terraform.workspace}-orchestration" : "orchestration", app_version = var.phdi_version, container_port = 8080, host_port = 8080, public = true + registry_url = local.registry_url env_vars = [ { - name = "OTEL_METRICS", + name = "OTEL_METRICS", value = "none" }, { - name = "OTEL_METRICS_EXPORTER", + name = "OTEL_METRICS_EXPORTER", value = "none" }, { @@ -120,7 +154,7 @@ service_data = { }, { name = "ECR_VIEWER_URL", - value = "http://ecr-viewer:3000" + value = "http://ecr-viewer:3000${var.ecr_viewer_basepath}" }, { name = "MESSAGE_PARSER_URL", diff --git a/terraform/implementation/ecs/_variable.tf b/terraform/implementation/ecs/_variable.tf index 3743de6..6eabe8b 100644 --- a/terraform/implementation/ecs/_variable.tf +++ b/terraform/implementation/ecs/_variable.tf @@ -5,15 +5,10 @@ variable "availability_zones" { } variable "internal" { - description = "Internal" + description = "Flag to determine if the several AWS resources are public (intended for external access, public internet) or private (only intended to be accessed within your AWS VPC or avaiable with other means, a transit gateway for example)." type = bool default = true } -variable "create_internet_gateway" { - type = bool - description = "Flag to determine if an internet gateway should be created" - default = false -} variable "ecs_alb_sg" { description = "The security group for the Application Load Balancer" @@ -21,12 +16,6 @@ variable "ecs_alb_sg" { default = "ecs-albsg" } -variable "enable_nat_gateway" { - description = "Enable NAT Gateway" - type = bool - default = false -} - variable "owner" { description = "The owner of the infrastructure" type = string @@ -64,12 +53,6 @@ variable "region" { default = "us-east-1" } -variable "single_nat_gateway" { - description = "Single NAT Gateway" - type = bool - default = false -} - variable "vpc" { description = "The name of the VPC" type = string diff --git a/terraform/implementation/setup/setup.sh b/terraform/implementation/setup/setup.sh index 0221e84..bff48ac 100755 --- a/terraform/implementation/setup/setup.sh +++ b/terraform/implementation/setup/setup.sh @@ -80,7 +80,7 @@ if ! grep -q "region" "$WORKSPACE.tfvars"; then fi if ! grep -q "oidc_github_repo" "$WORKSPACE.tfvars"; then - read -p "Do you want to setup a GitHub IODC role? (y/n): " github_choice + read -p "Do you want to setup a GitHub OIDC role? (y/n): " github_choice if [[ "$github_choice" =~ ^[Yy]$ ]]; then read -p "What is the organization/repo value for assume role? ( default=\"\" ): " repo_choice repo_choice=${repo_choice:-""} diff --git a/terraform/modules/ecs/README.md b/terraform/modules/ecs/README.md index 5d0a154..afe73bb 100644 --- a/terraform/modules/ecs/README.md +++ b/terraform/modules/ecs/README.md @@ -26,8 +26,6 @@ No modules. | [aws_alb_listener.http](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/alb_listener) | resource | | [aws_alb_listener_rule.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/alb_listener_rule) | resource | | [aws_alb_target_group.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/alb_target_group) | resource | -| [aws_appautoscaling_policy.ecs_policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/appautoscaling_policy) | resource | -| [aws_appautoscaling_target.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/appautoscaling_target) | resource | | [aws_appmesh_mesh.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/appmesh_mesh) | resource | | [aws_appmesh_virtual_node.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/appmesh_virtual_node) | resource | | [aws_cloudwatch_log_group.ecs_cloudwatch_logs](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_group) | resource | diff --git a/terraform/modules/ecs/alb.tf b/terraform/modules/ecs/alb.tf index bbcd289..c036e0f 100644 --- a/terraform/modules/ecs/alb.tf +++ b/terraform/modules/ecs/alb.tf @@ -1,5 +1,3 @@ -# https://avd.aquasec.com/misconfig/aws/elb/avd-aws-0053 -# trivy:ignore:AVD-AWS-0053 resource "aws_alb" "ecs" { name = local.ecs_alb_name internal = var.internal diff --git a/terraform/modules/oidc/_variable.tf b/terraform/modules/oidc/_variable.tf index 90dfc8c..4f8a8a5 100644 --- a/terraform/modules/oidc/_variable.tf +++ b/terraform/modules/oidc/_variable.tf @@ -14,7 +14,7 @@ variable "owner" { default = "skylight" validation { condition = can(regex("^[[:alnum:]]{1,8}$", var.owner)) - error_message = "owner must be 8 characters or less, all lowerspace with no special characters or spaces" + error_message = "owner must be 8 characters or less, all lowercase with no special characters or spaces" } } diff --git a/terraform/modules/tfstate/_variable.tf b/terraform/modules/tfstate/_variable.tf index 6973431..514d742 100644 --- a/terraform/modules/tfstate/_variable.tf +++ b/terraform/modules/tfstate/_variable.tf @@ -4,7 +4,7 @@ variable "owner" { default = "skylight" validation { condition = can(regex("^[[:alnum:]]{1,8}$", var.owner)) - error_message = "owner must be 8 characters/numbers or less, all lowerspace with no special characters or spaces" + error_message = "owner must be 8 characters/numbers or less, all lowercase with no special characters or spaces" } } From 6f6b3edac5659ec9037ab68b7e6e0c9c90eda6fd Mon Sep 17 00:00:00 2001 From: Alis Akers Date: Mon, 4 Nov 2024 12:09:11 -0800 Subject: [PATCH 9/9] update docs to include suggestions for directory/environment management --- .github/workflows/deployment_apply.yaml | 3 +++ .github/workflows/deployment_plan.yaml | 3 +++ README.md | 7 ++++--- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/.github/workflows/deployment_apply.yaml b/.github/workflows/deployment_apply.yaml index b9f885e..465f33f 100644 --- a/.github/workflows/deployment_apply.yaml +++ b/.github/workflows/deployment_apply.yaml @@ -31,6 +31,9 @@ jobs: defaults: run: shell: bash + # this may need to be updated if you change the directory you are working with + # ./terraform/implementation/dev || ./terraform/implementation/prod for example + # this practice is recommended to keep the terraform code organized while reducing the risk of conflicts working-directory: ./terraform/implementation/ecs steps: - name: Check Out Changes diff --git a/.github/workflows/deployment_plan.yaml b/.github/workflows/deployment_plan.yaml index 9519cea..7b58332 100644 --- a/.github/workflows/deployment_plan.yaml +++ b/.github/workflows/deployment_plan.yaml @@ -31,6 +31,9 @@ jobs: defaults: run: shell: bash + # this may need to be updated if you change the directory you are working with + # ./terraform/implementation/dev || ./terraform/implementation/prod for example + # this practice is recommended to keep the terraform code organized while reducing the risk of conflicts working-directory: ./terraform/implementation/ecs steps: - name: Check Out Changes diff --git a/README.md b/README.md index fc00f25..1ed6272 100644 --- a/README.md +++ b/README.md @@ -193,9 +193,10 @@ The setup.sh script will create the following files: ## 4.6 Run Terraform Code In Your Designated Environment 4.6.1. Run ECS Module Locally -* To run your ECS Module Changes in your local terminal, navigate to _terraform/implementation/ecs/_ and run the following command: `cd /terraform/implementation`. +* It is highly recommended to create a new directory per environment that is launched, to do so run `cp terraform/implementation/ecs terraform/implementation/{insertEnvironmentName}`. +* To run your ECS Module Changes in your local terminal, navigate to your working directory, ` cd terraform/implementation/ecs/` or `cd terraform/implementation/{insertEnvironmentName}` * In your terminal run the deploy script for your designated environment `./deploy.sh -e {insertEnvironmentName}`.\ -    Note: The _-e_ tag stands for environment and you can specify `dev`, `stage`, `prod` +    Note: The _-e_ tag stands for environment and you can specify `dev`, `stage`, `prod`, this can match your environment naming convention.     or whatever environment your team desires. [Return to Table of Contents](#table-of-contents). @@ -226,7 +227,7 @@ The setup.sh script will create the following files: ## 4.10 Update Variables 4.10.1. Update Other Default Variables -* Navigate to the _defaults.tfvars_ file `cd terraform/implementation/ecs/default.tfvars`. +* Navigate to the _defaults.tfvars_ file ` cd terraform/implementation/ecs/` or `cd terraform/implementation/{insertEnvironmentName}`. * In this _defaults.tfvars_ file, you can update and override any other default values. 4.10.2. Test and Validate Your Changes