From 2586532143606ccb9b77f899f116feababb59aba Mon Sep 17 00:00:00 2001 From: Malcolm Roberts Date: Wed, 7 Jun 2023 09:08:34 -0500 Subject: [PATCH] Initial implementation --- .../exercises/alb-exercise1/lb/terragrunt.hcl | 60 +++ .../alb-exercise1/web/terragrunt.hcl | 52 +++ src/basic-web-infra/exercises/env.hcl | 21 ++ .../exercises/vpc/terragrunt.hcl | 34 ++ src/basic-web-infra/global/config/main.tf | 28 ++ src/basic-web-infra/global/config/rules.tf | 205 +++++++++++ src/basic-web-infra/global/config/s3.tf | 84 +++++ .../global/config/terragrunt.hcl | 10 + .../global/iam/account_alias.tf | 3 + src/basic-web-infra/global/iam/groups.tf | 12 + src/basic-web-infra/global/iam/main.tf | 111 ++++++ src/basic-web-infra/global/iam/outputs.tf | 0 src/basic-web-infra/global/iam/roles.tf | 0 src/basic-web-infra/global/iam/terragrunt.hcl | 10 + src/basic-web-infra/global/iam/variables.tf | 0 src/basic-web-infra/global/ssm/iam.tf | 53 +++ src/basic-web-infra/global/ssm/main.tf | 42 +++ src/basic-web-infra/global/ssm/patching.tf | 341 ++++++++++++++++++ .../global/ssm/ssm-artifacts.tf | 41 +++ .../global/ssm/ssm-packages.tf | 58 +++ .../global/ssm/ssm-patch-log.tf | 60 +++ src/basic-web-infra/global/ssm/terragrunt.hcl | 10 + .../global/ssm/windows-defender-updates.tf | 111 ++++++ src/basic-web-infra/modules/lb/certificate.tf | 36 ++ src/basic-web-infra/modules/lb/dns.tf | 13 + src/basic-web-infra/modules/lb/main.tf | 135 +++++++ src/basic-web-infra/modules/lb/outputs.tf | 19 + src/basic-web-infra/modules/lb/s3.tf | 51 +++ src/basic-web-infra/modules/lb/variables.tf | 61 ++++ src/basic-web-infra/modules/lb/waf.tf | 172 +++++++++ src/basic-web-infra/modules/vpc/flowlogs.tf | 82 +++++ src/basic-web-infra/modules/vpc/main.tf | 77 ++++ src/basic-web-infra/modules/vpc/outputs.tf | 31 ++ src/basic-web-infra/modules/vpc/variables.tf | 44 +++ src/basic-web-infra/modules/web/ami.tf | 12 + src/basic-web-infra/modules/web/keypair.tf | 17 + src/basic-web-infra/modules/web/main.tf | 122 +++++++ src/basic-web-infra/modules/web/outputs.tf | 11 + .../modules/web/remote_access.tf | 65 ++++ src/basic-web-infra/modules/web/variables.tf | 79 ++++ 40 files changed, 2373 insertions(+) create mode 100644 src/basic-web-infra/exercises/alb-exercise1/lb/terragrunt.hcl create mode 100644 src/basic-web-infra/exercises/alb-exercise1/web/terragrunt.hcl create mode 100644 src/basic-web-infra/exercises/env.hcl create mode 100644 src/basic-web-infra/exercises/vpc/terragrunt.hcl create mode 100644 src/basic-web-infra/global/config/main.tf create mode 100644 src/basic-web-infra/global/config/rules.tf create mode 100644 src/basic-web-infra/global/config/s3.tf create mode 100644 src/basic-web-infra/global/config/terragrunt.hcl create mode 100644 src/basic-web-infra/global/iam/account_alias.tf create mode 100644 src/basic-web-infra/global/iam/groups.tf create mode 100644 src/basic-web-infra/global/iam/main.tf create mode 100644 src/basic-web-infra/global/iam/outputs.tf create mode 100644 src/basic-web-infra/global/iam/roles.tf create mode 100644 src/basic-web-infra/global/iam/terragrunt.hcl create mode 100644 src/basic-web-infra/global/iam/variables.tf create mode 100644 src/basic-web-infra/global/ssm/iam.tf create mode 100644 src/basic-web-infra/global/ssm/main.tf create mode 100644 src/basic-web-infra/global/ssm/patching.tf create mode 100644 src/basic-web-infra/global/ssm/ssm-artifacts.tf create mode 100644 src/basic-web-infra/global/ssm/ssm-packages.tf create mode 100644 src/basic-web-infra/global/ssm/ssm-patch-log.tf create mode 100644 src/basic-web-infra/global/ssm/terragrunt.hcl create mode 100644 src/basic-web-infra/global/ssm/windows-defender-updates.tf create mode 100644 src/basic-web-infra/modules/lb/certificate.tf create mode 100644 src/basic-web-infra/modules/lb/dns.tf create mode 100644 src/basic-web-infra/modules/lb/main.tf create mode 100644 src/basic-web-infra/modules/lb/outputs.tf create mode 100644 src/basic-web-infra/modules/lb/s3.tf create mode 100644 src/basic-web-infra/modules/lb/variables.tf create mode 100644 src/basic-web-infra/modules/lb/waf.tf create mode 100644 src/basic-web-infra/modules/vpc/flowlogs.tf create mode 100644 src/basic-web-infra/modules/vpc/main.tf create mode 100644 src/basic-web-infra/modules/vpc/outputs.tf create mode 100644 src/basic-web-infra/modules/vpc/variables.tf create mode 100644 src/basic-web-infra/modules/web/ami.tf create mode 100644 src/basic-web-infra/modules/web/keypair.tf create mode 100644 src/basic-web-infra/modules/web/main.tf create mode 100644 src/basic-web-infra/modules/web/outputs.tf create mode 100644 src/basic-web-infra/modules/web/remote_access.tf create mode 100644 src/basic-web-infra/modules/web/variables.tf diff --git a/src/basic-web-infra/exercises/alb-exercise1/lb/terragrunt.hcl b/src/basic-web-infra/exercises/alb-exercise1/lb/terragrunt.hcl new file mode 100644 index 0000000..25ab2b3 --- /dev/null +++ b/src/basic-web-infra/exercises/alb-exercise1/lb/terragrunt.hcl @@ -0,0 +1,60 @@ +include { + path = find_in_parent_folders() +} + +include "account" { + path = "${get_terragrunt_dir()}/../../../account.hcl" + expose = true + } + +include "env" { + path = "${get_terragrunt_dir()}/../../env.hcl" + expose = true + } + +dependencies { + paths = [ + "${get_terragrunt_dir()}/../../vpc", + "${get_terragrunt_dir()}/../web" + ] +} + +dependency "vpc" { + config_path = "${get_terragrunt_dir()}/../../vpc" + + mock_outputs = { + vpc_id = "vpc-test" + private_subnets_ids = [ "subnet-private-a", "subnet-private-b" ] + public_subnets_ids = [ "subnet-public-a", "subnet-public-b" ] + private_subnets_cidr_blocks = [ "10.1.2.0/24", "10.1.4.0/24" ] + public_subnets_cidr_blocks = [ "10.1.1.0/24", "10.1.3.0/24" ] + } +} + +dependency "web" { + config_path = "${get_terragrunt_dir()}/../web" + + mock_outputs = { + webserver_ids = ["i-12343459359", "i-94949494242424" ] + } +} + +terraform { + source = "${get_terragrunt_dir()}/../../../modules/lb//" +} + +inputs = { + deployment_long_name = include.account.locals.deployment_long_name + deployment_short_name = include.account.locals.deployment_short_name + deployment_role = include.env.locals.deployment_role + vpc_id = dependency.vpc.outputs.vpc_id + loadbalancer_subnets = dependency.vpc.outputs.public_subnets_ids + + default_domain_name = "careevolution.dev" + default_subdomain = "alb-exercise1" + target_instances = dependency.web.outputs.webserver_ids + target_security_group_id = dependency.web.outputs.security_group_id + target_port = "80" + + tags = include.env.locals.tags +} \ No newline at end of file diff --git a/src/basic-web-infra/exercises/alb-exercise1/web/terragrunt.hcl b/src/basic-web-infra/exercises/alb-exercise1/web/terragrunt.hcl new file mode 100644 index 0000000..6a89543 --- /dev/null +++ b/src/basic-web-infra/exercises/alb-exercise1/web/terragrunt.hcl @@ -0,0 +1,52 @@ +include { + path = find_in_parent_folders() +} + +include "account" { + path = "${get_terragrunt_dir()}/../../../account.hcl" + expose = true + } + +include "env" { + path = "${get_terragrunt_dir()}/../../env.hcl" + expose = true + } + +dependencies { + paths = [ + "${get_terragrunt_dir()}/../../vpc" + ] +} + +dependency "vpc" { + config_path = "${get_terragrunt_dir()}/../../vpc" + + mock_outputs = { + vpc_id = "vpc-test" + private_subnets_ids = [ "subnet-private-a", "subnet-private-b" ] + public_subnets_ids = [ "subnet-public-a", "subnet-public-b" ] + private_subnets_cidr_blocks = [ "10.1.2.0/24", "10.1.4.0/24" ] + public_subnets_cidr_blocks = [ "10.1.1.0/24", "10.1.3.0/24" ] + } +} +terraform { + source = "${get_terragrunt_dir()}/../../../modules/web//" +} + +inputs = { + deployment_long_name = include.account.locals.deployment_long_name + deployment_short_name = include.account.locals.deployment_short_name + deployment_role = include.env.locals.deployment_role + + vpc_id = dependency.vpc.outputs.vpc_id + vpc_cidr_block = include.env.locals.vpc_cidr + instance_subnet_id = dependency.vpc.outputs.public_subnets_ids[0] + suffixes = [ "01A", "02A" ] + instance_type = "t3.medium" + keypair_name = "${include.account.locals.deployment_long_name}-${include.env.locals.deployment_role}" + tags = include.env.locals.tags + patch_group = "Windows Automatic Reboot" + + allow_remote_access = include.env.locals.allow_remote_access + remote_access_cidrs = include.env.locals.remote_access_cidrs +} \ No newline at end of file diff --git a/src/basic-web-infra/exercises/env.hcl b/src/basic-web-infra/exercises/env.hcl new file mode 100644 index 0000000..62e160d --- /dev/null +++ b/src/basic-web-infra/exercises/env.hcl @@ -0,0 +1,21 @@ + +locals { + deployment_role = "exercises" + vpc_cidr = "10.45.0.0/16" + + allow_remote_access = false + remote_access_cidrs = [ + ] + + terragrunt_tags = { + created_by = "terraform" + terraform_path = "/${lower(path_relative_to_include())}" + } + + tags = { + ce_resource_path = "/HIRING/EXERCISES" + created_by = "terraform", + project = "exercises" + cost_center = "hiring" + } +} \ No newline at end of file diff --git a/src/basic-web-infra/exercises/vpc/terragrunt.hcl b/src/basic-web-infra/exercises/vpc/terragrunt.hcl new file mode 100644 index 0000000..1b3e805 --- /dev/null +++ b/src/basic-web-infra/exercises/vpc/terragrunt.hcl @@ -0,0 +1,34 @@ +include { + path = find_in_parent_folders() +} + +include "account" { + path = "${get_terragrunt_dir()}/../../account.hcl" + expose = true + } + +include "env" { + path = "${get_terragrunt_dir()}/../env.hcl" + expose = true + } + +dependency "infrastructure" { + config_path = "${get_terragrunt_dir()}/../../../infrastructure/prod" +} + +terraform { + source = "${get_terragrunt_dir()}/../../modules/vpc//" +} + +inputs = { + deployment_long_name = include.account.locals.deployment_long_name + deployment_short_name = include.account.locals.deployment_short_name + deployment_role = include.env.locals.deployment_role + + vpc_cidr = include.env.locals.vpc_cidr + infrastructure_dns_domain_name = dependency.infrastructure.outputs.dns_domain_name + infrastructure_dns_server_ips = dependency.infrastructure.outputs.dns_server_ips + infrastructure_ntp_server_ips = dependency.infrastructure.outputs.ntp_server_ips + infrastructure_netbios_nameserver_ips = dependency.infrastructure.outputs.netbios_name_server_ips + infrastructure_netbios_node_type = dependency.infrastructure.outputs.netbios_node_type +} \ No newline at end of file diff --git a/src/basic-web-infra/global/config/main.tf b/src/basic-web-infra/global/config/main.tf new file mode 100644 index 0000000..2ccd740 --- /dev/null +++ b/src/basic-web-infra/global/config/main.tf @@ -0,0 +1,28 @@ +data "aws_caller_identity" "current" {} +data "aws_region" "current" {} + +resource "aws_iam_role" "config" { + name = "AWSConfigRole" + + assume_role_policy = < { + name = dvo.resource_record_name + record = dvo.resource_record_value + type = dvo.resource_record_type + } + } + + allow_overwrite = true + name = each.value.name + records = [each.value.record] + ttl = 60 + type = each.value.type + zone_id = data.aws_route53_zone.certificate.zone_id +} + +resource "aws_acm_certificate_validation" "certificate" { + certificate_arn = aws_acm_certificate.certificate.arn + validation_record_fqdns = [for record in aws_route53_record.certificate : record.fqdn] +} diff --git a/src/basic-web-infra/modules/lb/dns.tf b/src/basic-web-infra/modules/lb/dns.tf new file mode 100644 index 0000000..c597dd7 --- /dev/null +++ b/src/basic-web-infra/modules/lb/dns.tf @@ -0,0 +1,13 @@ + +resource "aws_route53_record" "loadbalancer_A" { + provider = aws.public_infrastructure + zone_id = data.aws_route53_zone.certificate.zone_id + name = var.default_subdomain + type = "A" + + alias { + name = aws_lb.loadbalancer.dns_name + zone_id = aws_lb.loadbalancer.zone_id + evaluate_target_health = true + } +} diff --git a/src/basic-web-infra/modules/lb/main.tf b/src/basic-web-infra/modules/lb/main.tf new file mode 100644 index 0000000..a67ba69 --- /dev/null +++ b/src/basic-web-infra/modules/lb/main.tf @@ -0,0 +1,135 @@ +data "aws_caller_identity" "current" {} +data "aws_elb_service_account" "main" {} + +resource "aws_security_group" "loadbalancer" { + vpc_id = var.vpc_id + + tags = merge(var.tags, { + Name = "LoadBalancer (${var.deployment_role})" + Description = "LoadBalancer security group (${var.deployment_role})" + }) +} + +resource "aws_security_group_rule" "https" { + security_group_id = aws_security_group.loadbalancer.id + type = "ingress" + protocol = "TCP" + cidr_blocks = ["0.0.0.0/0"] + from_port = 443 + to_port = 443 + description = "Allows open access to https" +} + +resource "aws_security_group_rule" "http" { + security_group_id = aws_security_group.loadbalancer.id + type = "ingress" + protocol = "TCP" + cidr_blocks = ["0.0.0.0/0"] + from_port = 80 + to_port = 80 + description = "Allows open access to https" +} + +resource "aws_security_group_rule" "outbound" { + security_group_id = aws_security_group.loadbalancer.id + type = "egress" + protocol = "-1" + from_port = 80 + to_port = 80 + source_security_group_id = var.target_security_group_id + description = "Allows egress to the instances sg." +} + +resource "aws_lb" "loadbalancer" { + name = "${var.deployment_short_name}-${var.deployment_role}" + internal = false + load_balancer_type = "application" + security_groups = [ + aws_security_group.loadbalancer.id + ] + + enable_deletion_protection = false + drop_invalid_header_fields = true + + subnets = var.loadbalancer_subnets + + access_logs { + bucket = aws_s3_bucket.logging_bucket.bucket + enabled = true + } + + tags = merge(var.tags, { + Owner = var.deployment_long_name + Purpose = "LB" + Deployment = upper(var.deployment_short_name) + Environment = upper(var.deployment_role) + }) +} + +resource "aws_wafv2_web_acl_association" "web_acl" { + resource_arn = aws_lb.loadbalancer.arn + web_acl_arn = aws_wafv2_web_acl.waf_acl.arn +} + +resource "aws_lb_target_group" "targetgroup" { + name = var.default_subdomain + port = var.target_port + protocol = "HTTP" + target_type = "instance" + vpc_id = var.vpc_id + slow_start = 300 + + health_check { + enabled = true + healthy_threshold = 2 + interval = 90 + matcher = "200" + path = "/" + port = "traffic-port" + protocol = "HTTP" + timeout = 60 + unhealthy_threshold = 2 + } + + stickiness { + cookie_duration = 28800 + enabled = true + type = "lb_cookie" + } +} + +resource "aws_lb_target_group_attachment" "targetgroup" { + for_each = var.target_instances + target_group_arn = aws_lb_target_group.targetgroup.arn + target_id = each.value + port = var.target_port +} + +resource "aws_lb_listener" "https" { + load_balancer_arn = aws_lb.loadbalancer.arn + port = "443" + protocol = "HTTPS" + ssl_policy = "ELBSecurityPolicy-FS-1-2-Res-2020-10" + certificate_arn = aws_acm_certificate.certificate.arn + + default_action { + type = "forward" + target_group_arn = aws_lb_target_group.targetgroup.arn + } +} + +resource "aws_lb_listener" "http" { + load_balancer_arn = aws_lb.loadbalancer.arn + port = "80" + protocol = "HTTP" + + default_action { + type = "redirect" + + redirect { + port = "443" + protocol = "HTTPS" + status_code = "HTTP_301" + } + } +} diff --git a/src/basic-web-infra/modules/lb/outputs.tf b/src/basic-web-infra/modules/lb/outputs.tf new file mode 100644 index 0000000..b7ad5dc --- /dev/null +++ b/src/basic-web-infra/modules/lb/outputs.tf @@ -0,0 +1,19 @@ +output "arn" { + value = aws_lb.loadbalancer.arn +} + +output "dns_name" { + value = aws_lb.loadbalancer.dns_name +} + +output "zone_id" { + value = aws_lb.loadbalancer.zone_id +} + +output "https_listener_arn" { + value = aws_lb_listener.https.arn +} + +output "targetgroup_arn" { + value = aws_lb_target_group.targetgroup.arn +} \ No newline at end of file diff --git a/src/basic-web-infra/modules/lb/s3.tf b/src/basic-web-infra/modules/lb/s3.tf new file mode 100644 index 0000000..307d183 --- /dev/null +++ b/src/basic-web-infra/modules/lb/s3.tf @@ -0,0 +1,51 @@ +resource "aws_s3_bucket" "logging_bucket" { + bucket = "${var.deployment_short_name}-${var.deployment_role}-loadbalancer" + force_destroy = true + + tags = var.tags +} + +resource "aws_s3_bucket_acl" "logging_bucket" { + bucket = aws_s3_bucket.logging_bucket.id + acl = "private" +} + +resource "aws_s3_bucket_public_access_block" "logging_bucket" { + bucket = aws_s3_bucket.logging_bucket.id + + block_public_acls = true + block_public_policy = true + ignore_public_acls = true + restrict_public_buckets = true +} + +resource "aws_s3_bucket_server_side_encryption_configuration" "logging_bucket" { + bucket = aws_s3_bucket.logging_bucket.bucket + + rule { + apply_server_side_encryption_by_default { + sse_algorithm = "AES256" + } + } +} + +resource "aws_s3_bucket_policy" "logging_bucket" { + bucket = aws_s3_bucket.logging_bucket.bucket + policy = <