Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 1 addition & 23 deletions deployment/ecs/envs/bo/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ module "ecs_service" {
memory = var.memory
health_check_path = var.health_check_path
mpath_exec = var.mpath_exec
readonly_root_filesystem = true
readonly_root_filesystem = var.readonly_root_filesystem
custom_domain_name = var.custom_domain_name
environment_variables = {
RAILS_ENV = "production"
Expand Down Expand Up @@ -135,25 +135,3 @@ resource "aws_secretsmanager_secret_version" "app" {
}


module "twingate_connector" {
source = "../../modules/twingate-connector"

# Network/cluster wiring
vpc_id = local.vpc_id
subnet_ids = local.private_subnet_ids
cluster_id = module.ecs_service.cluster_id
twingate_exec = var.twingate_exec
# Place the connector in private subnets, no public IP
assign_public_ip = false
desired_count = 1
cpu = 1024
memory = 2048

twingate_secret_path = var.twingate_secret_path

readonly_root_filesystem = true


tags = merge(local.tags, { Service = "TwingateConnector" })
}

6 changes: 4 additions & 2 deletions deployment/ecs/envs/bo/rds.tf
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ resource "aws_db_subnet_group" "this" {
tags = merge(local.tags, { Name = "${var.db_identifier}-subnets" })
}

# Security Group for RDS – allow MySQL from ECS tasks only
resource "aws_security_group" "rds_mysql" {
name = "${var.db_identifier}-sg"
description = "Allow MySQL from ECS tasks"
Expand All @@ -27,7 +26,9 @@ resource "aws_security_group" "rds_mysql" {
from_port = 3306
to_port = 3306
protocol = "tcp"
security_groups = [module.ecs_service.service_sg_id,module.twingate_connector.service_sg_id]
security_groups = [
module.ecs_service.service_sg_id
]
}

egress {
Expand All @@ -40,6 +41,7 @@ resource "aws_security_group" "rds_mysql" {
tags = merge(local.tags, { Name = "${var.db_identifier}-sg" })
}


# RDS Instance – MySQL 8, db.t3.micro, gp2, single-AZ
resource "aws_db_instance" "this" {
identifier = var.db_identifier
Expand Down
1 change: 0 additions & 1 deletion deployment/ecs/envs/bo/terraform.tfvars
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,5 @@ tags = {
}

db_secret_arn = aws_secretsmanager_secret.db.arn
twingate_exec = false
mpath_exec = false
custom_domain_name = "mpath-ecs-bo.microhealthllc.com"
17 changes: 6 additions & 11 deletions deployment/ecs/envs/bo/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -294,17 +294,6 @@ variable "use_ssl" {
}


variable "twingate_secret_path" {
description = "Optional path to the Twingate secret in AWS Secrets Manager (e.g., mpath/bo/twingate)."
type = string
default = ""
}

variable "twingate_exec" {
type = bool
default = false
}

variable "mpath_exec" {
type = bool
default = false
Expand All @@ -314,3 +303,9 @@ variable "custom_domain_name" {
description = "The domain allowed to access the ALB"
type = string
}

variable "readonly_root_filesystem" {
type = bool
default = true
description = "Whether to make the container's root filesystem read-only."
}
2 changes: 2 additions & 0 deletions deployment/ecs/envs/mgt/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
app_env.json
app_env*.json
5 changes: 5 additions & 0 deletions deployment/ecs/envs/mgt/backend.hcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
bucket = "mpath-terraform-remote-state"
key = "mpath/ecs/mgt/terraform.tfstate"
region = "us-east-1"
encrypt = true
use_lockfile = true
63 changes: 63 additions & 0 deletions deployment/ecs/envs/mgt/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}

backend "s3" {} # init with: terraform init -backend-config=backend.hcl
}

provider "aws" {
region = var.aws_region
}

# Pull shared network from the ROOT stack
data "terraform_remote_state" "root" {
backend = "s3"
config = {
bucket = "mpath-terraform-remote-state"
key = "mpath/vpc/terraform.tfstate"
region = var.aws_region
encrypt = true
}
}

locals {
vpc_id = data.terraform_remote_state.root.outputs.vpc_id
private_subnet_ids = data.terraform_remote_state.root.outputs.private_subnet_ids
public_subnet_ids = data.terraform_remote_state.root.outputs.public_subnet_ids

tags = {
ManagedBy = "Terraform"
}
}

module "twingate_connector" {
source = "../../modules/twingate-connector"

# Network wiring
vpc_id = local.vpc_id
subnet_ids = local.private_subnet_ids


# Place the connector in private subnets, no public IP
assign_public_ip = false

# Task sizing
desired_count = 1
cpu = 1024
memory = 2048
env = var.env

# Secrets
twingate_secret_path = var.twingate_secret_path

# Hardening
readonly_root_filesystem = var.readonly_root_filesystem

tags = merge(local.tags, {
Service = "TwingateConnector"
})
}
Empty file.
61 changes: 61 additions & 0 deletions deployment/ecs/envs/mgt/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
variable "aws_region" {
description = "AWS region to deploy resources"
type = string
default = "us-east-1"
}
variable "twingate_secret_path" {
description = "Path to the Twingate secret in AWS Secrets Manager"
type = string
}

# Optional KMS key(s) for encrypting secrets (used by ECS exec policy, etc.)
variable "kms_key_id" {
description = "Optional KMS key for encrypting the RDS secret or other app secrets."
type = string
default = null
}

variable "kms_key_arns" {
description = "Optional list of KMS key ARNs used to encrypt Secrets Manager secrets."
type = list(string)
default = []
}



variable "enable_log_encryption" {
description = "Whether to enable KMS encryption on CloudWatch Logs."
type = bool
default = false
}

variable "log_kms_key_id" {
description = "KMS key ID/ARN to use for CloudWatch Logs encryption when enable_log_encryption is true."
type = string
default = null
}


variable "cpu" {
description = "CPU units for the ECS task (256, 512, 1024, etc.)"
type = number
default = 512
}

variable "memory" {
description = "Memory for the ECS task (in MB)"
type = number
default = 1024
}


variable "env" {
description = "Short env name (e.g., bo, qa, prod)"
type = string
}

variable "readonly_root_filesystem" {
type = bool
default = true
description = "Whether to make the container's root filesystem read-only."
}
2 changes: 2 additions & 0 deletions deployment/ecs/envs/qa/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
app_env.json
app_env*.json
5 changes: 5 additions & 0 deletions deployment/ecs/envs/qa/backend.hcl
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
bucket = "mpath-terraform-remote-state"
key = "mpath/ecs/qa/terraform.tfstate"
region = "us-east-1"
encrypt = true
use_lockfile = true
137 changes: 137 additions & 0 deletions deployment/ecs/envs/qa/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
terraform {
required_providers {
aws = { source = "hashicorp/aws", version = "~> 5.0" }
}
backend "s3" {} # init with: terraform init -backend-config=backend.hcl
}

provider "aws" {
region = var.aws_region
}

locals {
app_name = "mpath"
env = var.environment
}


# Pull shared network from the ROOT stack
data "terraform_remote_state" "root" {
backend = "s3"
config = {
bucket = "mpath-terraform-remote-state"
key = "mpath/vpc/terraform.tfstate"
region = var.aws_region
encrypt = true
}
}

locals {
vpc_id = data.terraform_remote_state.root.outputs.vpc_id
private_subnet_ids = data.terraform_remote_state.root.outputs.private_subnet_ids
public_subnet_ids = data.terraform_remote_state.root.outputs.public_subnet_ids

tags = {
Project = local.app_name
Environment = local.env
ManagedBy = "Terraform"
}
}


data "aws_secretsmanager_secret_version" "mpath_cert" {
secret_id = "/mpath/acm/cert-arn"
}

locals {
_raw_cert_string = data.aws_secretsmanager_secret_version.mpath_cert.secret_string
_maybe_json = try(jsondecode(local._raw_cert_string), null)
_json_cert_arn = local._maybe_json == null ? "" : try(local._maybe_json.cert_arn, "")
acm_cert_from_sm = local._json_cert_arn != "" ? local._json_cert_arn : local._raw_cert_string

# Final selection: explicit var wins; else Secrets Manager
selected_acm_cert_arn = var.acm_certificate_arn != "" ? var.acm_certificate_arn : local.acm_cert_from_sm
# Or, if you’re worried about whitespace:
# selected_acm_cert_arn = trimspace(var.acm_certificate_arn) != "" ? var.acm_certificate_arn : local.acm_cert_from_sm
}



module "ecs_service" {
source = "../../modules/ecs"

cluster_name = "${local.app_name}-${local.env}"
service_name = "${local.app_name}-app-${local.env}"
vpc_id = local.vpc_id
subnet_ids = local.private_subnet_ids
db_secret_arn = aws_secretsmanager_secret.db.arn
app_secret_arn = aws_secretsmanager_secret.app.arn
# Container / service
container_image = var.container_image
container_port = var.container_port
desired_count = var.desired_count
cpu = var.cpu
memory = var.memory
health_check_path = var.health_check_path
mpath_exec = var.mpath_exec
readonly_root_filesystem = var.readonly_root_filesystem
custom_domain_name = var.custom_domain_name
environment_variables = {
RAILS_ENV = "production"
RAILS_SERVE_STATIC_FILES = "true"
NODE_ENV = "production"
}

# ALB/TG/listeners inside the module (per-env ALB)
create_alb = true
public_subnet_ids = local.public_subnet_ids
alb_name = "${local.app_name}-${local.env}-alb"
alb_deletion_protection = true
acm_certificate_arn = local.selected_acm_cert_arn
ssl_policy = var.ssl_policy

# Ops & deployments
platform_version = var.platform_version
deployment_maximum_percent = var.deployment_maximum_percent
deployment_minimum_healthy_percent = var.deployment_minimum_healthy_percent
deployment_circuit_breaker_enabled = var.deployment_circuit_breaker_enabled
deployment_circuit_breaker_rollback = var.deployment_circuit_breaker_rollback
container_insights_enabled = true
log_retention_days = var.log_retention_days
assign_public_ip = false
microsoft_secret_path = var.microsoft_secret_path
tags = local.tags
}


# Discover this env’s ALB (created by module.ecs_service)
data "aws_lb" "qa_alb" {
name = "${local.app_name}-${local.env}-alb"
depends_on = [module.ecs_service]
}

# Associate the root WAF to this ALB
resource "aws_wafv2_web_acl_association" "mpath_web_acl_assoc" {
resource_arn = data.aws_lb.qa_alb.arn
web_acl_arn = data.terraform_remote_state.root.outputs.waf_web_acl_arn
}

resource "random_password" "secret_key_base" {
length = 64
special = false
}

resource "aws_secretsmanager_secret" "app" {
name = "mpath/qa/app"
description = "mPATH qa app env"
}

resource "aws_secretsmanager_secret_version" "app" {
secret_id = aws_secretsmanager_secret.app.id
secret_string = jsonencode({
SECRET_KEY_BASE = random_password.secret_key_base.result
# ...other keys...
})
}


Loading