From e70adaa9fce50528bf8b7946c7f4ee52e479f52a Mon Sep 17 00:00:00 2001 From: Daniel Ribeiro Date: Thu, 24 Aug 2023 19:44:14 +1000 Subject: [PATCH] Add VPC endpoints for SSM --- terraform/main.tf | 76 ++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 69 insertions(+), 7 deletions(-) diff --git a/terraform/main.tf b/terraform/main.tf index e0e1f8f..a1175dc 100644 --- a/terraform/main.tf +++ b/terraform/main.tf @@ -69,14 +69,17 @@ resource "aws_subnet" "lambda_subnet" { } resource "aws_security_group" "bastion_sg" { + name = "bastion-sg" vpc_id = aws_vpc.backend_vpc.id } resource "aws_security_group" "db_sg" { + name = "db-sg" vpc_id = aws_vpc.backend_vpc.id } resource "aws_security_group" "lambda_sg" { + name = "lambda-sg" vpc_id = aws_vpc.backend_vpc.id } @@ -107,7 +110,8 @@ resource "aws_instance" "bastion_host" { } } -resource "aws_iam_role" "ec2_ssm_role" { +# See https://repost.aws/knowledge-center/ec2-systems-manager-vpc-endpoints +resource "aws_iam_role" "bastion_ssm_role" { name = "ec2-bastion-ssm-role" assume_role_policy = jsonencode({ @@ -124,14 +128,72 @@ resource "aws_iam_role" "ec2_ssm_role" { resource "aws_iam_instance_profile" "ec2_ssm_instance_profile" { name = "ec2-bastion-ssm-profile" - role = aws_iam_role.ec2_ssm_role.name + role = aws_iam_role.bastion_ssm_role.name } resource "aws_iam_role_policy_attachment" "ec2_ssm_policy_attachment" { - role = aws_iam_role.ec2_ssm_role.name + role = aws_iam_role.bastion_ssm_role.name policy_arn = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore" } +# https://docs.aws.amazon.com/systems-manager/latest/userguide/ssm-agent-minimum-s3-permissions.html +resource "aws_iam_policy" "bastion_ssm_s3_policy" { + name = "bastion_ssm_s3" + + policy = jsonencode({ + Version = "2012-10-17", + Statement = [{ + Action = "s3:GetObject", + Effect = "Allow", + Resources = [ + "arn:aws:s3:::aws-ssm-${var.region}/*", + "arn:aws:s3:::aws-windows-downloads-${var.region}/*", + "arn:aws:s3:::amazon-ssm-${var.region}/*", + "arn:aws:s3:::amazon-ssm-packages-${var.region}/*", + "arn:aws:s3:::${var.region}-birdwatcher-prod/*", + "arn:aws:s3:::aws-ssm-distributor-file-${var.region}/*", + "arn:aws:s3:::aws-ssm-document-attachments-${var.region}/*", + "arn:aws:s3:::patch-baseline-snapshot-${var.region}/*" + ] + }] + }) +} + +resource "aws_iam_role_policy_attachment" "bastion_host_ssm_s3" { + policy_arn = aws_iam_policy.bastion_ssm_s3_policy.arn + role = aws_iam_role.bastion_ssm_role.name +} + +resource "aws_vpc_endpoint" "ssm_endpoints" { + for_each = toset(["ssmmessages", "ec2messages", "ssm"]) + service_name = "com.amazonaws.${var.aws_region}.${each.key}" + vpc_id = aws_vpc.backend_vpc.id + vpc_endpoint_type = "Interface" + subnet_ids = [aws_subnet.bastion_subnet.id] + security_group_ids = [aws_security_group.vpc_endpoints_sg.id] +} + +resource "aws_security_group" "vpc_endpoints_sg" { + name = "vpc-endpoints-ssm-sg" + vpc_id = aws_vpc.backend_vpc.id +} + +resource "aws_vpc_security_group_ingress_rule" "vpc_endpoints_ingress_rule" { + security_group_id = aws_security_group.vpc_endpoints_sg.id + referenced_security_group_id = aws_security_group.bastion_sg.id + from_port = 443 + ip_protocol = "tcp" + to_port = 443 +} + +resource "aws_vpc_security_group_egress_rule" "bastion_host_egress_rule" { + security_group_id = aws_security_group.bastion_sg.id + referenced_security_group_id = aws_security_group.vpc_endpoints_sg.id + from_port = 443 + ip_protocol = "tcp" + to_port = 443 +} + ################################################################################ # RDS ################################################################################ @@ -158,7 +220,7 @@ resource "aws_db_instance" "fastapi_db" { vpc_security_group_ids = [aws_security_group.db_sg.id] db_subnet_group_name = aws_db_subnet_group.db_subnet_group.id - multi_az = true # Enable multi-AZ deployment for high availability + multi_az = true } ################################################################################ @@ -236,14 +298,14 @@ resource "aws_db_proxy" "db_proxy" { depends_on = [aws_cloudwatch_log_group.db_proxy_log_group] } -resource "aws_db_proxy_default_target_group" "default" { +resource "aws_db_proxy_default_target_group" "db_proxy_target_group" { db_proxy_name = aws_db_proxy.db_proxy.name } -resource "aws_db_proxy_target" "example" { +resource "aws_db_proxy_target" "db_proxy_target" { db_instance_identifier = aws_db_instance.fastapi_db.identifier db_proxy_name = aws_db_proxy.db_proxy.name - target_group_name = aws_db_proxy_default_target_group.default.name + target_group_name = aws_db_proxy_default_target_group.db_proxy_target_group.name } resource "aws_cloudwatch_log_group" "db_proxy_log_group" {