mirror of
https://github.com/Sea-Haven-Industries/afterhours-shift-manager.git
synced 2026-09-30 07:53:11 +00:00
fix(infra): own a dedicated VPC for Fargate (PLAT-216) (#260)
Prod has no default VPC; 10.70 is unused and matches the meals seam.
This commit is contained in:
parent
26adb8e6c0
commit
593cab66ef
5 changed files with 137 additions and 33 deletions
|
|
@ -2,22 +2,6 @@
|
|||
# image; Terraform ignores container_definitions after the bootstrap task
|
||||
# definition. Dual-run with API Gateway until the Fargate cutover.
|
||||
|
||||
data "aws_vpc" "default" {
|
||||
default = true
|
||||
}
|
||||
|
||||
data "aws_subnets" "default" {
|
||||
filter {
|
||||
name = "vpc-id"
|
||||
values = [data.aws_vpc.default.id]
|
||||
}
|
||||
|
||||
filter {
|
||||
name = "default-for-az"
|
||||
values = ["true"]
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_ecr_repository" "api" {
|
||||
name = local.project
|
||||
image_tag_mutability = "MUTABLE"
|
||||
|
|
@ -56,7 +40,7 @@ resource "aws_ecr_lifecycle_policy" "api" {
|
|||
resource "aws_security_group" "alb" {
|
||||
name = "${local.project}-alb"
|
||||
description = "Public ALB for afterhours-shift-manager"
|
||||
vpc_id = data.aws_vpc.default.id
|
||||
vpc_id = aws_vpc.this.id
|
||||
|
||||
ingress {
|
||||
description = "HTTP from the internet (health and pre-DNS)"
|
||||
|
|
@ -88,7 +72,7 @@ resource "aws_security_group" "alb" {
|
|||
resource "aws_security_group" "api" {
|
||||
name = "${local.project}-api"
|
||||
description = "Fargate tasks for afterhours-shift-manager"
|
||||
vpc_id = data.aws_vpc.default.id
|
||||
vpc_id = aws_vpc.this.id
|
||||
|
||||
ingress {
|
||||
description = "From ALB"
|
||||
|
|
@ -111,7 +95,7 @@ resource "aws_lb" "api" {
|
|||
load_balancer_type = "application"
|
||||
idle_timeout = 120
|
||||
security_groups = [aws_security_group.alb.id]
|
||||
subnets = data.aws_subnets.default.ids
|
||||
subnets = aws_subnet.public[*].id
|
||||
|
||||
drop_invalid_header_fields = true
|
||||
}
|
||||
|
|
@ -120,7 +104,7 @@ resource "aws_lb_target_group" "api" {
|
|||
name = "${local.project}-api"
|
||||
port = 8080
|
||||
protocol = "HTTP"
|
||||
vpc_id = data.aws_vpc.default.id
|
||||
vpc_id = aws_vpc.this.id
|
||||
target_type = "ip"
|
||||
|
||||
health_check {
|
||||
|
|
@ -276,7 +260,7 @@ resource "aws_ecs_service" "api" {
|
|||
deployment_maximum_percent = 200
|
||||
|
||||
network_configuration {
|
||||
subnets = data.aws_subnets.default.ids
|
||||
subnets = aws_subnet.public[*].id
|
||||
security_groups = [aws_security_group.api.id]
|
||||
assign_public_ip = true
|
||||
}
|
||||
|
|
|
|||
|
|
@ -668,19 +668,41 @@ data "aws_iam_policy_document" "hcptf_apply_services" {
|
|||
sid = "VpcSecurityGroups"
|
||||
effect = "Allow"
|
||||
actions = [
|
||||
"ec2:DescribeVpcs",
|
||||
"ec2:DescribeSubnets",
|
||||
"ec2:DescribeSecurityGroups",
|
||||
"ec2:DescribeNetworkInterfaces",
|
||||
"ec2:DescribeAccountAttributes",
|
||||
"ec2:CreateSecurityGroup",
|
||||
"ec2:DeleteSecurityGroup",
|
||||
"ec2:AuthorizeSecurityGroupIngress",
|
||||
"ec2:AssociateRouteTable",
|
||||
"ec2:AttachInternetGateway",
|
||||
"ec2:AuthorizeSecurityGroupEgress",
|
||||
"ec2:RevokeSecurityGroupIngress",
|
||||
"ec2:RevokeSecurityGroupEgress",
|
||||
"ec2:AuthorizeSecurityGroupIngress",
|
||||
"ec2:CreateInternetGateway",
|
||||
"ec2:CreateRoute",
|
||||
"ec2:CreateRouteTable",
|
||||
"ec2:CreateSecurityGroup",
|
||||
"ec2:CreateSubnet",
|
||||
"ec2:CreateTags",
|
||||
"ec2:CreateVpc",
|
||||
"ec2:DeleteInternetGateway",
|
||||
"ec2:DeleteRoute",
|
||||
"ec2:DeleteRouteTable",
|
||||
"ec2:DeleteSecurityGroup",
|
||||
"ec2:DeleteSubnet",
|
||||
"ec2:DeleteTags",
|
||||
"ec2:DeleteVpc",
|
||||
"ec2:DescribeAccountAttributes",
|
||||
"ec2:DescribeAvailabilityZones",
|
||||
"ec2:DescribeInternetGateways",
|
||||
"ec2:DescribeNetworkInterfaces",
|
||||
"ec2:DescribeRouteTables",
|
||||
"ec2:DescribeSecurityGroupRules",
|
||||
"ec2:DescribeSecurityGroups",
|
||||
"ec2:DescribeSubnets",
|
||||
"ec2:DescribeTags",
|
||||
"ec2:DescribeVpcAttribute",
|
||||
"ec2:DescribeVpcs",
|
||||
"ec2:DetachInternetGateway",
|
||||
"ec2:DisassociateRouteTable",
|
||||
"ec2:ModifySubnetAttribute",
|
||||
"ec2:ModifyVpcAttribute",
|
||||
"ec2:RevokeSecurityGroupEgress",
|
||||
"ec2:RevokeSecurityGroupIngress",
|
||||
]
|
||||
resources = ["*"]
|
||||
}
|
||||
|
|
@ -907,6 +929,25 @@ data "aws_iam_policy_document" "hcptf_plan_refresh" {
|
|||
resources = ["*"]
|
||||
}
|
||||
|
||||
statement {
|
||||
sid = "RefreshVpc"
|
||||
effect = "Allow"
|
||||
actions = [
|
||||
"ec2:DescribeAccountAttributes",
|
||||
"ec2:DescribeAvailabilityZones",
|
||||
"ec2:DescribeInternetGateways",
|
||||
"ec2:DescribeNetworkInterfaces",
|
||||
"ec2:DescribeRouteTables",
|
||||
"ec2:DescribeSecurityGroupRules",
|
||||
"ec2:DescribeSecurityGroups",
|
||||
"ec2:DescribeSubnets",
|
||||
"ec2:DescribeTags",
|
||||
"ec2:DescribeVpcAttribute",
|
||||
"ec2:DescribeVpcs",
|
||||
]
|
||||
resources = ["*"]
|
||||
}
|
||||
|
||||
statement {
|
||||
sid = "RefreshEcr"
|
||||
effect = "Allow"
|
||||
|
|
|
|||
|
|
@ -14,8 +14,14 @@ locals {
|
|||
|
||||
artifacts_bucket_name = "afterhours-shift-manager-artifacts-${local.account_id}"
|
||||
ssm_prefix = "/afterhours-shift-manager"
|
||||
table_name = "afterhours-shifts"
|
||||
site_alerts_arn = "arn:aws:sns:${var.aws_region}:${local.account_id}:site-alerts"
|
||||
|
||||
# Prod has no default VPC. 10.70 is unused in 011934824531
|
||||
# (10.0 proposal-system, 10.20 payments-dashboard, 10.40 syslog,
|
||||
# 10.60 meal-order-manager, 10.80 apm-wo).
|
||||
vpc_cidr = "10.70.0.0/16"
|
||||
public_subnet_cidrs = ["10.70.0.0/24", "10.70.1.0/24"]
|
||||
table_name = "afterhours-shifts"
|
||||
site_alerts_arn = "arn:aws:sns:${var.aws_region}:${local.account_id}:site-alerts"
|
||||
|
||||
github_oidc_provider_arn = "arn:aws:iam::${local.account_id}:oidc-provider/token.actions.githubusercontent.com"
|
||||
# Org has Actions OIDC use_immutable_subject=true.
|
||||
|
|
|
|||
58
terraform/vpc.tf
Normal file
58
terraform/vpc.tf
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
data "aws_availability_zones" "available" {
|
||||
state = "available"
|
||||
}
|
||||
|
||||
resource "aws_vpc" "this" {
|
||||
cidr_block = local.vpc_cidr
|
||||
enable_dns_support = true
|
||||
enable_dns_hostnames = true
|
||||
|
||||
tags = {
|
||||
Name = "${local.project}-vpc"
|
||||
}
|
||||
|
||||
# First apply updates the live hcptf apply role before CreateVpc.
|
||||
depends_on = [aws_iam_role_policy.hcptf_apply_services]
|
||||
}
|
||||
|
||||
resource "aws_internet_gateway" "this" {
|
||||
vpc_id = aws_vpc.this.id
|
||||
|
||||
tags = {
|
||||
Name = "${local.project}-igw"
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_subnet" "public" {
|
||||
count = length(local.public_subnet_cidrs)
|
||||
|
||||
vpc_id = aws_vpc.this.id
|
||||
cidr_block = local.public_subnet_cidrs[count.index]
|
||||
availability_zone = data.aws_availability_zones.available.names[count.index]
|
||||
map_public_ip_on_launch = true
|
||||
|
||||
tags = {
|
||||
Name = "${local.project}-public-${count.index}"
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_route_table" "public" {
|
||||
vpc_id = aws_vpc.this.id
|
||||
|
||||
tags = {
|
||||
Name = "${local.project}-public"
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_route" "public_default" {
|
||||
route_table_id = aws_route_table.public.id
|
||||
destination_cidr_block = "0.0.0.0/0"
|
||||
gateway_id = aws_internet_gateway.this.id
|
||||
}
|
||||
|
||||
resource "aws_route_table_association" "public" {
|
||||
count = length(local.public_subnet_cidrs)
|
||||
|
||||
subnet_id = aws_subnet.public[count.index].id
|
||||
route_table_id = aws_route_table.public.id
|
||||
}
|
||||
|
|
@ -68,6 +68,21 @@ def test_ecs_ignore_changes_and_task_size():
|
|||
assert 'path = "/api/health"' in ecs
|
||||
|
||||
|
||||
def test_stack_owns_a_vpc_instead_of_looking_up_default():
|
||||
vpc = (TERRAFORM / "vpc.tf").read_text()
|
||||
ecs = (TERRAFORM / "ecs.tf").read_text()
|
||||
assert 'resource "aws_vpc" "this"' in vpc
|
||||
assert "cidr_block = local.vpc_cidr" in vpc
|
||||
assert 'vpc_cidr = "10.70.0.0/16"' in LOCALS
|
||||
assert 'data "aws_vpc" "default"' not in ecs
|
||||
assert "data.aws_vpc.default" not in ecs
|
||||
assert "data.aws_subnets.default" not in ecs
|
||||
assert "aws_vpc.this.id" in ecs
|
||||
assert "aws_subnet.public[*].id" in ecs
|
||||
assert "ec2:CreateVpc" in HCP_IAM
|
||||
assert "sid = \"RefreshVpc\"" in HCP_IAM
|
||||
|
||||
|
||||
def test_deploy_api_workflow_exists():
|
||||
deploy_api = (ROOT / ".github" / "workflows" / "deploy-api.yaml").read_text()
|
||||
assert "environment: ${{ needs.target.outputs.environment }}" in deploy_api
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue