From 7a23aa319565aae20ee960d3f08d700405523125 Mon Sep 17 00:00:00 2001 From: Deshmukh Date: Wed, 20 Nov 2024 16:24:13 +0530 Subject: [PATCH 01/40] As per AWS NG architecture creating additional and associating CIDR ranges to the VPC --- ...g_template.yaml => .pre-commit-config.yaml | 0 examples/sample-input-nist.tfvars | 124 ++++++++++++++++++ locals.tf | 1 - main.tf | 1 + modules/aws_vpc/main.tf | 9 ++ modules/aws_vpc/variables.tf | 11 ++ variables.tf | 7 + 7 files changed, 152 insertions(+), 1 deletion(-) rename .pre-commit-config_template.yaml => .pre-commit-config.yaml (100%) create mode 100644 examples/sample-input-nist.tfvars diff --git a/.pre-commit-config_template.yaml b/.pre-commit-config.yaml similarity index 100% rename from .pre-commit-config_template.yaml rename to .pre-commit-config.yaml diff --git a/examples/sample-input-nist.tfvars b/examples/sample-input-nist.tfvars new file mode 100644 index 00000000..cd35ce97 --- /dev/null +++ b/examples/sample-input-nist.tfvars @@ -0,0 +1,124 @@ +# !NOTE! - These are only a subset of the variables in CONFIG-VARS.md provided +# as examples. Customize this file to add any variables from CONFIG-VARS.md whose +# default values you want to change. + +# **************** REQUIRED VARIABLES **************** +# These required variables' values MUST be provided by the User +prefix = "" +location = "" # e.g., "us-east-1" +# **************** REQUIRED VARIABLES **************** + +# !NOTE! - Without specifying your CIDR block access rules, ingress traffic +# to your cluster will be blocked by default. + +#***************** CIDR Range for Spoke VPC ************** + +cidr = "10.80.16.0/22" + +# ********* Set to true to enable NIST complaint code *********** +enable_nist_features = false + +#***************** Additional CIDR ranges for Spoke VPC ************* + +additional_cidr_ranges = ["10.88.4.0/24", "10.89.1.0/26", "10.90.0.128/27", "10.91.0.128/27"] + +# ************** RECOMMENDED VARIABLES *************** +default_public_access_cidrs = [] # e.g., ["123.45.6.89/32"] +ssh_public_key = "~/.ssh/id_rsa.pub" +# ************** RECOMMENDED VARIABLES *************** + +# Tags for all tagable items in your cluster. +tags = {} # e.g., { "key1" = "value1", "key2" = "value2" } + +# Postgres config - By having this entry a database server is created. If you do not +# need an external database server remove the 'postgres_servers' +# block below. +postgres_servers = { + default = {}, +} + +## Cluster config +kubernetes_version = "1.29" +default_nodepool_node_count = 2 +default_nodepool_vm_type = "m5.2xlarge" +default_nodepool_custom_data = "" + +## General +efs_performance_mode = "maxIO" +storage_type = "standard" + +## Cluster Node Pools config +node_pools = { + cas = { + "vm_type" = "i3.8xlarge" + "cpu_type" = "AL2_x86_64" + "os_disk_type" = "gp2" + "os_disk_size" = 200 + "os_disk_iops" = 0 + "min_nodes" = 1 + "max_nodes" = 5 + "node_taints" = ["workload.sas.com/class=cas:NoSchedule"] + "node_labels" = { + "workload.sas.com/class" = "cas" + } + "custom_data" = "./files/custom-data/additional_userdata.sh" + "metadata_http_endpoint" = "enabled" + "metadata_http_tokens" = "required" + "metadata_http_put_response_hop_limit" = 1 + }, + compute = { + "vm_type" = "m5.8xlarge" + "cpu_type" = "AL2_x86_64" + "os_disk_type" = "gp2" + "os_disk_size" = 200 + "os_disk_iops" = 0 + "min_nodes" = 1 + "max_nodes" = 5 + "node_taints" = ["workload.sas.com/class=compute:NoSchedule"] + "node_labels" = { + "workload.sas.com/class" = "compute" + "launcher.sas.com/prepullImage" = "sas-programming-environment" + } + "custom_data" = "" + "metadata_http_endpoint" = "enabled" + "metadata_http_tokens" = "required" + "metadata_http_put_response_hop_limit" = 1 + }, + stateless = { + "vm_type" = "m5.4xlarge" + "cpu_type" = "AL2_x86_64" + "os_disk_type" = "gp2" + "os_disk_size" = 200 + "os_disk_iops" = 0 + "min_nodes" = 1 + "max_nodes" = 5 + "node_taints" = ["workload.sas.com/class=stateless:NoSchedule"] + "node_labels" = { + "workload.sas.com/class" = "stateless" + } + "custom_data" = "" + "metadata_http_endpoint" = "enabled" + "metadata_http_tokens" = "required" + "metadata_http_put_response_hop_limit" = 1 + }, + stateful = { + "vm_type" = "m5.4xlarge" + "cpu_type" = "AL2_x86_64" + "os_disk_type" = "gp2" + "os_disk_size" = 200 + "os_disk_iops" = 0 + "min_nodes" = 1 + "max_nodes" = 3 + "node_taints" = ["workload.sas.com/class=stateful:NoSchedule"] + "node_labels" = { + "workload.sas.com/class" = "stateful" + } + "custom_data" = "" + "metadata_http_endpoint" = "enabled" + "metadata_http_tokens" = "required" + "metadata_http_put_response_hop_limit" = 1 + } +} + +# Jump Server +create_jump_vm = true diff --git a/locals.tf b/locals.tf index e3f57521..d8eeeb80 100755 --- a/locals.tf +++ b/locals.tf @@ -179,5 +179,4 @@ locals { "internal" : false } } : {} - } diff --git a/main.tf b/main.tf index d189dd3a..b00e1c4a 100755 --- a/main.tf +++ b/main.tf @@ -88,6 +88,7 @@ module "vpc" { tags = local.tags public_subnet_tags = merge(local.tags, { "kubernetes.io/role/elb" = "1" }, { "kubernetes.io/cluster/${local.cluster_name}" = "shared" }) private_subnet_tags = merge(local.tags, { "kubernetes.io/role/internal-elb" = "1" }, { "kubernetes.io/cluster/${local.cluster_name}" = "shared" }) + additional_cidr_ranges = var.additional_cidr_ranges } # EKS Setup - https://github.com/terraform-aws-modules/terraform-aws-eks diff --git a/modules/aws_vpc/main.tf b/modules/aws_vpc/main.tf index 89c82a76..73dc80d4 100644 --- a/modules/aws_vpc/main.tf +++ b/modules/aws_vpc/main.tf @@ -47,6 +47,15 @@ resource "aws_vpc" "vpc" { ) } +###### +# Additional CIDR association +###### +resource "aws_vpc_ipv4_cidr_block_association" "additional_cidr" { + count = var.enable_nist_features == true ? 4 : 0 + vpc_id = aws_vpc.vpc[0].id + cidr_block = element(var.additional_cidr_ranges, count.index) +} + resource "aws_vpc_endpoint" "private_endpoints" { for_each = var.vpc_private_endpoints_enabled ? var.vpc_private_endpoints : {} vpc_id = local.vpc_id diff --git a/modules/aws_vpc/variables.tf b/modules/aws_vpc/variables.tf index 22f74e79..8f06e901 100644 --- a/modules/aws_vpc/variables.tf +++ b/modules/aws_vpc/variables.tf @@ -164,3 +164,14 @@ variable "workers_security_group_id" { description = "Workers Security Group ID input variable value" type = string } + +variable "additional_cidr_ranges" { + description = "Number of additional CIDR ranges to be attached to VPC" + type = list(string) +} + +variable "enable_nist_features" { + description = "Enables NIST complaint code if set to true" + type = bool + default = false +} diff --git a/variables.tf b/variables.tf index afb628c0..fab951f1 100644 --- a/variables.tf +++ b/variables.tf @@ -719,3 +719,10 @@ variable "enable_nist_features" { type = bool default = false } + +#### Network changes made for AWS NG architecture #### +variable "additional_cidr_ranges" { + description = "Additionl cidr ranges to be associated with VPC" + type = list(string) + default = null +} From 643c22ccd7cb9b5524cda3a2e2987db2ec5e27d6 Mon Sep 17 00:00:00 2001 From: Deshmukh Date: Wed, 20 Nov 2024 16:50:40 +0530 Subject: [PATCH 02/40] Creating ENI subnets, route association for ENI subnets to private route table as per AWS NG architecture --- locals.tf | 2 ++ main.tf | 10 ++++++---- modules/aws_vpc/main.tf | 38 ++++++++++++++++++++++++++++++++---- modules/aws_vpc/variables.tf | 7 +++++++ variables.tf | 4 ++-- 5 files changed, 51 insertions(+), 10 deletions(-) diff --git a/locals.tf b/locals.tf index d8eeeb80..e72eb882 100755 --- a/locals.tf +++ b/locals.tf @@ -46,6 +46,8 @@ locals { private_subnet_azs = can(var.subnet_azs["private"]) ? var.subnet_azs["private"] : data.aws_availability_zones.available.names database_subnet_azs = can(var.subnet_azs["database"]) ? var.subnet_azs["database"] : data.aws_availability_zones.available.names control_plane_subnet_azs = can(var.subnet_azs["control_plane"]) ? var.subnet_azs["control_plane"] : data.aws_availability_zones.available.names + # ENI subnets as per AWS NG architecture + eni_subnet_azs = can(var.subnet_azs["eni"]) ? var.subnet_azs["eni"] : data.aws_availability_zones.available.names ssh_public_key = (var.create_jump_vm || var.storage_type == "standard" ? file(var.ssh_public_key) diff --git a/main.tf b/main.tf index b00e1c4a..6f66568a 100755 --- a/main.tf +++ b/main.tf @@ -80,15 +80,17 @@ module "vpc" { private_subnet_azs = local.private_subnet_azs database_subnet_azs = local.database_subnet_azs control_plane_subnet_azs = local.control_plane_subnet_azs + eni_subnet_azs = local.eni_subnet_azs existing_subnet_ids = var.subnet_ids subnets = var.subnets existing_nat_id = var.nat_id vpc_private_endpoints_enabled = var.vpc_private_endpoints_enabled - tags = local.tags - public_subnet_tags = merge(local.tags, { "kubernetes.io/role/elb" = "1" }, { "kubernetes.io/cluster/${local.cluster_name}" = "shared" }) - private_subnet_tags = merge(local.tags, { "kubernetes.io/role/internal-elb" = "1" }, { "kubernetes.io/cluster/${local.cluster_name}" = "shared" }) - additional_cidr_ranges = var.additional_cidr_ranges + tags = local.tags + public_subnet_tags = merge(local.tags, { "kubernetes.io/role/elb" = "1" }, { "kubernetes.io/cluster/${local.cluster_name}" = "shared" }) + private_subnet_tags = merge(local.tags, { "kubernetes.io/role/internal-elb" = "1" }, { "kubernetes.io/cluster/${local.cluster_name}" = "shared" }) + additional_cidr_ranges = var.additional_cidr_ranges + enable_nist_features = var.enable_nist_features } # EKS Setup - https://github.com/terraform-aws-modules/terraform-aws-eks diff --git a/modules/aws_vpc/main.tf b/modules/aws_vpc/main.tf index 73dc80d4..5aea5d6f 100644 --- a/modules/aws_vpc/main.tf +++ b/modules/aws_vpc/main.tf @@ -105,6 +105,7 @@ resource "aws_subnet" "public" { availability_zone = length(regexall("^[a-z]{2}-", element(var.public_subnet_azs, count.index))) > 0 ? element(var.public_subnet_azs, count.index) : null availability_zone_id = length(regexall("^[a-z]{2}-", element(var.public_subnet_azs, count.index))) == 0 ? element(var.public_subnet_azs, count.index) : null map_public_ip_on_launch = var.map_public_ip_on_launch + depends_on = [aws_vpc.vpc, aws_vpc_ipv4_cidr_block_association.additional_cidr] tags = merge( { @@ -205,7 +206,7 @@ resource "aws_subnet" "private" { cidr_block = element(var.subnets["private"], count.index) availability_zone = length(regexall("^[a-z]{2}-", element(var.private_subnet_azs, count.index))) > 0 ? element(var.private_subnet_azs, count.index) : null availability_zone_id = length(regexall("^[a-z]{2}-", element(var.private_subnet_azs, count.index))) == 0 ? element(var.private_subnet_azs, count.index) : null - + depends_on = [aws_vpc.vpc, aws_vpc_ipv4_cidr_block_association.additional_cidr] tags = merge( { "Name" = format( @@ -249,7 +250,7 @@ resource "aws_subnet" "database" { cidr_block = element(var.subnets["database"], count.index) availability_zone = length(regexall("^[a-z]{2}-", element(var.database_subnet_azs, count.index))) > 0 ? element(var.database_subnet_azs, count.index) : null availability_zone_id = length(regexall("^[a-z]{2}-", element(var.database_subnet_azs, count.index))) == 0 ? element(var.database_subnet_azs, count.index) : null - + depends_on = [aws_vpc.vpc, aws_vpc_ipv4_cidr_block_association.additional_cidr] tags = merge( { "Name" = format( @@ -268,7 +269,7 @@ resource "aws_db_subnet_group" "database" { name = lower(var.name) description = "Database subnet group for ${var.name}" subnet_ids = aws_subnet.database[*].id - + depends_on = [aws_vpc.vpc, aws_vpc_ipv4_cidr_block_association.additional_cidr] tags = merge( { "Name" = format("%s", var.name) @@ -286,7 +287,7 @@ resource "aws_subnet" "control_plane" { cidr_block = element(var.subnets["control_plane"], count.index) availability_zone = length(regexall("^[a-z]{2}-", element(var.control_plane_subnet_azs, count.index))) > 0 ? element(var.control_plane_subnet_azs, count.index) : null availability_zone_id = length(regexall("^[a-z]{2}-", element(var.control_plane_subnet_azs, count.index))) == 0 ? element(var.control_plane_subnet_azs, count.index) : null - + depends_on = [aws_vpc.vpc, aws_vpc_ipv4_cidr_block_association.additional_cidr] tags = merge( { "Name" = format( @@ -352,3 +353,32 @@ resource "aws_route" "private_nat_gateway" { create = "5m" } } + +################# +# ENI subnets creation as per AWS NG architecture +################# +resource "aws_subnet" "eni" { + count = var.enable_nist_features == true ? 2 : 0 + vpc_id = local.vpc_id + cidr_block = element(var.subnets["eni"], count.index) + #availability_zone = element(var.availability_zones, count.index) + availability_zone = length(regexall("^[a-z]{2}-", element(var.eni_subnet_azs, count.index))) > 0 ? element(var.eni_subnet_azs, count.index) : null + availability_zone_id = length(regexall("^[a-z]{2}-", element(var.eni_subnet_azs, count.index))) == 0 ? element(var.eni_subnet_azs, count.index) : null + depends_on = [aws_vpc.vpc, aws_vpc_ipv4_cidr_block_association.additional_cidr] + tags = merge( + { + "Name" = format("%s", "${var.name}-eni-${count.index}"), + "type" = var.enable_nist_features == true ? "awsng-spoke-eni" : null + }, + var.tags + ) +} + +################# +# ENI subnets association with private route table ##### +################# +resource "aws_route_table_association" "eni" { + count = var.enable_nist_features == true ? length(aws_subnet.eni) : 0 + subnet_id = element(aws_subnet.eni[*].id, count.index) + route_table_id = element(aws_route_table.private[*].id, 0) +} \ No newline at end of file diff --git a/modules/aws_vpc/variables.tf b/modules/aws_vpc/variables.tf index 8f06e901..60668351 100644 --- a/modules/aws_vpc/variables.tf +++ b/modules/aws_vpc/variables.tf @@ -165,6 +165,7 @@ variable "workers_security_group_id" { type = string } +#### Newly added variables for enchance NIST code #### variable "additional_cidr_ranges" { description = "Number of additional CIDR ranges to be attached to VPC" type = list(string) @@ -175,3 +176,9 @@ variable "enable_nist_features" { type = bool default = false } + +variable "eni_subnet_azs" { + description = "A list of availability zones names or ids in the region for creating the eni subnets" + type = list(string) + default = [] +} diff --git a/variables.tf b/variables.tf index fab951f1..6fcaaf06 100644 --- a/variables.tf +++ b/variables.tf @@ -387,8 +387,8 @@ variable "subnet_azs" { # We only support configuring the AZs for the public, private, control_plane, and database subnet validation { - condition = var.subnet_azs == {} || alltrue([for subnet in keys(var.subnet_azs) : contains(["public", "private", "control_plane", "database"], subnet)]) - error_message = "ERROR: public, private, control_plane, and database are the only keys allowed in the subnet_azs map" + condition = var.subnet_azs == {} || alltrue([for subnet in keys(var.subnet_azs) : contains(["public", "private", "control_plane", "database", "eni"], subnet)]) + error_message = "ERROR: public, private, control_plane, database, and eni are the only keys allowed in the subnet_azs map" } } variable "security_group_id" { From 7dc78da56b4c98e24ababdf5cf6826e73a2f529b Mon Sep 17 00:00:00 2001 From: Deshmukh Date: Wed, 20 Nov 2024 17:08:54 +0530 Subject: [PATCH 03/40] Creating VPC attachment for Hub integration as per AWS NG requirements --- examples/sample-input-nist.tfvars | 3 +++ main.tf | 3 +++ modules/aws_vpc/main.tf | 16 +++++++++++++++- modules/aws_vpc/variables.tf | 16 ++++++++++++++++ variables.tf | 15 +++++++++++++++ 5 files changed, 52 insertions(+), 1 deletion(-) diff --git a/examples/sample-input-nist.tfvars b/examples/sample-input-nist.tfvars index cd35ce97..d5832cbf 100644 --- a/examples/sample-input-nist.tfvars +++ b/examples/sample-input-nist.tfvars @@ -14,6 +14,9 @@ location = "" # e.g., "us-east-1" #***************** CIDR Range for Spoke VPC ************** cidr = "10.80.16.0/22" +core_network_id = "core-network-0febf425a0504df84" +hub = "CustomerSpokeUS" +hub_environment = "dev" # ********* Set to true to enable NIST complaint code *********** enable_nist_features = false diff --git a/main.tf b/main.tf index 6f66568a..95e5e386 100755 --- a/main.tf +++ b/main.tf @@ -91,6 +91,9 @@ module "vpc" { private_subnet_tags = merge(local.tags, { "kubernetes.io/role/internal-elb" = "1" }, { "kubernetes.io/cluster/${local.cluster_name}" = "shared" }) additional_cidr_ranges = var.additional_cidr_ranges enable_nist_features = var.enable_nist_features + core_network_id = var.core_network_id + hub_environment = var.hub_environment + hub = var.hub } # EKS Setup - https://github.com/terraform-aws-modules/terraform-aws-eks diff --git a/modules/aws_vpc/main.tf b/modules/aws_vpc/main.tf index 5aea5d6f..a029dcd8 100644 --- a/modules/aws_vpc/main.tf +++ b/modules/aws_vpc/main.tf @@ -381,4 +381,18 @@ resource "aws_route_table_association" "eni" { count = var.enable_nist_features == true ? length(aws_subnet.eni) : 0 subnet_id = element(aws_subnet.eni[*].id, count.index) route_table_id = element(aws_route_table.private[*].id, 0) -} \ No newline at end of file +} + +################# +# VPC attachment for HUB integration ##### +################# +resource "aws_networkmanager_vpc_attachment" "vpc_attach" { + count = var.enable_nist_features == true ? 1 : 0 + subnet_arns = aws_subnet.eni[*].arn + core_network_id = var.core_network_id + vpc_arn = aws_vpc.vpc[0].arn + tags = { + segment = var.hub + Name = "${var.name}-${var.hub_environment}" + } +} diff --git a/modules/aws_vpc/variables.tf b/modules/aws_vpc/variables.tf index 60668351..b31a1b7a 100644 --- a/modules/aws_vpc/variables.tf +++ b/modules/aws_vpc/variables.tf @@ -182,3 +182,19 @@ variable "eni_subnet_azs" { type = list(string) default = [] } + +variable "hub_environment" { + description = "name of the hub_environment" + type = string +} + +variable "core_network_id" { + description = "Cloud WAN: Core network ID from Global networking account" + type = string +} + +variable "hub" { + description = "Name of the Hub: for e.g, CustomerSpokeUS or CustomerSpokeEU " + type = string +} + diff --git a/variables.tf b/variables.tf index 6fcaaf06..158a3443 100644 --- a/variables.tf +++ b/variables.tf @@ -726,3 +726,18 @@ variable "additional_cidr_ranges" { type = list(string) default = null } + +variable "hub_environment" { + description = "name of the hub_environment" + type = string +} + +variable "core_network_id" { + description = "Cloud WAN: Core network ID from Global networking account" + type = string +} + +variable "hub" { + description = "Name of the Hub: for e.g, CustomerSpokeUS or CustomerSpokeEU " + type = string +} From a6889c54ef435e8ee43666f13c480db4cf291b3c Mon Sep 17 00:00:00 2001 From: Deshmukh Date: Wed, 20 Nov 2024 17:22:35 +0530 Subject: [PATCH 04/40] Updating Private route table with a route to Cloud WAN for hub integration --- examples/sample-input-nist.tfvars | 1 + main.tf | 1 + modules/aws_vpc/main.tf | 15 +++++++++++++++ modules/aws_vpc/variables.tf | 4 ++++ variables.tf | 6 ++++++ 5 files changed, 27 insertions(+) diff --git a/examples/sample-input-nist.tfvars b/examples/sample-input-nist.tfvars index d5832cbf..f542aba6 100644 --- a/examples/sample-input-nist.tfvars +++ b/examples/sample-input-nist.tfvars @@ -17,6 +17,7 @@ cidr = "10.80.16.0/22" core_network_id = "core-network-0febf425a0504df84" hub = "CustomerSpokeUS" hub_environment = "dev" +core_network_arn = "arn:aws:networkmanager::654654181786:core-network/core-network-0febf425a0504df84" # ********* Set to true to enable NIST complaint code *********** enable_nist_features = false diff --git a/main.tf b/main.tf index 95e5e386..f9fc3bae 100755 --- a/main.tf +++ b/main.tf @@ -92,6 +92,7 @@ module "vpc" { additional_cidr_ranges = var.additional_cidr_ranges enable_nist_features = var.enable_nist_features core_network_id = var.core_network_id + core_network_arn = var.core_network_arn hub_environment = var.hub_environment hub = var.hub } diff --git a/modules/aws_vpc/main.tf b/modules/aws_vpc/main.tf index a029dcd8..ead7ef69 100644 --- a/modules/aws_vpc/main.tf +++ b/modules/aws_vpc/main.tf @@ -396,3 +396,18 @@ resource "aws_networkmanager_vpc_attachment" "vpc_attach" { Name = "${var.name}-${var.hub_environment}" } } + +################# +# Route to Core network device from Private route table ##### +################# +resource "aws_route" "private_core_network" { + count = var.enable_nist_features == true ? 1 : 0 + route_table_id = aws_route_table.private[0].id + destination_cidr_block = "0.0.0.0/0" + core_network_arn = var.core_network_arn + depends_on = [aws_networkmanager_vpc_attachment.vpc_attach] + + timeouts { + create = "5m" + } +} diff --git a/modules/aws_vpc/variables.tf b/modules/aws_vpc/variables.tf index b31a1b7a..f19e26ae 100644 --- a/modules/aws_vpc/variables.tf +++ b/modules/aws_vpc/variables.tf @@ -198,3 +198,7 @@ variable "hub" { type = string } +variable "core_network_arn" { + description = "Core network ARN" + type = string +} diff --git a/variables.tf b/variables.tf index 158a3443..67dcb590 100644 --- a/variables.tf +++ b/variables.tf @@ -741,3 +741,9 @@ variable "hub" { description = "Name of the Hub: for e.g, CustomerSpokeUS or CustomerSpokeEU " type = string } + +variable "core_network_arn" { + description = "Core network ARN" + type = string +} + From 760cfdb0ae99e947fb9a0d713be9a9d06f1add0f Mon Sep 17 00:00:00 2001 From: Deshmukh Date: Wed, 20 Nov 2024 17:36:06 +0530 Subject: [PATCH 05/40] Identifying & associating the resolver rules to query internal private domain records as per the design --- modules/aws_vpc/main.tf | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/modules/aws_vpc/main.tf b/modules/aws_vpc/main.tf index ead7ef69..48515717 100644 --- a/modules/aws_vpc/main.tf +++ b/modules/aws_vpc/main.tf @@ -411,3 +411,29 @@ resource "aws_route" "private_core_network" { create = "5m" } } + +################# +# Resolver config +################# + +resource "aws_route53_resolver_dnssec_config" "config" { + count = var.enable_nist_features == true ? 1 : 0 + resource_id = aws_vpc.vpc[0].id +} + +################# +# Fetching the resolver Rules +################# +data "aws_route53_resolver_rule" "rule" { + count = var.enable_nist_features == true ? 1 : 0 + name = "${var.hub}-sasng-${var.hub_environment}-r53-resolver-rule" +} + +################# +# Associating the resolver rules to VPC +################# +resource "aws_route53_resolver_rule_association" "rule" { + count = var.enable_nist_features == true ? 1 : 0 + resolver_rule_id = data.aws_route53_resolver_rule.rule[0].id + vpc_id = aws_vpc.vpc[0].id +} \ No newline at end of file From b389c4ccc7e96ab894ea85e30607c7ab12907b37 Mon Sep 17 00:00:00 2001 From: Deshmukh Date: Wed, 20 Nov 2024 17:53:38 +0530 Subject: [PATCH 06/40] Creating new private endpoints to facilitate the Nodegroups connecting to EKS --- main.tf | 1 + modules/aws_vpc/main.tf | 23 +++++++++++++++++++++++ modules/aws_vpc/variables.tf | 10 ++++++++++ variables.tf | 10 ++++++++++ 4 files changed, 44 insertions(+) diff --git a/main.tf b/main.tf index f9fc3bae..f4737fef 100755 --- a/main.tf +++ b/main.tf @@ -95,6 +95,7 @@ module "vpc" { core_network_arn = var.core_network_arn hub_environment = var.hub_environment hub = var.hub + vpc_nist_endpoints = var.vpc_nist_endpoints } # EKS Setup - https://github.com/terraform-aws-modules/terraform-aws-eks diff --git a/modules/aws_vpc/main.tf b/modules/aws_vpc/main.tf index 48515717..fc0a0773 100644 --- a/modules/aws_vpc/main.tf +++ b/modules/aws_vpc/main.tf @@ -76,6 +76,29 @@ resource "aws_vpc_endpoint" "private_endpoints" { ] : null } +###### +### Additional private endpoints required for HUB integration +###### +resource "aws_vpc_endpoint" "nist_endpoints" { + for_each = var.enable_nist_features == true ? var.vpc_nist_endpoints : {} + vpc_id = local.vpc_id + service_name = "com.amazonaws.${var.region}.${each.key}" + vpc_endpoint_type = each.value + security_group_ids = each.value == "Interface" ? [var.security_group_id] : null + private_dns_enabled = each.value == "Interface" ? true : null + + tags = merge( + { + "Name" = format("%s", "${var.name}-private-endpoint-${each.key}") + }, + var.tags + ) + + subnet_ids = each.value == "Interface" ? [ + for subnet in local.private_subnets : subnet.id + ] : null +} + data "aws_subnet" "public" { count = local.existing_public_subnets ? length(var.existing_subnet_ids["public"]) : 0 id = element(var.existing_subnet_ids["public"], count.index) diff --git a/modules/aws_vpc/variables.tf b/modules/aws_vpc/variables.tf index f19e26ae..585117dd 100644 --- a/modules/aws_vpc/variables.tf +++ b/modules/aws_vpc/variables.tf @@ -202,3 +202,13 @@ variable "core_network_arn" { description = "Core network ARN" type = string } + +variable "vpc_nist_endpoints" { + description = "Endpoints needed for private cluster with WAN" + type = map(string) + default = { + "ssm" = "Interface", + "ssmmessages" = "Interface", + "ec2messages" = "Interface" + } +} diff --git a/variables.tf b/variables.tf index 67dcb590..febd1892 100644 --- a/variables.tf +++ b/variables.tf @@ -747,3 +747,13 @@ variable "core_network_arn" { type = string } +variable "vpc_nist_endpoints" { + description = "Endpoints needed for private cluster with WAN" + type = map(string) + default = { + "ssm" = "Interface", + "ssmmessages" = "Interface", + "ec2messages" = "Interface" + } +} + From ce62f91292abe9f5b7be2a27488f5c8d55872ab9 Mon Sep 17 00:00:00 2001 From: Deshmukh Date: Wed, 20 Nov 2024 18:07:17 +0530 Subject: [PATCH 07/40] Applying condition on NAT gateway, EIP, Private route on NAT gateway to be created only if NIST features are set to false --- modules/aws_vpc/main.tf | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/aws_vpc/main.tf b/modules/aws_vpc/main.tf index fc0a0773..d5e8b469 100644 --- a/modules/aws_vpc/main.tf +++ b/modules/aws_vpc/main.tf @@ -324,7 +324,7 @@ resource "aws_subnet" "control_plane" { } resource "aws_eip" "nat" { - count = var.existing_nat_id == null ? local.create_nat_gateway ? 1 : 0 : 0 + count = var.existing_nat_id == null ? local.create_nat_gateway ? var.enable_nist_features == false ? 1 : 0 : 0 : 0 domain = "vpc" @@ -346,7 +346,7 @@ data "aws_nat_gateway" "nat_gateway" { } resource "aws_nat_gateway" "nat_gateway" { - count = var.existing_nat_id == null ? local.create_nat_gateway ? 1 : 0 : 0 + count = var.existing_nat_id == null ? local.create_nat_gateway ? var.enable_nist_features == false ? 1 : 0 : 0 : 0 allocation_id = element(aws_eip.nat[*].id, 0) subnet_id = local.existing_public_subnets ? element(data.aws_subnet.public[*].id, 0) : element(aws_subnet.public[*].id, 0) @@ -366,7 +366,7 @@ resource "aws_nat_gateway" "nat_gateway" { } resource "aws_route" "private_nat_gateway" { - count = var.existing_nat_id == null ? local.create_nat_gateway ? 1 : 0 : 0 + count = var.existing_nat_id == null ? local.create_nat_gateway ? var.enable_nist_features == false ? 1 : 0 : 0 : null route_table_id = element(aws_route_table.private[*].id, count.index) destination_cidr_block = "0.0.0.0/0" From 72508fdcd0ca1cb7f272c5fda76100b108bf4db3 Mon Sep 17 00:00:00 2001 From: Deshmukh Date: Wed, 20 Nov 2024 18:17:59 +0530 Subject: [PATCH 08/40] added additional tags on VPC,Private route table --- modules/aws_vpc/main.tf | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/modules/aws_vpc/main.tf b/modules/aws_vpc/main.tf index d5e8b469..badd17fe 100644 --- a/modules/aws_vpc/main.tf +++ b/modules/aws_vpc/main.tf @@ -42,6 +42,7 @@ resource "aws_vpc" "vpc" { tags = merge( { "Name" = format("%s", "${var.name}-vpc") + "type" = var.enable_nist_features == true ? "awsng-spoke-vpc" : null }, var.tags, ) @@ -236,7 +237,8 @@ resource "aws_subnet" "private" { "%s-${var.private_subnet_suffix}-%s", var.name, element(var.private_subnet_azs, count.index), - ) + ), + "nlb" = "yes" }, var.tags, var.private_subnet_tags, @@ -258,7 +260,8 @@ resource "aws_route_table" "private" { "%s-${var.private_subnet_suffix}-%s", var.name, element(var.private_subnet_azs, count.index), - ) + ), + "type" = var.enable_nist_features == true ? "awsng-spoke-private-rt" : null }, var.tags, ) From b6f7398e8cd8dfd61ca2574083a9e69ab52dbd0e Mon Sep 17 00:00:00 2001 From: Deshmukh Date: Wed, 20 Nov 2024 19:29:03 +0530 Subject: [PATCH 09/40] Creating kms script to enable encryption via CMK for EC2, RDS, EFS and FSx Ontap only if NIST falg is set to true --- examples/sample-input-nist.tfvars | 1 + kms.tf | 61 +++++++++++++++++++++++++++++++ locals.tf | 16 ++++++++ variables.tf | 5 +++ 4 files changed, 83 insertions(+) create mode 100644 kms.tf diff --git a/examples/sample-input-nist.tfvars b/examples/sample-input-nist.tfvars index f542aba6..049cb141 100644 --- a/examples/sample-input-nist.tfvars +++ b/examples/sample-input-nist.tfvars @@ -21,6 +21,7 @@ core_network_arn = "arn:aws:networkmanager::654654181786:core-network/core-net # ********* Set to true to enable NIST complaint code *********** enable_nist_features = false +backup_account_id = "992382826079" #***************** Additional CIDR ranges for Spoke VPC ************* diff --git a/kms.tf b/kms.tf new file mode 100644 index 00000000..20f6274f --- /dev/null +++ b/kms.tf @@ -0,0 +1,61 @@ + +# ####### Create CMK for each resource ################# +data "aws_caller_identity" "current" {} + +resource "aws_kms_key" "cmk" { + for_each = { + for key in keys(local.key_names) : + key => key if var.enable_nist_features && ( + key == "rds_key" || + key == "ebs_key" || + (key == "efs_key" && var.storage_type_backend == "efs") || + (key == "fsx_key" && var.storage_type_backend == "ontap") + ) + } + description = "KMS key for ${each.value}" + enable_key_rotation = true + deletion_window_in_days = 7 + tags = local.tags + policy = jsonencode({ + "Version" : "2012-10-17", + "Id" : "${each.value}-policy", # Unique identifier for the policy + "Statement" : [ + { + "Sid" : "Allow access through ${each.key} for all principals in the account", + "Effect" : "Allow", + "Principal" : { + "AWS" : [ + "arn:aws:iam::${data.aws_caller_identity.current.account_id}:root", + "arn:aws:iam::${var.backup_account_id}:root" + ] + }, + "Action" : "kms:*", + "Resource" : "*" + }, + { + "Sid" : "Allow direct access to key metadata to the account", + "Effect" : "Allow", + "Principal" : { + "AWS" : "arn:aws:iam::${data.aws_caller_identity.current.account_id}:root" + }, + "Action" : [ + "kms:Describe*", + "kms:Get*", + "kms:List*", + "kms:RevokeGrant" + ], + "Resource" : "*" + } + ] + }) +} + + + +resource "aws_kms_alias" "cmk" { + for_each = var.enable_nist_features ? { for key in keys(local.key_names) : key => key if contains(keys(aws_kms_key.cmk), key) } : {} + name = "alias/${local.key_names[each.key]}" + target_key_id = aws_kms_key.cmk[each.key].key_id +} + + diff --git a/locals.tf b/locals.tf index e72eb882..bd0a5ad3 100755 --- a/locals.tf +++ b/locals.tf @@ -181,4 +181,20 @@ locals { "internal" : false } } : {} + + ####### Create and associate KMS keys only if NIST code is enabled ###### + key_names = { + "rds_key" = "${var.prefix}-rds-key" + "fsx_key" = "${var.prefix}-fsx-key" + "efs_key" = "${var.prefix}-efs-key" + "ebs_key" = "${var.prefix}-ebs-key" + "eks_key" = "${var.prefix}-eks-key" + } + + kms_keys = { + for key in keys(local.key_names) : + key => aws_kms_key.cmk[key].arn + if contains(keys(aws_kms_key.cmk), key) + } + } diff --git a/variables.tf b/variables.tf index febd1892..6f104200 100644 --- a/variables.tf +++ b/variables.tf @@ -757,3 +757,8 @@ variable "vpc_nist_endpoints" { } } +variable "backup_account_id" { + type = string + description = "Central backup account number for backup and logging" +} + From e1f7dd0be6071abd0f9dd76bd4bd540dfec5cbef Mon Sep 17 00:00:00 2001 From: Deshmukh Date: Wed, 20 Nov 2024 19:47:27 +0530 Subject: [PATCH 10/40] Enabling Instance metadata service v2 and CMK encryption on volumes as per NIST standards --- modules/aws_vm/main.tf | 10 ++++++++++ modules/aws_vm/variables.tf | 6 ++++++ vms.tf | 4 +++- 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/modules/aws_vm/main.tf b/modules/aws_vm/main.tf index 6eccb769..bf6440ae 100644 --- a/modules/aws_vm/main.tf +++ b/modules/aws_vm/main.tf @@ -75,12 +75,21 @@ resource "aws_instance" "vm" { subnet_id = var.subnet_id associate_public_ip_address = var.create_public_ip + metadata_options { + http_endpoint = var.enable_nist_features == true ? "enabled" : "disabled" + http_tokens = var.enable_nist_features == true ? "required" : "optional" + http_put_response_hop_limit = 1 + http_protocol_ipv6 = var.enable_nist_features == true ? "enabled" : "disabled" + instance_metadata_tags = var.enable_nist_features == true ? "enabled" : "disabled" + } + root_block_device { volume_type = var.os_disk_type volume_size = var.os_disk_size delete_on_termination = var.os_disk_delete_on_termination iops = var.os_disk_iops encrypted = var.enable_ebs_encryption + kms_key_id = var.ebs_cmk_key tags = merge( { Name : "${var.name}-root-vol" @@ -123,6 +132,7 @@ resource "aws_ebs_volume" "raid_disk" { iops = var.data_disk_iops tags = merge(var.tags, tomap({ Name : "${var.name}-vm" })) encrypted = var.enable_ebs_encryption + kms_key_id = var.ebs_cmk_key } # Reference the feature flag variable name, an example reference to suppress TFLint warning diff --git a/modules/aws_vm/variables.tf b/modules/aws_vm/variables.tf index 707a7d8b..7b2a7c48 100644 --- a/modules/aws_vm/variables.tf +++ b/modules/aws_vm/variables.tf @@ -118,3 +118,9 @@ variable "enable_nist_features" { type = bool default = false } + +variable "ebs_cmk_key" { + description = "KMS key for ebs encryption" + type = string + default = "null" +} diff --git a/vms.tf b/vms.tf index b4628a06..1d4ee243 100644 --- a/vms.tf +++ b/vms.tf @@ -127,7 +127,9 @@ module "jump" { ssh_public_key = local.ssh_public_key enable_ebs_encryption = var.enable_ebs_encryption - cloud_init = data.cloudinit_config.jump[0].rendered + cloud_init = data.cloudinit_config.jump[0].rendered + ebs_cmk_key = lookup(local.kms_keys, "ebs_key", null) + enable_nist_features = var.enable_nist_features depends_on = [module.nfs] From fdaf38656a6224cf1cc71a1ab8e4149e6fb5e784 Mon Sep 17 00:00:00 2001 From: Deshmukh Date: Wed, 20 Nov 2024 20:44:49 +0530 Subject: [PATCH 11/40] Creating enhanced monitoring role for Postgres as per NIST standards --- main.tf | 7 +++++++ modules/aws_rds_iam/main.tf | 30 ++++++++++++++++++++++++++++++ modules/aws_rds_iam/outputs.tf | 4 ++++ modules/aws_rds_iam/variables.tf | 4 ++++ 4 files changed, 45 insertions(+) create mode 100644 modules/aws_rds_iam/main.tf create mode 100644 modules/aws_rds_iam/outputs.tf create mode 100644 modules/aws_rds_iam/variables.tf diff --git a/main.tf b/main.tf index f4737fef..21f65fef 100755 --- a/main.tf +++ b/main.tf @@ -354,3 +354,10 @@ resource "aws_resourcegroups_group" "aws_rg" { JSON } } + +########## Monitoring role for RDS ######### + +module "monitoring_role" { + source = "./modules/aws_rds_iam" + enable_nist_features = var.enable_nist_features +} diff --git a/modules/aws_rds_iam/main.tf b/modules/aws_rds_iam/main.tf new file mode 100644 index 00000000..8f409151 --- /dev/null +++ b/modules/aws_rds_iam/main.tf @@ -0,0 +1,30 @@ +################################################################################ +# Create an IAM role to allow enhanced monitoring +################################################################################ + +resource "aws_iam_role" "rds_enhanced_monitoring" { + count = var.enable_nist_features == true ? 1 : 0 + name_prefix = "rds-enhanced-monitoring-iam-role" + assume_role_policy = data.aws_iam_policy_document.rds_enhanced_monitoring.json +} + +resource "aws_iam_role_policy_attachment" "rds_enhanced_monitoring" { + count = var.enable_nist_features == true ? 1 : 0 + role = aws_iam_role.rds_enhanced_monitoring[0].name + policy_arn = "arn:aws:iam::aws:policy/service-role/AmazonRDSEnhancedMonitoringRole" +} + +data "aws_iam_policy_document" "rds_enhanced_monitoring" { + statement { + actions = [ + "sts:AssumeRole", + ] + + effect = "Allow" + + principals { + type = "Service" + identifiers = ["monitoring.rds.amazonaws.com"] + } + } +} diff --git a/modules/aws_rds_iam/outputs.tf b/modules/aws_rds_iam/outputs.tf new file mode 100644 index 00000000..b0e90399 --- /dev/null +++ b/modules/aws_rds_iam/outputs.tf @@ -0,0 +1,4 @@ +output "rds_monitoring_role" { + description = "Role ARN of the RDS" + value = var.enable_nist_features == true ? aws_iam_role.rds_enhanced_monitoring[0].arn : null +} \ No newline at end of file diff --git a/modules/aws_rds_iam/variables.tf b/modules/aws_rds_iam/variables.tf new file mode 100644 index 00000000..7b96406e --- /dev/null +++ b/modules/aws_rds_iam/variables.tf @@ -0,0 +1,4 @@ +variable "enable_nist_features" { + description = "A flag to enable NIST features under development for this project" + type = bool +} \ No newline at end of file From a2a8bd0492b16642774f48ab01d868cc2cd28d1d Mon Sep 17 00:00:00 2001 From: Deshmukh Date: Wed, 20 Nov 2024 21:05:22 +0530 Subject: [PATCH 12/40] CloudWatch alarm module added to create alarms for RDS, EFS, Fsx Ontap resources --- locals.tf | 3 + main.tf | 10 ++ modules/aws_cloudwatch/main.tf | 211 ++++++++++++++++++++++++++++ modules/aws_cloudwatch/variables.tf | 33 +++++ 4 files changed, 257 insertions(+) create mode 100644 modules/aws_cloudwatch/main.tf create mode 100644 modules/aws_cloudwatch/variables.tf diff --git a/locals.tf b/locals.tf index bd0a5ad3..7a6db92c 100755 --- a/locals.tf +++ b/locals.tf @@ -197,4 +197,7 @@ locals { if contains(keys(aws_kms_key.cmk), key) } + fsx_id = var.storage_type_backend == "ontap" ? aws_fsx_ontap_file_system.ontap-fs[0].id : null + efs_id = var.storage_type_backend == "efs" ? aws_efs_file_system.efs-fs[0].id : null + } diff --git a/main.tf b/main.tf index 21f65fef..6704a94d 100755 --- a/main.tf +++ b/main.tf @@ -361,3 +361,13 @@ module "monitoring_role" { source = "./modules/aws_rds_iam" enable_nist_features = var.enable_nist_features } + +module "cloudwatch" { + depends_on = [module.postgresql] + count = var.enable_nist_features == true ? 1 : 0 + source = "./modules/aws_cloudwatch" + prefix = var.prefix + storage_type_backend = var.storage_type_backend + efs_id = local.efs_id + fsx_id = local.fsx_id +} diff --git a/modules/aws_cloudwatch/main.tf b/modules/aws_cloudwatch/main.tf new file mode 100644 index 00000000..2df57381 --- /dev/null +++ b/modules/aws_cloudwatch/main.tf @@ -0,0 +1,211 @@ +# # SNS Notification +resource "aws_sns_topic" "user_updates" { + name = "SAS-AWS-NextGen-SNS-topic" + kms_master_key_id = "alias/aws/sns" +} +resource "aws_sns_topic_subscription" "user_updates_email_target" { + topic_arn = aws_sns_topic.user_updates.arn + protocol = "https" + endpoint = "https://srvc_azure_monitor:Za7zlnEMLLHckpE@sasdev.service-now.com/api/sn_em_connector/em/inbound_event?source=aws" +} + +# ########## RDS Postgres Instances ######### +# # CloudWatch Alarm for RDS CPU Utilization +resource "aws_cloudwatch_metric_alarm" "rds_cpu_utilization" { + alarm_name = "${var.prefix}-cpu-utilization" + comparison_operator = "GreaterThanThreshold" + evaluation_periods = "1" + metric_name = "CPUUtilization" + namespace = "AWS/RDS" + period = "900" + statistic = "Average" + threshold = var.cpu_threshold + actions_enabled = true + alarm_description = "Alarm if CPU utilization exceeds threshold" + alarm_actions = [aws_sns_topic.user_updates.arn] + dimensions = { + DBInstanceIdentifier = "${var.prefix}-default-pgsql" //var.instance_id + } +} + +# # # CloudWatch Alarm for RDS Write IOPS +resource "aws_cloudwatch_metric_alarm" "rds_write_iops" { + alarm_name = "${var.prefix}-RDS-Write-IOPS-Alert" + comparison_operator = "GreaterThanThreshold" + evaluation_periods = 1 + metric_name = "WriteIOPS" + namespace = "AWS/RDS" + period = 900 + statistic = "Average" + threshold = 1000 # Adjust the threshold based on your requirements + alarm_description = "Alarm when RDS write IOPS exceeds the threshold" + actions_enabled = true + alarm_actions = [aws_sns_topic.user_updates.arn] + dimensions = { + DBInstanceIdentifier = "${var.prefix}-default-pgsql" + } +} + +# CloudWatch Alarm for RDS READ IOPS +resource "aws_cloudwatch_metric_alarm" "rds_read_iops" { + alarm_name = "${var.prefix}-RDS-Read-IOPS-Alert" + comparison_operator = "GreaterThanThreshold" + evaluation_periods = 1 + metric_name = "ReadIOPS" + namespace = "AWS/RDS" + period = 900 + statistic = "Average" + threshold = 1000 # Adjust the threshold based on your requirements + alarm_description = "Alarm when RDS read IOPS exceeds the threshold" + actions_enabled = true + alarm_actions = [aws_sns_topic.user_updates.arn] + dimensions = { + DBInstanceIdentifier = "${var.prefix}-default-pgsql" + } +} + +# CloudWatch Alarm for RDS Network Receive Throughput +resource "aws_cloudwatch_metric_alarm" "rds_network_receive_throughput" { + alarm_name = "${var.prefix}-RDS-Network-Receive-Throughput-Alert" + comparison_operator = "GreaterThanThreshold" + evaluation_periods = 1 + metric_name = "NetworkReceiveThroughput" + namespace = "AWS/RDS" + period = 900 + statistic = "Average" + threshold = 1000000 # Adjust the threshold based on your requirements + alarm_description = "Alarm when RDS network receive throughput exceeds the threshold" + actions_enabled = true + alarm_actions = [aws_sns_topic.user_updates.arn] + dimensions = { + DBInstanceIdentifier = "${var.prefix}-default-pgsql" + } +} + +# # CloudWatch Alarm for RDS Network Transmit Throughput + +resource "aws_cloudwatch_metric_alarm" "rds_network_transmit_throughput" { + alarm_name = "${var.prefix}-RDS-Network-Transmit-Throughput-Alert" + comparison_operator = "GreaterThanThreshold" + evaluation_periods = 1 + metric_name = "NetworkReceiveThroughput" + namespace = "AWS/RDS" + period = 900 + statistic = "Average" + threshold = 1000000 # Adjust the threshold based on your requirements + alarm_description = "Alarm when RDS network transmit throughput exceeds the threshold" + actions_enabled = true + alarm_actions = [aws_sns_topic.user_updates.arn] + dimensions = { + DBInstanceIdentifier = "${var.prefix}-default-pgsql" + } +} + +#CloudWatch Alarm for RDS Freeable Memory +resource "aws_cloudwatch_metric_alarm" "rds_freeable_memory" { + alarm_name = "${var.prefix}-RDS-Free-Memory-Alert" + comparison_operator = "LessThanThreshold" + evaluation_periods = 1 + metric_name = "FreeableMemory" + namespace = "AWS/RDS" + period = 900 + statistic = "Average" + threshold = 500000000 # Adjust the threshold based on your requirements (in bytes) + alarm_description = "Alarm when RDS free memory is below the threshold" + actions_enabled = true + alarm_actions = [aws_sns_topic.user_updates.arn] + dimensions = { + DBInstanceIdentifier = "${var.prefix}-default-pgsql" + } +} + +# # CloudWatch Alarm for RDS Free Storage Space +resource "aws_cloudwatch_metric_alarm" "rds_free_storage" { + alarm_name = "${var.prefix}-RDS-Free-Storage-Alert" + comparison_operator = "LessThanThreshold" + evaluation_periods = 1 + metric_name = "FreeStorageSpace" + namespace = "AWS/RDS" + period = 900 + statistic = "Average" + threshold = 10000000000 # Adjust the threshold based on your requirements (in bytes) + alarm_description = "Alarm when RDS free disk space is below the threshold" + actions_enabled = true + alarm_actions = [aws_sns_topic.user_updates.arn] # Add SNS topic ARN for notifications + dimensions = { + DBInstanceIdentifier = "${var.prefix}-default-pgsql" + } +} + +# ###EFS############## +resource "aws_cloudwatch_metric_alarm" "efs_client_connections" { + count = var.storage_type_backend == "efs" ? 1 : 0 + alarm_name = "${var.prefix}-EFS-Client-Connections-Alarm" + comparison_operator = "GreaterThanThreshold" + evaluation_periods = "1" + metric_name = "ClientConnections" + namespace = "AWS/EFS" + period = "900" # 5 minutes + statistic = "Average" + threshold = "90" # Set your desired threshold + alarm_description = "Alarm when EFS client connections exceed 10" + alarm_actions = [aws_sns_topic.user_updates.arn] # Add SNS topic ARN for notifications + dimensions = { + FileSystemId = var.efs_id + } +} +resource "aws_cloudwatch_metric_alarm" "efs_total_io_bytes" { + count = var.storage_type_backend == "efs" ? 1 : 0 + alarm_name = "${var.prefix}-EFS-Total-IO-Bytes-Alarm" + comparison_operator = "GreaterThanThreshold" + evaluation_periods = "1" + metric_name = "TotalIOBytes" + namespace = "AWS/EFS" + period = "900" # 5 minutes + statistic = "Sum" + threshold = "1000000" # Set your desired threshold + alarm_description = "Alarm when EFS total IO bytes exceed 1,000,000" + alarm_actions = [aws_sns_topic.user_updates.arn] # Add SNS topic ARN for notifications + dimensions = { + FileSystemId = var.efs_id + } +} + +##FSX#### +# # # Alarm for storage capacity +resource "aws_cloudwatch_metric_alarm" "fsx_storage_capacity" { + count = var.storage_type_backend == "ontap" ? 1 : 0 + alarm_name = "${var.prefix}-fsx-storage-capacity-alarm" + comparison_operator = "GreaterThanThreshold" + evaluation_periods = 1 + metric_name = "StorageCapacity" + namespace = "AWS/FSx" + period = 900 + statistic = "Average" + threshold = 90 # Change threshold percentage as needed + alarm_description = "Alarm when FSx storage capacity exceeds 90%." + alarm_actions = [aws_sns_topic.user_updates.arn] # Add SNS topic ARN for notifications + dimensions = { + FileSystemId = var.fsx_id + } +} +# # # Alarm for storage used +resource "aws_cloudwatch_metric_alarm" "fsx_storage_used" { + count = var.storage_type_backend == "ontap" ? 1 : 0 + alarm_name = "${var.prefix}-fsx-storage-used-alarm" + comparison_operator = "GreaterThanThreshold" + evaluation_periods = 1 + metric_name = "StorageUsed" + namespace = "AWS/FSx" + period = 900 + statistic = "Average" + threshold = 90 # Change threshold percentage as needed + alarm_description = "Alarm when FSx storage used exceeds 90%." + alarm_actions = [aws_sns_topic.user_updates.arn] # Add SNS topic ARN for notifications + dimensions = { + FileSystemId = var.fsx_id + } +} + + + diff --git a/modules/aws_cloudwatch/variables.tf b/modules/aws_cloudwatch/variables.tf new file mode 100644 index 00000000..bd692646 --- /dev/null +++ b/modules/aws_cloudwatch/variables.tf @@ -0,0 +1,33 @@ +variable "prefix" { + description = "Prefix for CloudWatch alarm names" + type = string +} + +variable "cpu_threshold" { + description = "Threshold for CPU utilization" + type = number + default = 80 +} + +variable "storage_type_backend" { + description = "The storage backend used for the chosen storage type. Defaults to 'nfs' for storage_type='standard'. Defaults to 'efs for storage_type='ha'. 'efs' and 'ontap' are valid choices for storage_type='ha'." + type = string + default = "nfs" + # If storage_type is standard, this will be set to "nfs" + + validation { + condition = contains(["nfs", "efs", "ontap", "none"], lower(var.storage_type_backend)) + error_message = "ERROR: Supported values for `storage_type_backend` are nfs, efs, ontap and none." + } +} + +variable "efs_id" { + description = "EFS is" + type = string +} + +variable "fsx_id" { + description = "FSx is" + type = string +} + From 74de8a74b974f0645e0c351d2d52fe89f8252426 Mon Sep 17 00:00:00 2001 From: Deshmukh Date: Wed, 20 Nov 2024 22:03:23 +0530 Subject: [PATCH 13/40] Enabling NIST features on postgres module --- examples/sample-input-nist.tfvars | 16 ++++++++++++---- locals.tf | 11 +++++++++++ main.tf | 15 ++++++++++++--- modules/aws_vm/variables.tf | 1 - vms.tf | 1 + 5 files changed, 36 insertions(+), 8 deletions(-) diff --git a/examples/sample-input-nist.tfvars b/examples/sample-input-nist.tfvars index 049cb141..daa302ee 100644 --- a/examples/sample-input-nist.tfvars +++ b/examples/sample-input-nist.tfvars @@ -4,8 +4,8 @@ # **************** REQUIRED VARIABLES **************** # These required variables' values MUST be provided by the User -prefix = "" -location = "" # e.g., "us-east-1" +prefix = "test" +location = "us-east-1" # e.g., "us-east-1" # **************** REQUIRED VARIABLES **************** # !NOTE! - Without specifying your CIDR block access rules, ingress traffic @@ -13,20 +13,28 @@ location = "" # e.g., "us-east-1" #***************** CIDR Range for Spoke VPC ************** -cidr = "10.80.16.0/22" +vpc_cidr = "10.80.16.0/22" core_network_id = "core-network-0febf425a0504df84" hub = "CustomerSpokeUS" hub_environment = "dev" core_network_arn = "arn:aws:networkmanager::654654181786:core-network/core-network-0febf425a0504df84" # ********* Set to true to enable NIST complaint code *********** -enable_nist_features = false +enable_nist_features = true backup_account_id = "992382826079" #***************** Additional CIDR ranges for Spoke VPC ************* additional_cidr_ranges = ["10.88.4.0/24", "10.89.1.0/26", "10.90.0.128/27", "10.91.0.128/27"] +subnets = { + "private" : ["10.80.16.0/23"], + "control_plane" : ["10.90.0.128/28", "10.90.0.144/28"], # AWS recommends at least 16 IP addresses per subnet + "public" : ["10.89.1.0/27", "10.89.1.32/27"], + "database" : ["10.88.4.0/25", "10.88.4.128/25"], + "eni" : ["10.91.0.128/28", "10.91.0.144/28"] +} + # ************** RECOMMENDED VARIABLES *************** default_public_access_cidrs = [] # e.g., ["123.45.6.89/32"] ssh_public_key = "~/.ssh/id_rsa.pub" diff --git a/locals.tf b/locals.tf index 7a6db92c..301d3dd6 100755 --- a/locals.tf +++ b/locals.tf @@ -197,7 +197,18 @@ locals { if contains(keys(aws_kms_key.cmk), key) } + ####### Fetching EFS and FSx id for alarm creation ###### + fsx_id = var.storage_type_backend == "ontap" ? aws_fsx_ontap_file_system.ontap-fs[0].id : null efs_id = var.storage_type_backend == "efs" ? aws_efs_file_system.efs-fs[0].id : null + ####### Postgres NIST enhancements ###### + + copy_tags_snapshot = var.enable_nist_features == true ? true : false + rds_enhanced_monitoring = var.enable_nist_features == true ? module.monitoring_role.rds_monitoring_role : null + rds_storage_encryption = var.enable_nist_features == true ? true : false + rds_monitoring_interval = var.enable_nist_features == true ? 30 : 0 + rds_performance_insight = var.enable_nist_features == true ? true : false + rds_performance_retention_period = var.enable_nist_features == true ? 7 : 0 + } diff --git a/main.tf b/main.tf index 6704a94d..5eb71fcb 100755 --- a/main.tf +++ b/main.tf @@ -306,11 +306,11 @@ module "postgresql" { # disable backups to create DB faster backup_retention_period = each.value.backup_retention_days - tags = local.tags + tags = merge(local.tags, { "Backup" = var.enable_nist_features == true ? "Enabled" : null }) # DB subnet group - use public subnet if public access is requested - publicly_accessible = length(local.postgres_public_access_cidrs) > 0 ? true : false - subnet_ids = length(local.postgres_public_access_cidrs) > 0 ? length(module.vpc.public_subnets) > 0 ? module.vpc.public_subnets : module.vpc.database_subnets : module.vpc.database_subnets + publicly_accessible = length(local.postgres_public_access_cidrs) > 0 ? false : true + subnet_ids = length(local.postgres_public_access_cidrs) > 0 ? length(module.vpc.public_subnets) > 0 ? module.vpc.database_subnets : module.vpc.database_subnets : module.vpc.database_subnets # DB parameter group family = "postgres${each.value.server_version}" @@ -332,6 +332,15 @@ module "postgresql" { create_db_parameter_group = true create_db_option_group = true manage_master_user_password = false + ### NIST enhancements + kms_key_id = lookup(local.kms_keys, "rds_key", null) + performance_insights_enabled = local.rds_performance_insight + performance_insights_retention_period = local.rds_performance_retention_period + performance_insights_kms_key_id = lookup(local.kms_keys, "rds_key", null) + copy_tags_to_snapshot = local.copy_tags_snapshot + monitoring_interval = local.rds_monitoring_interval + monitoring_role_arn = local.rds_enhanced_monitoring + enabled_cloudwatch_logs_exports = ["postgresql", "upgrade"] } # Resource Groups - https://www.terraform.io/docs/providers/aws/r/resourcegroups_group.html diff --git a/modules/aws_vm/variables.tf b/modules/aws_vm/variables.tf index 7b2a7c48..8edcc752 100644 --- a/modules/aws_vm/variables.tf +++ b/modules/aws_vm/variables.tf @@ -122,5 +122,4 @@ variable "enable_nist_features" { variable "ebs_cmk_key" { description = "KMS key for ebs encryption" type = string - default = "null" } diff --git a/vms.tf b/vms.tf index 1d4ee243..0da2898c 100644 --- a/vms.tf +++ b/vms.tf @@ -180,4 +180,5 @@ module "nfs" { enable_ebs_encryption = var.enable_ebs_encryption cloud_init = data.cloudinit_config.nfs[0].rendered + ebs_cmk_key = lookup(local.kms_keys, "ebs_key", null) } From 7dd552c0fbc64bffc5b6658db758bd912aa2c109 Mon Sep 17 00:00:00 2001 From: Deshmukh Date: Thu, 21 Nov 2024 13:51:16 +0530 Subject: [PATCH 14/40] Enabling CMK encryption on efs and fsx resources as per NIST standards --- locals.tf | 1 - main.tf | 6 ++++-- vms.tf | 3 ++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/locals.tf b/locals.tf index 301d3dd6..876ee262 100755 --- a/locals.tf +++ b/locals.tf @@ -188,7 +188,6 @@ locals { "fsx_key" = "${var.prefix}-fsx-key" "efs_key" = "${var.prefix}-efs-key" "ebs_key" = "${var.prefix}-ebs-key" - "eks_key" = "${var.prefix}-eks-key" } kms_keys = { diff --git a/main.tf b/main.tf index 5eb71fcb..29c2d21e 100755 --- a/main.tf +++ b/main.tf @@ -9,11 +9,13 @@ provider "aws" { region = var.location - profile = var.aws_profile - shared_credentials_files = local.aws_shared_credentials + # profile = var.aws_profile + # shared_credentials_files = local.aws_shared_credentials access_key = var.aws_access_key_id secret_key = var.aws_secret_access_key token = var.aws_session_token + shared_config_files = ["\\Users\\viddeshmukh\\.aws\\credentials"] + profile = "221082210704_AdministratorAccess" } diff --git a/vms.tf b/vms.tf index 0da2898c..87beeec9 100644 --- a/vms.tf +++ b/vms.tf @@ -32,7 +32,7 @@ resource "aws_fsx_ontap_file_system" "ontap-fs" { preferred_subnet_id = module.vpc.private_subnets[0] security_group_ids = [local.workers_security_group_id] tags = merge(local.tags, { "Name" : "${var.prefix}-ontap-fs" }) - + kms_key_id = lookup(local.kms_keys, "fsx_key", null) depends_on = [module.ontap] } @@ -66,6 +66,7 @@ resource "aws_efs_file_system" "efs-fs" { provisioned_throughput_in_mibps = var.efs_throughput_mode == "provisioned" ? var.efs_throughput_rate : null tags = merge(local.tags, { "Name" : "${var.prefix}-efs" }) encrypted = var.enable_efs_encryption + kms_key_id = lookup(local.kms_keys, "efs_key", null) } # EFS Mount Target - https://www.terraform.io/docs/providers/aws/r/efs_mount_target.html From 5480100619d92604ac9f31d5bee1d893ee863150 Mon Sep 17 00:00:00 2001 From: Deshmukh Date: Thu, 21 Nov 2024 14:06:42 +0530 Subject: [PATCH 15/40] Updated outputs.tf --- main.tf | 6 ++---- outputs.tf | 10 +++++++++- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/main.tf b/main.tf index 29c2d21e..5eb71fcb 100755 --- a/main.tf +++ b/main.tf @@ -9,13 +9,11 @@ provider "aws" { region = var.location - # profile = var.aws_profile - # shared_credentials_files = local.aws_shared_credentials + profile = var.aws_profile + shared_credentials_files = local.aws_shared_credentials access_key = var.aws_access_key_id secret_key = var.aws_secret_access_key token = var.aws_session_token - shared_config_files = ["\\Users\\viddeshmukh\\.aws\\credentials"] - profile = "221082210704_AdministratorAccess" } diff --git a/outputs.tf b/outputs.tf index 16dd270c..6e5e38f9 100755 --- a/outputs.tf +++ b/outputs.tf @@ -122,7 +122,7 @@ output "postgres_servers" { output "nat_ip" { description = "List of public Elastic IPs created for AWS NAT Gateway." - value = module.vpc.create_nat_gateway ? module.vpc.nat_public_ips[0] : null + value = var.enable_nist_features == true ? null : module.vpc.nat_public_ips[0] } output "prefix" { @@ -243,3 +243,11 @@ output "enable_nist_features" { description = "Flag to enable NIST features." value = var.enable_nist_features } + +output "kms_key_arns" { + description = "KMS key arns's" + value = { + for key in keys(local.kms_keys) : + key => aws_kms_key.cmk[key].arn if contains(keys(aws_kms_key.cmk), key) + } +} From 2d08b144eb897e4975706939ddcbf8d7b07aca53 Mon Sep 17 00:00:00 2001 From: Deshmukh Date: Thu, 21 Nov 2024 14:16:05 +0530 Subject: [PATCH 16/40] Removing the IAM user on FSX Ontap module --- examples/sample-input-nist.tfvars | 4 +++- main.tf | 1 + modules/aws_fsx_ontap/main.tf | 15 --------------- 3 files changed, 4 insertions(+), 16 deletions(-) diff --git a/examples/sample-input-nist.tfvars b/examples/sample-input-nist.tfvars index daa302ee..97bcc953 100644 --- a/examples/sample-input-nist.tfvars +++ b/examples/sample-input-nist.tfvars @@ -58,7 +58,9 @@ default_nodepool_custom_data = "" ## General efs_performance_mode = "maxIO" -storage_type = "standard" +storage_type = "ha" +storage_type_backend = "efs" +enable_efs_encryption = true ## Cluster Node Pools config node_pools = { diff --git a/main.tf b/main.tf index 5eb71fcb..71f76a5d 100755 --- a/main.tf +++ b/main.tf @@ -15,6 +15,7 @@ provider "aws" { secret_key = var.aws_secret_access_key token = var.aws_session_token + } data "aws_eks_cluster_auth" "cluster" { diff --git a/modules/aws_fsx_ontap/main.tf b/modules/aws_fsx_ontap/main.tf index b8f3c4d5..332b40ae 100644 --- a/modules/aws_fsx_ontap/main.tf +++ b/modules/aws_fsx_ontap/main.tf @@ -66,18 +66,3 @@ data "aws_iam_policy_document" "fsx_ontap" { } } -resource "aws_iam_policy" "fsx_ontap" { - name_prefix = "${var.prefix}-fsx-ontap" - description = "FSx policy for user ${data.aws_iam_user.terraform.user_name}" - policy = data.aws_iam_policy_document.fsx_ontap.json - tags = var.tags -} - -data "aws_iam_user" "terraform" { - user_name = var.iam_user_name -} - -resource "aws_iam_user_policy_attachment" "attachment" { - user = data.aws_iam_user.terraform.user_name - policy_arn = aws_iam_policy.fsx_ontap.arn -} From fc97cbc6677327d834f40ca82d97179b35ea17a0 Mon Sep 17 00:00:00 2001 From: Deshmukh Date: Thu, 21 Nov 2024 15:28:37 +0530 Subject: [PATCH 17/40] S3 module creation for enabling logging --- examples/sample-input-nist.tfvars | 2 +- main.tf | 13 +- modules/aws_s3/locals.tf | 16 +++ modules/aws_s3/main.tf | 226 ++++++++++++++++++++++++++++++ modules/aws_s3/outputs.tf | 12 ++ modules/aws_s3/variables.tf | 43 ++++++ variables.tf | 22 +++ 7 files changed, 332 insertions(+), 2 deletions(-) create mode 100644 modules/aws_s3/locals.tf create mode 100644 modules/aws_s3/main.tf create mode 100644 modules/aws_s3/outputs.tf create mode 100644 modules/aws_s3/variables.tf diff --git a/examples/sample-input-nist.tfvars b/examples/sample-input-nist.tfvars index 97bcc953..5cca0bb7 100644 --- a/examples/sample-input-nist.tfvars +++ b/examples/sample-input-nist.tfvars @@ -59,7 +59,7 @@ default_nodepool_custom_data = "" ## General efs_performance_mode = "maxIO" storage_type = "ha" -storage_type_backend = "efs" +storage_type_backend = "ontap" enable_efs_encryption = true ## Cluster Node Pools config diff --git a/main.tf b/main.tf index 71f76a5d..1629bf2b 100755 --- a/main.tf +++ b/main.tf @@ -15,7 +15,6 @@ provider "aws" { secret_key = var.aws_secret_access_key token = var.aws_session_token - } data "aws_eks_cluster_auth" "cluster" { @@ -372,6 +371,7 @@ module "monitoring_role" { enable_nist_features = var.enable_nist_features } +########## Cloud watch alarms ######### module "cloudwatch" { depends_on = [module.postgresql] count = var.enable_nist_features == true ? 1 : 0 @@ -381,3 +381,14 @@ module "cloudwatch" { efs_id = local.efs_id fsx_id = local.fsx_id } + +##########Spoke bucket for centralized logging######## +module "spoke_logging_bucket" { + count = var.enable_nist_features == true ? 1 : 0 + source = "./modules/aws_s3" + central_logging_bucket = var.central_logging_bucket + location = var.location + spoke_account_id = var.spoke_account_id + tags = local.tags + hub_environment = var.hub_environment +} diff --git a/modules/aws_s3/locals.tf b/modules/aws_s3/locals.tf new file mode 100644 index 00000000..7dd0a6f3 --- /dev/null +++ b/modules/aws_s3/locals.tf @@ -0,0 +1,16 @@ +locals { + account_id_map = { + "us-east-1" = "127311923021" # US East (N. Virginia) + "us-east-2" = "033677994240" # US East (Ohio) + "us-west-1" = "027434742980" # US West (N. California) + "us-west-2" = "797873946194" # US West (Oregon) + "ap-south-1" = "718504428378" # Asia Pacific (Mumbai) + "ap-southeast-1" = "114774131450" # Asia Pacific (Singapore) + "ca-central-1" = "985666609251" # Canada (Central) + "eu-central-1" = "054676820928" # Europe (Frankfurt) + "eu-west-3" = "009996457667" # Europe (Paris) + "eu-west-1" = "156460612806" # Europe (Ireland) + "ap-northeast-1" = "582318560864" #Tokyo + } + account_id = lookup(local.account_id_map, var.location, null) +} \ No newline at end of file diff --git a/modules/aws_s3/main.tf b/modules/aws_s3/main.tf new file mode 100644 index 00000000..960fd0ac --- /dev/null +++ b/modules/aws_s3/main.tf @@ -0,0 +1,226 @@ +# ---------- SPOKE ACCOUNT LOG BUCKET ---------- # + +data "aws_caller_identity" "current" {} + + +resource "aws_s3_bucket" "local_s3_bucket" { + bucket = "aws-waf-logs-infra-${var.spoke_account_id}-${var.location}-bkt" + force_destroy = var.force_destroy + object_lock_enabled = true + tags = merge( + { + "Name" = format("%s", "aws-waf-logs-infra-${var.spoke_account_id}-${var.location}-bkt"), + }, + var.tags + ) +} + +resource "aws_s3_bucket_server_side_encryption_configuration" "encryption_local" { + bucket = aws_s3_bucket.local_s3_bucket.id + rule { + apply_server_side_encryption_by_default { + sse_algorithm = "AES256" + } + } +} + +resource "aws_s3_object" "log-prefix" { + depends_on = [aws_s3_bucket.local_s3_bucket] + for_each = toset(var.prefixes) + bucket = aws_s3_bucket.local_s3_bucket.id + content_encoding = "ContentMD5" + checksum_algorithm = "CRC32C" + key = "${each.value}/" + + lifecycle { + ignore_changes = [object_lock_retain_until_date, object_lock_mode] + } +} + +resource "aws_s3_bucket_public_access_block" "access_block_local" { + bucket = aws_s3_bucket.local_s3_bucket.id + block_public_acls = true + block_public_policy = true + ignore_public_acls = true + restrict_public_buckets = true +} +resource "aws_s3_bucket_versioning" "bucket_versioning_local" { + bucket = aws_s3_bucket.local_s3_bucket.id + versioning_configuration { + status = "Enabled" + mfa_delete = "Disabled" + } +} +resource "aws_s3_bucket_lifecycle_configuration" "log_bkt_lifecycle_local" { + bucket = aws_s3_bucket.local_s3_bucket.id + rule { + id = "spoke-rule" + filter {} # enabling lifecycle configuration on all objects in the bucket + expiration { + days = 30 + } + noncurrent_version_expiration { + noncurrent_days = 30 + } + status = "Enabled" + } +} +############### aws_s3_bucket_replication_configuration ################ +data "aws_iam_policy_document" "assume_role_local" { + statement { + effect = "Allow" + principals { + type = "Service" + identifiers = ["s3.amazonaws.com"] + } + principals { + type = "AWS" + identifiers = ["arn:aws:iam::730335345263:role/sascloud-awsng-logging-cross-account-iam-role"] + } + actions = ["sts:AssumeRole"] + } +} +resource "aws_iam_role" "replication_role_local" { + name = "sas-awsng-${var.location}-${var.hub_environment}-replication-role" + assume_role_policy = data.aws_iam_policy_document.assume_role_local.json + tags = var.tags +} +data "aws_iam_policy_document" "replication_json" { + statement { + effect = "Allow" + actions = [ + "s3:ListBucket", + "s3:GetReplicationConfiguration", + "s3:GetObjectVersionForReplication", + "s3:GetObjectVersionAcl", + "s3:GetObjectVersionTagging", + "s3:GetObjectRetention", + "s3:GetObjectLegalHold" + ] + resources = [ + "${aws_s3_bucket.local_s3_bucket.arn}/*", + "aws_s3_bucket.local_s3_bucket.arn", + "var.central_logging_bucket/*", + "var.central_logging_bucket" + ] + } + statement { + effect = "Allow" + actions = [ + "s3:ReplicateObject", + "s3:ReplicateDelete", + "s3:ReplicateTags", + "s3:ObjectOwnerOverrideToBucketOwner" + ] + resources = ["${aws_s3_bucket.local_s3_bucket.arn}/*", + "${var.central_logging_bucket}/*"] + } +} +resource "aws_s3_bucket_policy" "allow_access_from_another_account" { + bucket = aws_s3_bucket.local_s3_bucket.id + policy = < Date: Thu, 21 Nov 2024 15:50:13 +0530 Subject: [PATCH 18/40] Conformance pack creation for fetching the NIST controls applied on the account --- main.tf | 10 + ...-Best-Practices-for-NIST-800-53-rev-5.yaml | 1583 +++++++++++++++++ .../SAS-Custom-Conformance-Pack.yaml | 63 + modules/aws_config/main.tf | 16 + modules/aws_config/outputs.tf | 8 + modules/aws_config/variables.tf | 21 + variables.tf | 11 + 7 files changed, 1712 insertions(+) create mode 100644 modules/aws_config/Operational-Best-Practices-for-NIST-800-53-rev-5.yaml create mode 100644 modules/aws_config/SAS-Custom-Conformance-Pack.yaml create mode 100644 modules/aws_config/main.tf create mode 100644 modules/aws_config/outputs.tf create mode 100644 modules/aws_config/variables.tf diff --git a/main.tf b/main.tf index 1629bf2b..25a097b7 100755 --- a/main.tf +++ b/main.tf @@ -392,3 +392,13 @@ module "spoke_logging_bucket" { tags = local.tags hub_environment = var.hub_environment } + +###################################Config Conformance Pack############################ +module "nist_pack" { + count = var.enable_nist_features == true ? 1 : 0 + source = "./modules/aws_config" + conformance_pack_name = var.conformance_pack_name + custom_conformance_pack_name = var.custom_conformance_pack_name + hub_environment = var.hub_environment + tags = local.tags +} diff --git a/modules/aws_config/Operational-Best-Practices-for-NIST-800-53-rev-5.yaml b/modules/aws_config/Operational-Best-Practices-for-NIST-800-53-rev-5.yaml new file mode 100644 index 00000000..e497ab2e --- /dev/null +++ b/modules/aws_config/Operational-Best-Practices-for-NIST-800-53-rev-5.yaml @@ -0,0 +1,1583 @@ +################################################################################## +# +# Conformance Pack: +# Operational Best Practices for NIST 800-53 Rev5 +# +# This conformance pack helps verify compliance with NIST 800-53 Rev5 requirements. +# +# See Parameters section for names and descriptions of required parameters. +# +################################################################################## + +Parameters: + AccessKeysRotatedParamMaxAccessKeyAge: + Default: '90' + Type: String + AcmCertificateExpirationCheckParamDaysToExpiration: + Default: '90' + Type: String + CloudwatchAlarmActionCheckParamAlarmActionRequired: + Default: 'true' + Type: String + CloudwatchAlarmActionCheckParamInsufficientDataActionRequired: + Default: 'true' + Type: String + CloudwatchAlarmActionCheckParamOkActionRequired: + Default: 'false' + Type: String + IamCustomerPolicyBlockedKmsActionsParamBlockedActionsPatterns: + Default: kms:*, kms:Decrypt, kms:ReEncrypt* + Type: String + IamInlinePolicyBlockedKmsActionsParamBlockedActionsPatterns: + Default: kms:*, kms:Decrypt, kms:ReEncrypt* + Type: String + IamPasswordPolicyParamMaxPasswordAge: + Default: '90' + Type: String + IamPasswordPolicyParamMinimumPasswordLength: + Default: '14' + Type: String + IamPasswordPolicyParamPasswordReusePrevention: + Default: '24' + Type: String + IamPasswordPolicyParamRequireLowercaseCharacters: + Default: 'true' + Type: String + IamPasswordPolicyParamRequireNumbers: + Default: 'true' + Type: String + IamPasswordPolicyParamRequireSymbols: + Default: 'true' + Type: String + IamPasswordPolicyParamRequireUppercaseCharacters: + Default: 'true' + Type: String + IamUserUnusedCredentialsCheckParamMaxCredentialUsageAge: + Default: '90' + Type: String + RedshiftClusterConfigurationCheckParamClusterDbEncrypted: + Default: 'true' + Type: String + RedshiftClusterConfigurationCheckParamLoggingEnabled: + Default: 'true' + Type: String + RedshiftClusterMaintenancesettingsCheckParamAllowVersionUpgrade: + Default: 'true' + Type: String + RestrictedIncomingTrafficParamBlockedPort1: + Default: '20' + Type: String + RestrictedIncomingTrafficParamBlockedPort2: + Default: '21' + Type: String + RestrictedIncomingTrafficParamBlockedPort3: + Default: '3389' + Type: String + RestrictedIncomingTrafficParamBlockedPort4: + Default: '3306' + Type: String + RestrictedIncomingTrafficParamBlockedPort5: + Default: '4333' + Type: String + S3AccountLevelPublicAccessBlocksPeriodicParamBlockPublicAcls: + Default: 'true' + Type: String + S3AccountLevelPublicAccessBlocksPeriodicParamBlockPublicPolicy: + Default: 'true' + Type: String + S3AccountLevelPublicAccessBlocksPeriodicParamIgnorePublicAcls: + Default: 'true' + Type: String + S3AccountLevelPublicAccessBlocksPeriodicParamRestrictPublicBuckets: + Default: 'true' + Type: String + VpcSgOpenOnlyToAuthorizedPortsParamAuthorizedTcpPorts: + Default: '443' + Type: String +Resources: + AccessKeysRotated: + Properties: + ConfigRuleName: access-keys-rotated + InputParameters: + maxAccessKeyAge: + Fn::If: + - accessKeysRotatedParamMaxAccessKeyAge + - Ref: AccessKeysRotatedParamMaxAccessKeyAge + - Ref: AWS::NoValue + Source: + Owner: AWS + SourceIdentifier: ACCESS_KEYS_ROTATED + Type: AWS::Config::ConfigRule + AccountPartOfOrganizations: + Properties: + ConfigRuleName: account-part-of-organizations + Source: + Owner: AWS + SourceIdentifier: ACCOUNT_PART_OF_ORGANIZATIONS + Type: AWS::Config::ConfigRule + AcmCertificateExpirationCheck: + Properties: + ConfigRuleName: acm-certificate-expiration-check + InputParameters: + daysToExpiration: + Fn::If: + - acmCertificateExpirationCheckParamDaysToExpiration + - Ref: AcmCertificateExpirationCheckParamDaysToExpiration + - Ref: AWS::NoValue + Scope: + ComplianceResourceTypes: + - AWS::ACM::Certificate + Source: + Owner: AWS + SourceIdentifier: ACM_CERTIFICATE_EXPIRATION_CHECK + Type: AWS::Config::ConfigRule + AlbHttpToHttpsRedirectionCheck: + Properties: + ConfigRuleName: alb-http-to-https-redirection-check + Source: + Owner: AWS + SourceIdentifier: ALB_HTTP_TO_HTTPS_REDIRECTION_CHECK + Type: AWS::Config::ConfigRule + AlbWafEnabled: + Properties: + ConfigRuleName: alb-waf-enabled + Scope: + ComplianceResourceTypes: + - AWS::ElasticLoadBalancingV2::LoadBalancer + Source: + Owner: AWS + SourceIdentifier: ALB_WAF_ENABLED + Type: AWS::Config::ConfigRule + ApiGwAssociatedWithWaf: + Properties: + ConfigRuleName: api-gw-associated-with-waf + Scope: + ComplianceResourceTypes: + - AWS::ApiGateway::Stage + Source: + Owner: AWS + SourceIdentifier: API_GW_ASSOCIATED_WITH_WAF + Type: AWS::Config::ConfigRule + ApiGwCacheEnabledAndEncrypted: + Properties: + ConfigRuleName: api-gw-cache-enabled-and-encrypted + Scope: + ComplianceResourceTypes: + - AWS::ApiGateway::Stage + Source: + Owner: AWS + SourceIdentifier: API_GW_CACHE_ENABLED_AND_ENCRYPTED + Type: AWS::Config::ConfigRule + ApiGwExecutionLoggingEnabled: + Properties: + ConfigRuleName: api-gw-execution-logging-enabled + Scope: + ComplianceResourceTypes: + - AWS::ApiGateway::Stage + - AWS::ApiGatewayV2::Stage + Source: + Owner: AWS + SourceIdentifier: API_GW_EXECUTION_LOGGING_ENABLED + Type: AWS::Config::ConfigRule + ApiGwSslEnabled: + Properties: + ConfigRuleName: api-gw-ssl-enabled + Scope: + ComplianceResourceTypes: + - AWS::ApiGateway::Stage + Source: + Owner: AWS + SourceIdentifier: API_GW_SSL_ENABLED + Type: AWS::Config::ConfigRule + AutoscalingGroupElbHealthcheckRequired: + Properties: + ConfigRuleName: autoscaling-group-elb-healthcheck-required + Scope: + ComplianceResourceTypes: + - AWS::AutoScaling::AutoScalingGroup + Source: + Owner: AWS + SourceIdentifier: AUTOSCALING_GROUP_ELB_HEALTHCHECK_REQUIRED + Type: AWS::Config::ConfigRule + AutoscalingLaunchConfigPublicIpDisabled: + Properties: + ConfigRuleName: autoscaling-launch-config-public-ip-disabled + Scope: + ComplianceResourceTypes: + - AWS::AutoScaling::LaunchConfiguration + Source: + Owner: AWS + SourceIdentifier: AUTOSCALING_LAUNCH_CONFIG_PUBLIC_IP_DISABLED + Type: AWS::Config::ConfigRule + BeanstalkEnhancedHealthReportingEnabled: + Properties: + ConfigRuleName: beanstalk-enhanced-health-reporting-enabled + Scope: + ComplianceResourceTypes: + - AWS::ElasticBeanstalk::Environment + Source: + Owner: AWS + SourceIdentifier: BEANSTALK_ENHANCED_HEALTH_REPORTING_ENABLED + Type: AWS::Config::ConfigRule + CloudTrailCloudWatchLogsEnabled: + Properties: + ConfigRuleName: cloud-trail-cloud-watch-logs-enabled + Source: + Owner: AWS + SourceIdentifier: CLOUD_TRAIL_CLOUD_WATCH_LOGS_ENABLED + Type: AWS::Config::ConfigRule + CloudTrailEnabled: + Properties: + ConfigRuleName: cloudtrail-enabled + Source: + Owner: AWS + SourceIdentifier: CLOUD_TRAIL_ENABLED + Type: AWS::Config::ConfigRule + CloudTrailEncryptionEnabled: + Properties: + ConfigRuleName: cloud-trail-encryption-enabled + Source: + Owner: AWS + SourceIdentifier: CLOUD_TRAIL_ENCRYPTION_ENABLED + Type: AWS::Config::ConfigRule + CloudTrailLogFileValidationEnabled: + Properties: + ConfigRuleName: cloud-trail-log-file-validation-enabled + Source: + Owner: AWS + SourceIdentifier: CLOUD_TRAIL_LOG_FILE_VALIDATION_ENABLED + Type: AWS::Config::ConfigRule + CloudtrailS3DataeventsEnabled: + Properties: + ConfigRuleName: cloudtrail-s3-dataevents-enabled + Source: + Owner: AWS + SourceIdentifier: CLOUDTRAIL_S3_DATAEVENTS_ENABLED + Type: AWS::Config::ConfigRule + CloudwatchAlarmActionCheck: + Properties: + ConfigRuleName: cloudwatch-alarm-action-check + InputParameters: + alarmActionRequired: + Fn::If: + - cloudwatchAlarmActionCheckParamAlarmActionRequired + - Ref: CloudwatchAlarmActionCheckParamAlarmActionRequired + - Ref: AWS::NoValue + insufficientDataActionRequired: + Fn::If: + - cloudwatchAlarmActionCheckParamInsufficientDataActionRequired + - Ref: CloudwatchAlarmActionCheckParamInsufficientDataActionRequired + - Ref: AWS::NoValue + okActionRequired: + Fn::If: + - cloudwatchAlarmActionCheckParamOkActionRequired + - Ref: CloudwatchAlarmActionCheckParamOkActionRequired + - Ref: AWS::NoValue + Scope: + ComplianceResourceTypes: + - AWS::CloudWatch::Alarm + Source: + Owner: AWS + SourceIdentifier: CLOUDWATCH_ALARM_ACTION_CHECK + Type: AWS::Config::ConfigRule + CmkBackingKeyRotationEnabled: + Properties: + ConfigRuleName: cmk-backing-key-rotation-enabled + Source: + Owner: AWS + SourceIdentifier: CMK_BACKING_KEY_ROTATION_ENABLED + Type: AWS::Config::ConfigRule + CodebuildProjectArtifactEncryption: + Properties: + ConfigRuleName: codebuild-project-artifact-encryption + Scope: + ComplianceResourceTypes: + - AWS::CodeBuild::Project + Source: + Owner: AWS + SourceIdentifier: CODEBUILD_PROJECT_ARTIFACT_ENCRYPTION + Type: AWS::Config::ConfigRule + CodebuildProjectEnvvarAwscredCheck: + Properties: + ConfigRuleName: codebuild-project-envvar-awscred-check + Scope: + ComplianceResourceTypes: + - AWS::CodeBuild::Project + Source: + Owner: AWS + SourceIdentifier: CODEBUILD_PROJECT_ENVVAR_AWSCRED_CHECK + Type: AWS::Config::ConfigRule + DbInstanceBackupEnabled: + Properties: + ConfigRuleName: db-instance-backup-enabled + Scope: + ComplianceResourceTypes: + - AWS::RDS::DBInstance + Source: + Owner: AWS + SourceIdentifier: DB_INSTANCE_BACKUP_ENABLED + Type: AWS::Config::ConfigRule + DmsReplicationNotPublic: + Properties: + ConfigRuleName: dms-replication-not-public + Scope: + ComplianceResourceTypes: [] + Source: + Owner: AWS + SourceIdentifier: DMS_REPLICATION_NOT_PUBLIC + Type: AWS::Config::ConfigRule + DynamodbAutoscalingEnabled: + Properties: + ConfigRuleName: dynamodb-autoscaling-enabled + Scope: + ComplianceResourceTypes: + - AWS::DynamoDB::Table + Source: + Owner: AWS + SourceIdentifier: DYNAMODB_AUTOSCALING_ENABLED + Type: AWS::Config::ConfigRule + DynamodbInBackupPlan: + Properties: + ConfigRuleName: dynamodb-in-backup-plan + Source: + Owner: AWS + SourceIdentifier: DYNAMODB_IN_BACKUP_PLAN + Type: AWS::Config::ConfigRule + DynamodbPitrEnabled: + Properties: + ConfigRuleName: dynamodb-pitr-enabled + Scope: + ComplianceResourceTypes: + - AWS::DynamoDB::Table + Source: + Owner: AWS + SourceIdentifier: DYNAMODB_PITR_ENABLED + Type: AWS::Config::ConfigRule + DynamodbTableEncryptedKms: + Properties: + ConfigRuleName: dynamodb-table-encrypted-kms + Scope: + ComplianceResourceTypes: + - AWS::DynamoDB::Table + Source: + Owner: AWS + SourceIdentifier: DYNAMODB_TABLE_ENCRYPTED_KMS + Type: AWS::Config::ConfigRule + DynamodbThroughputLimitCheck: + Properties: + ConfigRuleName: dynamodb-throughput-limit-check + Source: + Owner: AWS + SourceIdentifier: DYNAMODB_THROUGHPUT_LIMIT_CHECK + Type: AWS::Config::ConfigRule + EbsInBackupPlan: + Properties: + ConfigRuleName: ebs-in-backup-plan + Source: + Owner: AWS + SourceIdentifier: EBS_IN_BACKUP_PLAN + Type: AWS::Config::ConfigRule + EbsOptimizedInstance: + Properties: + ConfigRuleName: ebs-optimized-instance + Scope: + ComplianceResourceTypes: + - AWS::EC2::Instance + Source: + Owner: AWS + SourceIdentifier: EBS_OPTIMIZED_INSTANCE + Type: AWS::Config::ConfigRule + EbsSnapshotPublicRestorableCheck: + Properties: + ConfigRuleName: ebs-snapshot-public-restorable-check + Source: + Owner: AWS + SourceIdentifier: EBS_SNAPSHOT_PUBLIC_RESTORABLE_CHECK + Type: AWS::Config::ConfigRule + Ec2EbsEncryptionByDefault: + Properties: + ConfigRuleName: ec2-ebs-encryption-by-default + Source: + Owner: AWS + SourceIdentifier: EC2_EBS_ENCRYPTION_BY_DEFAULT + Type: AWS::Config::ConfigRule + Ec2Imdsv2Check: + Properties: + ConfigRuleName: ec2-imdsv2-check + Scope: + ComplianceResourceTypes: + - AWS::EC2::Instance + Source: + Owner: AWS + SourceIdentifier: EC2_IMDSV2_CHECK + Type: AWS::Config::ConfigRule + Ec2InstanceManagedBySsm: + Properties: + ConfigRuleName: ec2-instance-managed-by-systems-manager + Scope: + ComplianceResourceTypes: + - AWS::EC2::Instance + - AWS::SSM::ManagedInstanceInventory + Source: + Owner: AWS + SourceIdentifier: EC2_INSTANCE_MANAGED_BY_SSM + Type: AWS::Config::ConfigRule + Ec2InstanceNoPublicIp: + Properties: + ConfigRuleName: ec2-instance-no-public-ip + Scope: + ComplianceResourceTypes: + - AWS::EC2::Instance + Source: + Owner: AWS + SourceIdentifier: EC2_INSTANCE_NO_PUBLIC_IP + Type: AWS::Config::ConfigRule + Ec2InstanceProfileAttached: + Properties: + ConfigRuleName: ec2-instance-profile-attached + Scope: + ComplianceResourceTypes: + - AWS::EC2::Instance + Source: + Owner: AWS + SourceIdentifier: EC2_INSTANCE_PROFILE_ATTACHED + Type: AWS::Config::ConfigRule + Ec2ManagedinstanceAssociationComplianceStatusCheck: + Properties: + ConfigRuleName: ec2-managedinstance-association-compliance-status-check + Scope: + ComplianceResourceTypes: + - AWS::SSM::AssociationCompliance + Source: + Owner: AWS + SourceIdentifier: EC2_MANAGEDINSTANCE_ASSOCIATION_COMPLIANCE_STATUS_CHECK + Type: AWS::Config::ConfigRule + Ec2ManagedinstancePatchComplianceStatusCheck: + Properties: + ConfigRuleName: ec2-managedinstance-patch-compliance-status-check + Scope: + ComplianceResourceTypes: + - AWS::SSM::PatchCompliance + Source: + Owner: AWS + SourceIdentifier: EC2_MANAGEDINSTANCE_PATCH_COMPLIANCE_STATUS_CHECK + Type: AWS::Config::ConfigRule + Ec2StoppedInstance: + Properties: + ConfigRuleName: ec2-stopped-instance + Source: + Owner: AWS + SourceIdentifier: EC2_STOPPED_INSTANCE + Type: AWS::Config::ConfigRule + Ec2VolumeInuseCheck: + Properties: + ConfigRuleName: ec2-volume-inuse-check + Scope: + ComplianceResourceTypes: + - AWS::EC2::Volume + Source: + Owner: AWS + SourceIdentifier: EC2_VOLUME_INUSE_CHECK + Type: AWS::Config::ConfigRule + EcsContainersReadonlyAccess: + Properties: + ConfigRuleName: ecs-containers-readonly-access + Scope: + ComplianceResourceTypes: + - AWS::ECS::TaskDefinition + Source: + Owner: AWS + SourceIdentifier: ECS_CONTAINERS_READONLY_ACCESS + Type: AWS::Config::ConfigRule + EcsTaskDefinitionUserForHostModeCheck: + Properties: + ConfigRuleName: ecs-task-definition-user-for-host-mode-check + Scope: + ComplianceResourceTypes: + - AWS::ECS::TaskDefinition + Source: + Owner: AWS + SourceIdentifier: ECS_TASK_DEFINITION_USER_FOR_HOST_MODE_CHECK + Type: AWS::Config::ConfigRule + EfsEncryptedCheck: + Properties: + ConfigRuleName: efs-encrypted-check + Source: + Owner: AWS + SourceIdentifier: EFS_ENCRYPTED_CHECK + Type: AWS::Config::ConfigRule + EfsInBackupPlan: + Properties: + ConfigRuleName: efs-in-backup-plan + Source: + Owner: AWS + SourceIdentifier: EFS_IN_BACKUP_PLAN + Type: AWS::Config::ConfigRule + ElasticBeanstalkManagedUpdatesEnabled: + Properties: + ConfigRuleName: elastic-beanstalk-managed-updates-enabled + Scope: + ComplianceResourceTypes: + - AWS::ElasticBeanstalk::Environment + Source: + Owner: AWS + SourceIdentifier: ELASTIC_BEANSTALK_MANAGED_UPDATES_ENABLED + Type: AWS::Config::ConfigRule + ElasticacheRedisClusterAutomaticBackupCheck: + Properties: + ConfigRuleName: elasticache-redis-cluster-automatic-backup-check + Source: + Owner: AWS + SourceIdentifier: ELASTICACHE_REDIS_CLUSTER_AUTOMATIC_BACKUP_CHECK + Type: AWS::Config::ConfigRule + ElasticsearchEncryptedAtRest: + Properties: + ConfigRuleName: elasticsearch-encrypted-at-rest + Source: + Owner: AWS + SourceIdentifier: ELASTICSEARCH_ENCRYPTED_AT_REST + Type: AWS::Config::ConfigRule + ElasticsearchInVpcOnly: + Properties: + ConfigRuleName: elasticsearch-in-vpc-only + Source: + Owner: AWS + SourceIdentifier: ELASTICSEARCH_IN_VPC_ONLY + Type: AWS::Config::ConfigRule + ElasticsearchLogsToCloudwatch: + Properties: + ConfigRuleName: elasticsearch-logs-to-cloudwatch + Scope: + ComplianceResourceTypes: + - AWS::Elasticsearch::Domain + Source: + Owner: AWS + SourceIdentifier: ELASTICSEARCH_LOGS_TO_CLOUDWATCH + Type: AWS::Config::ConfigRule + ElasticsearchNodeToNodeEncryptionCheck: + Properties: + ConfigRuleName: elasticsearch-node-to-node-encryption-check + Scope: + ComplianceResourceTypes: + - AWS::Elasticsearch::Domain + Source: + Owner: AWS + SourceIdentifier: ELASTICSEARCH_NODE_TO_NODE_ENCRYPTION_CHECK + Type: AWS::Config::ConfigRule + ElbAcmCertificateRequired: + Properties: + ConfigRuleName: elb-acm-certificate-required + Scope: + ComplianceResourceTypes: + - AWS::ElasticLoadBalancing::LoadBalancer + Source: + Owner: AWS + SourceIdentifier: ELB_ACM_CERTIFICATE_REQUIRED + Type: AWS::Config::ConfigRule + ElbCrossZoneLoadBalancingEnabled: + Properties: + ConfigRuleName: elb-cross-zone-load-balancing-enabled + Scope: + ComplianceResourceTypes: + - AWS::ElasticLoadBalancing::LoadBalancer + Source: + Owner: AWS + SourceIdentifier: ELB_CROSS_ZONE_LOAD_BALANCING_ENABLED + Type: AWS::Config::ConfigRule + ElbDeletionProtectionEnabled: + Properties: + ConfigRuleName: elb-deletion-protection-enabled + Scope: + ComplianceResourceTypes: + - AWS::ElasticLoadBalancingV2::LoadBalancer + Source: + Owner: AWS + SourceIdentifier: ELB_DELETION_PROTECTION_ENABLED + Type: AWS::Config::ConfigRule + ElbLoggingEnabled: + Properties: + ConfigRuleName: elb-logging-enabled + Scope: + ComplianceResourceTypes: + - AWS::ElasticLoadBalancing::LoadBalancer + - AWS::ElasticLoadBalancingV2::LoadBalancer + Source: + Owner: AWS + SourceIdentifier: ELB_LOGGING_ENABLED + Type: AWS::Config::ConfigRule + ElbTlsHttpsListenersOnly: + Properties: + ConfigRuleName: elb-tls-https-listeners-only + Scope: + ComplianceResourceTypes: + - AWS::ElasticLoadBalancing::LoadBalancer + Source: + Owner: AWS + SourceIdentifier: ELB_TLS_HTTPS_LISTENERS_ONLY + Type: AWS::Config::ConfigRule + Elbv2AcmCertificateRequired: + Properties: + ConfigRuleName: elbv2-acm-certificate-required + Source: + Owner: AWS + SourceIdentifier: ELBV2_ACM_CERTIFICATE_REQUIRED + Type: AWS::Config::ConfigRule + EmrMasterNoPublicIp: + Properties: + ConfigRuleName: emr-master-no-public-ip + Scope: + ComplianceResourceTypes: [] + Source: + Owner: AWS + SourceIdentifier: EMR_MASTER_NO_PUBLIC_IP + Type: AWS::Config::ConfigRule + EncryptedVolumes: + Properties: + ConfigRuleName: encrypted-volumes + Scope: + ComplianceResourceTypes: + - AWS::EC2::Volume + Source: + Owner: AWS + SourceIdentifier: ENCRYPTED_VOLUMES + Type: AWS::Config::ConfigRule + GuarddutyEnabledCentralized: + Properties: + ConfigRuleName: guardduty-enabled-centralized + Source: + Owner: AWS + SourceIdentifier: GUARDDUTY_ENABLED_CENTRALIZED + Type: AWS::Config::ConfigRule + IamCustomerPolicyBlockedKmsActions: + Properties: + ConfigRuleName: iam-customer-policy-blocked-kms-actions + InputParameters: + blockedActionsPatterns: + Fn::If: + - iamCustomerPolicyBlockedKmsActionsParamBlockedActionsPatterns + - Ref: IamCustomerPolicyBlockedKmsActionsParamBlockedActionsPatterns + - Ref: AWS::NoValue + Scope: + ComplianceResourceTypes: + - AWS::IAM::Policy + Source: + Owner: AWS + SourceIdentifier: IAM_CUSTOMER_POLICY_BLOCKED_KMS_ACTIONS + Type: AWS::Config::ConfigRule + IamInlinePolicyBlockedKmsActions: + Properties: + ConfigRuleName: iam-inline-policy-blocked-kms-actions + InputParameters: + blockedActionsPatterns: + Fn::If: + - iamInlinePolicyBlockedKmsActionsParamBlockedActionsPatterns + - Ref: IamInlinePolicyBlockedKmsActionsParamBlockedActionsPatterns + - Ref: AWS::NoValue + Scope: + ComplianceResourceTypes: + - AWS::IAM::Group + - AWS::IAM::Role + - AWS::IAM::User + Source: + Owner: AWS + SourceIdentifier: IAM_INLINE_POLICY_BLOCKED_KMS_ACTIONS + Type: AWS::Config::ConfigRule + IamNoInlinePolicyCheck: + Properties: + ConfigRuleName: iam-no-inline-policy-check + Scope: + ComplianceResourceTypes: + - AWS::IAM::User + - AWS::IAM::Role + - AWS::IAM::Group + Source: + Owner: AWS + SourceIdentifier: IAM_NO_INLINE_POLICY_CHECK + Type: AWS::Config::ConfigRule + IamPasswordPolicy: + Properties: + ConfigRuleName: iam-password-policy + InputParameters: + MaxPasswordAge: + Fn::If: + - iamPasswordPolicyParamMaxPasswordAge + - Ref: IamPasswordPolicyParamMaxPasswordAge + - Ref: AWS::NoValue + MinimumPasswordLength: + Fn::If: + - iamPasswordPolicyParamMinimumPasswordLength + - Ref: IamPasswordPolicyParamMinimumPasswordLength + - Ref: AWS::NoValue + PasswordReusePrevention: + Fn::If: + - iamPasswordPolicyParamPasswordReusePrevention + - Ref: IamPasswordPolicyParamPasswordReusePrevention + - Ref: AWS::NoValue + RequireLowercaseCharacters: + Fn::If: + - iamPasswordPolicyParamRequireLowercaseCharacters + - Ref: IamPasswordPolicyParamRequireLowercaseCharacters + - Ref: AWS::NoValue + RequireNumbers: + Fn::If: + - iamPasswordPolicyParamRequireNumbers + - Ref: IamPasswordPolicyParamRequireNumbers + - Ref: AWS::NoValue + RequireSymbols: + Fn::If: + - iamPasswordPolicyParamRequireSymbols + - Ref: IamPasswordPolicyParamRequireSymbols + - Ref: AWS::NoValue + RequireUppercaseCharacters: + Fn::If: + - iamPasswordPolicyParamRequireUppercaseCharacters + - Ref: IamPasswordPolicyParamRequireUppercaseCharacters + - Ref: AWS::NoValue + Source: + Owner: AWS + SourceIdentifier: IAM_PASSWORD_POLICY + Type: AWS::Config::ConfigRule + IamPolicyNoStatementsWithAdminAccess: + Properties: + ConfigRuleName: iam-policy-no-statements-with-admin-access + Scope: + ComplianceResourceTypes: + - AWS::IAM::Policy + Source: + Owner: AWS + SourceIdentifier: IAM_POLICY_NO_STATEMENTS_WITH_ADMIN_ACCESS + Type: AWS::Config::ConfigRule + IamPolicyNoStatementsWithFullAccess: + Properties: + ConfigRuleName: iam-policy-no-statements-with-full-access + Scope: + ComplianceResourceTypes: + - AWS::IAM::Policy + Source: + Owner: AWS + SourceIdentifier: IAM_POLICY_NO_STATEMENTS_WITH_FULL_ACCESS + Type: AWS::Config::ConfigRule + IamRootAccessKeyCheck: + Properties: + ConfigRuleName: iam-root-access-key-check + Source: + Owner: AWS + SourceIdentifier: IAM_ROOT_ACCESS_KEY_CHECK + Type: AWS::Config::ConfigRule + IamUserGroupMembershipCheck: + Properties: + ConfigRuleName: iam-user-group-membership-check + Scope: + ComplianceResourceTypes: + - AWS::IAM::User + Source: + Owner: AWS + SourceIdentifier: IAM_USER_GROUP_MEMBERSHIP_CHECK + Type: AWS::Config::ConfigRule + IamUserMfaEnabled: + Properties: + ConfigRuleName: iam-user-mfa-enabled + Source: + Owner: AWS + SourceIdentifier: IAM_USER_MFA_ENABLED + Type: AWS::Config::ConfigRule + IamUserUnusedCredentialsCheck: + Properties: + ConfigRuleName: iam-user-unused-credentials-check + InputParameters: + maxCredentialUsageAge: + Fn::If: + - iamUserUnusedCredentialsCheckParamMaxCredentialUsageAge + - Ref: IamUserUnusedCredentialsCheckParamMaxCredentialUsageAge + - Ref: AWS::NoValue + Source: + Owner: AWS + SourceIdentifier: IAM_USER_UNUSED_CREDENTIALS_CHECK + Type: AWS::Config::ConfigRule + IncomingSshDisabled: + Properties: + ConfigRuleName: restricted-ssh + Scope: + ComplianceResourceTypes: + - AWS::EC2::SecurityGroup + Source: + Owner: AWS + SourceIdentifier: INCOMING_SSH_DISABLED + Type: AWS::Config::ConfigRule + InstancesInVpc: + Properties: + ConfigRuleName: ec2-instances-in-vpc + Scope: + ComplianceResourceTypes: + - AWS::EC2::Instance + Source: + Owner: AWS + SourceIdentifier: INSTANCES_IN_VPC + Type: AWS::Config::ConfigRule + KinesisStreamEncrypted: + Properties: + ConfigRuleName: kinesis-stream-encrypted + Scope: + ComplianceResourceTypes: + - AWS::Kinesis::Stream + Source: + Owner: AWS + SourceIdentifier: KINESIS_STREAM_ENCRYPTED + Type: AWS::Config::ConfigRule + KmsCmkNotScheduledForDeletion: + Properties: + ConfigRuleName: kms-cmk-not-scheduled-for-deletion + Scope: + ComplianceResourceTypes: + - AWS::KMS::Key + Source: + Owner: AWS + SourceIdentifier: KMS_CMK_NOT_SCHEDULED_FOR_DELETION + Type: AWS::Config::ConfigRule + LambdaDlqCheck: + Properties: + ConfigRuleName: lambda-dlq-check + Scope: + ComplianceResourceTypes: + - AWS::Lambda::Function + Source: + Owner: AWS + SourceIdentifier: LAMBDA_DLQ_CHECK + Type: AWS::Config::ConfigRule + LambdaFunctionPublicAccessProhibited: + Properties: + ConfigRuleName: lambda-function-public-access-prohibited + Scope: + ComplianceResourceTypes: + - AWS::Lambda::Function + Source: + Owner: AWS + SourceIdentifier: LAMBDA_FUNCTION_PUBLIC_ACCESS_PROHIBITED + Type: AWS::Config::ConfigRule + LambdaInsideVpc: + Properties: + ConfigRuleName: lambda-inside-vpc + Scope: + ComplianceResourceTypes: + - AWS::Lambda::Function + Source: + Owner: AWS + SourceIdentifier: LAMBDA_INSIDE_VPC + Type: AWS::Config::ConfigRule + MfaEnabledForIamConsoleAccess: + Properties: + ConfigRuleName: mfa-enabled-for-iam-console-access + Source: + Owner: AWS + SourceIdentifier: MFA_ENABLED_FOR_IAM_CONSOLE_ACCESS + Type: AWS::Config::ConfigRule + MultiRegionCloudTrailEnabled: + Properties: + ConfigRuleName: multi-region-cloudtrail-enabled + Source: + Owner: AWS + SourceIdentifier: MULTI_REGION_CLOUD_TRAIL_ENABLED + Type: AWS::Config::ConfigRule + NoUnrestrictedRouteToIgw: + Properties: + ConfigRuleName: no-unrestricted-route-to-igw + Scope: + ComplianceResourceTypes: + - AWS::EC2::RouteTable + Source: + Owner: AWS + SourceIdentifier: NO_UNRESTRICTED_ROUTE_TO_IGW + Type: AWS::Config::ConfigRule + OpensearchEncryptedAtRest: + Properties: + ConfigRuleName: opensearch-encrypted-at-rest + Scope: + ComplianceResourceTypes: + - AWS::OpenSearch::Domain + Source: + Owner: AWS + SourceIdentifier: OPENSEARCH_ENCRYPTED_AT_REST + Type: AWS::Config::ConfigRule + OpensearchHttpsRequired: + Properties: + ConfigRuleName: opensearch-https-required + Scope: + ComplianceResourceTypes: + - AWS::OpenSearch::Domain + Source: + Owner: AWS + SourceIdentifier: OPENSEARCH_HTTPS_REQUIRED + Type: AWS::Config::ConfigRule + OpensearchInVpcOnly: + Properties: + ConfigRuleName: opensearch-in-vpc-only + Scope: + ComplianceResourceTypes: + - AWS::OpenSearch::Domain + Source: + Owner: AWS + SourceIdentifier: OPENSEARCH_IN_VPC_ONLY + Type: AWS::Config::ConfigRule + OpensearchLogsToCloudwatch: + Properties: + ConfigRuleName: opensearch-logs-to-cloudwatch + Scope: + ComplianceResourceTypes: + - AWS::OpenSearch::Domain + Source: + Owner: AWS + SourceIdentifier: OPENSEARCH_LOGS_TO_CLOUDWATCH + Type: AWS::Config::ConfigRule + OpensearchNodeToNodeEncryptionCheck: + Properties: + ConfigRuleName: opensearch-node-to-node-encryption-check + Scope: + ComplianceResourceTypes: + - AWS::OpenSearch::Domain + Source: + Owner: AWS + SourceIdentifier: OPENSEARCH_NODE_TO_NODE_ENCRYPTION_CHECK + Type: AWS::Config::ConfigRule + RdsEnhancedMonitoringEnabled: + Properties: + ConfigRuleName: rds-enhanced-monitoring-enabled + Scope: + ComplianceResourceTypes: + - AWS::RDS::DBInstance + Source: + Owner: AWS + SourceIdentifier: RDS_ENHANCED_MONITORING_ENABLED + Type: AWS::Config::ConfigRule + RdsInstanceDefaultAdminCheck: + Properties: + ConfigRuleName: rds-instance-default-admin-check + Scope: + ComplianceResourceTypes: + - AWS::RDS::DBInstance + Source: + Owner: AWS + SourceIdentifier: RDS_INSTANCE_DEFAULT_ADMIN_CHECK + Type: AWS::Config::ConfigRule + RdsInstanceDeletionProtectionEnabled: + Properties: + ConfigRuleName: rds-instance-deletion-protection-enabled + Scope: + ComplianceResourceTypes: + - AWS::RDS::DBInstance + Source: + Owner: AWS + SourceIdentifier: RDS_INSTANCE_DELETION_PROTECTION_ENABLED + Type: AWS::Config::ConfigRule + RdsInstancePublicAccessCheck: + Properties: + ConfigRuleName: rds-instance-public-access-check + Scope: + ComplianceResourceTypes: + - AWS::RDS::DBInstance + Source: + Owner: AWS + SourceIdentifier: RDS_INSTANCE_PUBLIC_ACCESS_CHECK + Type: AWS::Config::ConfigRule + RdsLoggingEnabled: + Properties: + ConfigRuleName: rds-logging-enabled + Scope: + ComplianceResourceTypes: + - AWS::RDS::DBInstance + Source: + Owner: AWS + SourceIdentifier: RDS_LOGGING_ENABLED + Type: AWS::Config::ConfigRule + RdsMultiAzSupport: + Properties: + ConfigRuleName: rds-multi-az-support + Scope: + ComplianceResourceTypes: + - AWS::RDS::DBInstance + Source: + Owner: AWS + SourceIdentifier: RDS_MULTI_AZ_SUPPORT + Type: AWS::Config::ConfigRule + RdsSnapshotEncrypted: + Properties: + ConfigRuleName: rds-snapshot-encrypted + Scope: + ComplianceResourceTypes: + - AWS::RDS::DBSnapshot + - AWS::RDS::DBClusterSnapshot + Source: + Owner: AWS + SourceIdentifier: RDS_SNAPSHOT_ENCRYPTED + Type: AWS::Config::ConfigRule + RdsSnapshotsPublicProhibited: + Properties: + ConfigRuleName: rds-snapshots-public-prohibited + Scope: + ComplianceResourceTypes: + - AWS::RDS::DBSnapshot + - AWS::RDS::DBClusterSnapshot + Source: + Owner: AWS + SourceIdentifier: RDS_SNAPSHOTS_PUBLIC_PROHIBITED + Type: AWS::Config::ConfigRule + RdsStorageEncrypted: + Properties: + ConfigRuleName: rds-storage-encrypted + Scope: + ComplianceResourceTypes: + - AWS::RDS::DBInstance + Source: + Owner: AWS + SourceIdentifier: RDS_STORAGE_ENCRYPTED + Type: AWS::Config::ConfigRule + RedshiftBackupEnabled: + Properties: + ConfigRuleName: redshift-backup-enabled + Scope: + ComplianceResourceTypes: + - AWS::Redshift::Cluster + Source: + Owner: AWS + SourceIdentifier: REDSHIFT_BACKUP_ENABLED + Type: AWS::Config::ConfigRule + RedshiftClusterConfigurationCheck: + Properties: + ConfigRuleName: redshift-cluster-configuration-check + InputParameters: + clusterDbEncrypted: + Fn::If: + - redshiftClusterConfigurationCheckParamClusterDbEncrypted + - Ref: RedshiftClusterConfigurationCheckParamClusterDbEncrypted + - Ref: AWS::NoValue + loggingEnabled: + Fn::If: + - redshiftClusterConfigurationCheckParamLoggingEnabled + - Ref: RedshiftClusterConfigurationCheckParamLoggingEnabled + - Ref: AWS::NoValue + Scope: + ComplianceResourceTypes: + - AWS::Redshift::Cluster + Source: + Owner: AWS + SourceIdentifier: REDSHIFT_CLUSTER_CONFIGURATION_CHECK + Type: AWS::Config::ConfigRule + RedshiftClusterKmsEnabled: + Properties: + ConfigRuleName: redshift-cluster-kms-enabled + Scope: + ComplianceResourceTypes: + - AWS::Redshift::Cluster + Source: + Owner: AWS + SourceIdentifier: REDSHIFT_CLUSTER_KMS_ENABLED + Type: AWS::Config::ConfigRule + RedshiftClusterMaintenancesettingsCheck: + Properties: + ConfigRuleName: redshift-cluster-maintenancesettings-check + InputParameters: + allowVersionUpgrade: + Fn::If: + - redshiftClusterMaintenancesettingsCheckParamAllowVersionUpgrade + - Ref: RedshiftClusterMaintenancesettingsCheckParamAllowVersionUpgrade + - Ref: AWS::NoValue + Scope: + ComplianceResourceTypes: + - AWS::Redshift::Cluster + Source: + Owner: AWS + SourceIdentifier: REDSHIFT_CLUSTER_MAINTENANCESETTINGS_CHECK + Type: AWS::Config::ConfigRule + RedshiftClusterPublicAccessCheck: + Properties: + ConfigRuleName: redshift-cluster-public-access-check + Scope: + ComplianceResourceTypes: + - AWS::Redshift::Cluster + Source: + Owner: AWS + SourceIdentifier: REDSHIFT_CLUSTER_PUBLIC_ACCESS_CHECK + Type: AWS::Config::ConfigRule + RedshiftDefaultAdminCheck: + Properties: + ConfigRuleName: redshift-default-admin-check + Scope: + ComplianceResourceTypes: + - AWS::Redshift::Cluster + Source: + Owner: AWS + SourceIdentifier: REDSHIFT_DEFAULT_ADMIN_CHECK + Type: AWS::Config::ConfigRule + RedshiftEnhancedVpcRoutingEnabled: + Properties: + ConfigRuleName: redshift-enhanced-vpc-routing-enabled + Scope: + ComplianceResourceTypes: + - AWS::Redshift::Cluster + Source: + Owner: AWS + SourceIdentifier: REDSHIFT_ENHANCED_VPC_ROUTING_ENABLED + Type: AWS::Config::ConfigRule + RedshiftRequireTlsSsl: + Properties: + ConfigRuleName: redshift-require-tls-ssl + Scope: + ComplianceResourceTypes: + - AWS::Redshift::Cluster + Source: + Owner: AWS + SourceIdentifier: REDSHIFT_REQUIRE_TLS_SSL + Type: AWS::Config::ConfigRule + RestrictedIncomingTraffic: + Properties: + ConfigRuleName: restricted-common-ports + InputParameters: + blockedPort1: + Fn::If: + - restrictedIncomingTrafficParamBlockedPort1 + - Ref: RestrictedIncomingTrafficParamBlockedPort1 + - Ref: AWS::NoValue + blockedPort2: + Fn::If: + - restrictedIncomingTrafficParamBlockedPort2 + - Ref: RestrictedIncomingTrafficParamBlockedPort2 + - Ref: AWS::NoValue + blockedPort3: + Fn::If: + - restrictedIncomingTrafficParamBlockedPort3 + - Ref: RestrictedIncomingTrafficParamBlockedPort3 + - Ref: AWS::NoValue + blockedPort4: + Fn::If: + - restrictedIncomingTrafficParamBlockedPort4 + - Ref: RestrictedIncomingTrafficParamBlockedPort4 + - Ref: AWS::NoValue + blockedPort5: + Fn::If: + - restrictedIncomingTrafficParamBlockedPort5 + - Ref: RestrictedIncomingTrafficParamBlockedPort5 + - Ref: AWS::NoValue + Scope: + ComplianceResourceTypes: + - AWS::EC2::SecurityGroup + Source: + Owner: AWS + SourceIdentifier: RESTRICTED_INCOMING_TRAFFIC + Type: AWS::Config::ConfigRule + RootAccountHardwareMfaEnabled: + Properties: + ConfigRuleName: root-account-hardware-mfa-enabled + Source: + Owner: AWS + SourceIdentifier: ROOT_ACCOUNT_HARDWARE_MFA_ENABLED + Type: AWS::Config::ConfigRule + RootAccountMfaEnabled: + Properties: + ConfigRuleName: root-account-mfa-enabled + Source: + Owner: AWS + SourceIdentifier: ROOT_ACCOUNT_MFA_ENABLED + Type: AWS::Config::ConfigRule + S3AccountLevelPublicAccessBlocksPeriodic: + Properties: + ConfigRuleName: s3-account-level-public-access-blocks-periodic + InputParameters: + BlockPublicAcls: + Fn::If: + - s3AccountLevelPublicAccessBlocksPeriodicParamBlockPublicAcls + - Ref: S3AccountLevelPublicAccessBlocksPeriodicParamBlockPublicAcls + - Ref: AWS::NoValue + BlockPublicPolicy: + Fn::If: + - s3AccountLevelPublicAccessBlocksPeriodicParamBlockPublicPolicy + - Ref: S3AccountLevelPublicAccessBlocksPeriodicParamBlockPublicPolicy + - Ref: AWS::NoValue + IgnorePublicAcls: + Fn::If: + - s3AccountLevelPublicAccessBlocksPeriodicParamIgnorePublicAcls + - Ref: S3AccountLevelPublicAccessBlocksPeriodicParamIgnorePublicAcls + - Ref: AWS::NoValue + RestrictPublicBuckets: + Fn::If: + - s3AccountLevelPublicAccessBlocksPeriodicParamRestrictPublicBuckets + - Ref: S3AccountLevelPublicAccessBlocksPeriodicParamRestrictPublicBuckets + - Ref: AWS::NoValue + Source: + Owner: AWS + SourceIdentifier: S3_ACCOUNT_LEVEL_PUBLIC_ACCESS_BLOCKS_PERIODIC + Type: AWS::Config::ConfigRule + S3BucketLevelPublicAccessProhibited: + Properties: + ConfigRuleName: s3-bucket-level-public-access-prohibited + Scope: + ComplianceResourceTypes: + - AWS::S3::Bucket + Source: + Owner: AWS + SourceIdentifier: S3_BUCKET_LEVEL_PUBLIC_ACCESS_PROHIBITED + Type: AWS::Config::ConfigRule + S3BucketLoggingEnabled: + Properties: + ConfigRuleName: s3-bucket-logging-enabled + Scope: + ComplianceResourceTypes: + - AWS::S3::Bucket + Source: + Owner: AWS + SourceIdentifier: S3_BUCKET_LOGGING_ENABLED + Type: AWS::Config::ConfigRule + S3BucketPublicReadProhibited: + Properties: + ConfigRuleName: s3-bucket-public-read-prohibited + Scope: + ComplianceResourceTypes: + - AWS::S3::Bucket + Source: + Owner: AWS + SourceIdentifier: S3_BUCKET_PUBLIC_READ_PROHIBITED + Type: AWS::Config::ConfigRule + S3BucketPublicWriteProhibited: + Properties: + ConfigRuleName: s3-bucket-public-write-prohibited + Scope: + ComplianceResourceTypes: + - AWS::S3::Bucket + Source: + Owner: AWS + SourceIdentifier: S3_BUCKET_PUBLIC_WRITE_PROHIBITED + Type: AWS::Config::ConfigRule + S3BucketReplicationEnabled: + Properties: + ConfigRuleName: s3-bucket-replication-enabled + Scope: + ComplianceResourceTypes: + - AWS::S3::Bucket + Source: + Owner: AWS + SourceIdentifier: S3_BUCKET_REPLICATION_ENABLED + Type: AWS::Config::ConfigRule + S3BucketServerSideEncryptionEnabled: + Properties: + ConfigRuleName: s3-bucket-server-side-encryption-enabled + Scope: + ComplianceResourceTypes: + - AWS::S3::Bucket + Source: + Owner: AWS + SourceIdentifier: S3_BUCKET_SERVER_SIDE_ENCRYPTION_ENABLED + Type: AWS::Config::ConfigRule + S3BucketSslRequestsOnly: + Properties: + ConfigRuleName: s3-bucket-ssl-requests-only + Scope: + ComplianceResourceTypes: + - AWS::S3::Bucket + Source: + Owner: AWS + SourceIdentifier: S3_BUCKET_SSL_REQUESTS_ONLY + Type: AWS::Config::ConfigRule + S3BucketVersioningEnabled: + Properties: + ConfigRuleName: s3-bucket-versioning-enabled + Scope: + ComplianceResourceTypes: + - AWS::S3::Bucket + Source: + Owner: AWS + SourceIdentifier: S3_BUCKET_VERSIONING_ENABLED + Type: AWS::Config::ConfigRule + S3DefaultEncryptionKms: + Properties: + ConfigRuleName: s3-default-encryption-kms + Scope: + ComplianceResourceTypes: + - AWS::S3::Bucket + Source: + Owner: AWS + SourceIdentifier: S3_DEFAULT_ENCRYPTION_KMS + Type: AWS::Config::ConfigRule + S3EventNotificationsEnabled: + Properties: + ConfigRuleName: s3-event-notifications-enabled + Scope: + ComplianceResourceTypes: + - AWS::S3::Bucket + Source: + Owner: AWS + SourceIdentifier: S3_EVENT_NOTIFICATIONS_ENABLED + Type: AWS::Config::ConfigRule + S3VersionLifecyclePolicyCheck: + Properties: + ConfigRuleName: s3-version-lifecycle-policy-check + Scope: + ComplianceResourceTypes: + - AWS::S3::Bucket + Source: + Owner: AWS + SourceIdentifier: S3_VERSION_LIFECYCLE_POLICY_CHECK + Type: AWS::Config::ConfigRule + SagemakerEndpointConfigurationKmsKeyConfigured: + Properties: + ConfigRuleName: sagemaker-endpoint-configuration-kms-key-configured + Source: + Owner: AWS + SourceIdentifier: SAGEMAKER_ENDPOINT_CONFIGURATION_KMS_KEY_CONFIGURED + Type: AWS::Config::ConfigRule + SagemakerNotebookInstanceKmsKeyConfigured: + Properties: + ConfigRuleName: sagemaker-notebook-instance-kms-key-configured + Source: + Owner: AWS + SourceIdentifier: SAGEMAKER_NOTEBOOK_INSTANCE_KMS_KEY_CONFIGURED + Type: AWS::Config::ConfigRule + SagemakerNotebookNoDirectInternetAccess: + Properties: + ConfigRuleName: sagemaker-notebook-no-direct-internet-access + Source: + Owner: AWS + SourceIdentifier: SAGEMAKER_NOTEBOOK_NO_DIRECT_INTERNET_ACCESS + Type: AWS::Config::ConfigRule + SecretsmanagerRotationEnabledCheck: + Properties: + ConfigRuleName: secretsmanager-rotation-enabled-check + Scope: + ComplianceResourceTypes: + - AWS::SecretsManager::Secret + Source: + Owner: AWS + SourceIdentifier: SECRETSMANAGER_ROTATION_ENABLED_CHECK + Type: AWS::Config::ConfigRule + SecretsmanagerUsingCmk: + Properties: + ConfigRuleName: secretsmanager-using-cmk + Scope: + ComplianceResourceTypes: + - AWS::SecretsManager::Secret + Source: + Owner: AWS + SourceIdentifier: SECRETSMANAGER_USING_CMK + Type: AWS::Config::ConfigRule + SecurityhubEnabled: + Properties: + ConfigRuleName: securityhub-enabled + Source: + Owner: AWS + SourceIdentifier: SECURITYHUB_ENABLED + Type: AWS::Config::ConfigRule + SnsEncryptedKms: + Properties: + ConfigRuleName: sns-encrypted-kms + Scope: + ComplianceResourceTypes: + - AWS::SNS::Topic + Source: + Owner: AWS + SourceIdentifier: SNS_ENCRYPTED_KMS + Type: AWS::Config::ConfigRule + SsmDocumentNotPublic: + Properties: + ConfigRuleName: ssm-document-not-public + Source: + Owner: AWS + SourceIdentifier: SSM_DOCUMENT_NOT_PUBLIC + Type: AWS::Config::ConfigRule + SubnetAutoAssignPublicIpDisabled: + Properties: + ConfigRuleName: subnet-auto-assign-public-ip-disabled + Scope: + ComplianceResourceTypes: + - AWS::EC2::Subnet + Source: + Owner: AWS + SourceIdentifier: SUBNET_AUTO_ASSIGN_PUBLIC_IP_DISABLED + Type: AWS::Config::ConfigRule + VpcDefaultSecurityGroupClosed: + Properties: + ConfigRuleName: vpc-default-security-group-closed + Scope: + ComplianceResourceTypes: + - AWS::EC2::SecurityGroup + Source: + Owner: AWS + SourceIdentifier: VPC_DEFAULT_SECURITY_GROUP_CLOSED + Type: AWS::Config::ConfigRule + VpcFlowLogsEnabled: + Properties: + ConfigRuleName: vpc-flow-logs-enabled + Source: + Owner: AWS + SourceIdentifier: VPC_FLOW_LOGS_ENABLED + Type: AWS::Config::ConfigRule + VpcSgOpenOnlyToAuthorizedPorts: + Properties: + ConfigRuleName: vpc-sg-open-only-to-authorized-ports + InputParameters: + authorizedTcpPorts: + Fn::If: + - vpcSgOpenOnlyToAuthorizedPortsParamAuthorizedTcpPorts + - Ref: VpcSgOpenOnlyToAuthorizedPortsParamAuthorizedTcpPorts + - Ref: AWS::NoValue + Scope: + ComplianceResourceTypes: + - AWS::EC2::SecurityGroup + Source: + Owner: AWS + SourceIdentifier: VPC_SG_OPEN_ONLY_TO_AUTHORIZED_PORTS + Type: AWS::Config::ConfigRule + VpcVpn2TunnelsUp: + Properties: + ConfigRuleName: vpc-vpn-2-tunnels-up + Scope: + ComplianceResourceTypes: + - AWS::EC2::VPNConnection + Source: + Owner: AWS + SourceIdentifier: VPC_VPN_2_TUNNELS_UP + Type: AWS::Config::ConfigRule + Wafv2LoggingEnabled: + Properties: + ConfigRuleName: wafv2-logging-enabled + Source: + Owner: AWS + SourceIdentifier: WAFV2_LOGGING_ENABLED + Type: AWS::Config::ConfigRule +Conditions: + accessKeysRotatedParamMaxAccessKeyAge: + Fn::Not: + - Fn::Equals: + - '' + - Ref: AccessKeysRotatedParamMaxAccessKeyAge + acmCertificateExpirationCheckParamDaysToExpiration: + Fn::Not: + - Fn::Equals: + - '' + - Ref: AcmCertificateExpirationCheckParamDaysToExpiration + cloudwatchAlarmActionCheckParamAlarmActionRequired: + Fn::Not: + - Fn::Equals: + - '' + - Ref: CloudwatchAlarmActionCheckParamAlarmActionRequired + cloudwatchAlarmActionCheckParamInsufficientDataActionRequired: + Fn::Not: + - Fn::Equals: + - '' + - Ref: CloudwatchAlarmActionCheckParamInsufficientDataActionRequired + cloudwatchAlarmActionCheckParamOkActionRequired: + Fn::Not: + - Fn::Equals: + - '' + - Ref: CloudwatchAlarmActionCheckParamOkActionRequired + iamCustomerPolicyBlockedKmsActionsParamBlockedActionsPatterns: + Fn::Not: + - Fn::Equals: + - '' + - Ref: IamCustomerPolicyBlockedKmsActionsParamBlockedActionsPatterns + iamInlinePolicyBlockedKmsActionsParamBlockedActionsPatterns: + Fn::Not: + - Fn::Equals: + - '' + - Ref: IamInlinePolicyBlockedKmsActionsParamBlockedActionsPatterns + iamPasswordPolicyParamMaxPasswordAge: + Fn::Not: + - Fn::Equals: + - '' + - Ref: IamPasswordPolicyParamMaxPasswordAge + iamPasswordPolicyParamMinimumPasswordLength: + Fn::Not: + - Fn::Equals: + - '' + - Ref: IamPasswordPolicyParamMinimumPasswordLength + iamPasswordPolicyParamPasswordReusePrevention: + Fn::Not: + - Fn::Equals: + - '' + - Ref: IamPasswordPolicyParamPasswordReusePrevention + iamPasswordPolicyParamRequireLowercaseCharacters: + Fn::Not: + - Fn::Equals: + - '' + - Ref: IamPasswordPolicyParamRequireLowercaseCharacters + iamPasswordPolicyParamRequireNumbers: + Fn::Not: + - Fn::Equals: + - '' + - Ref: IamPasswordPolicyParamRequireNumbers + iamPasswordPolicyParamRequireSymbols: + Fn::Not: + - Fn::Equals: + - '' + - Ref: IamPasswordPolicyParamRequireSymbols + iamPasswordPolicyParamRequireUppercaseCharacters: + Fn::Not: + - Fn::Equals: + - '' + - Ref: IamPasswordPolicyParamRequireUppercaseCharacters + iamUserUnusedCredentialsCheckParamMaxCredentialUsageAge: + Fn::Not: + - Fn::Equals: + - '' + - Ref: IamUserUnusedCredentialsCheckParamMaxCredentialUsageAge + redshiftClusterConfigurationCheckParamClusterDbEncrypted: + Fn::Not: + - Fn::Equals: + - '' + - Ref: RedshiftClusterConfigurationCheckParamClusterDbEncrypted + redshiftClusterConfigurationCheckParamLoggingEnabled: + Fn::Not: + - Fn::Equals: + - '' + - Ref: RedshiftClusterConfigurationCheckParamLoggingEnabled + redshiftClusterMaintenancesettingsCheckParamAllowVersionUpgrade: + Fn::Not: + - Fn::Equals: + - '' + - Ref: RedshiftClusterMaintenancesettingsCheckParamAllowVersionUpgrade + restrictedIncomingTrafficParamBlockedPort1: + Fn::Not: + - Fn::Equals: + - '' + - Ref: RestrictedIncomingTrafficParamBlockedPort1 + restrictedIncomingTrafficParamBlockedPort2: + Fn::Not: + - Fn::Equals: + - '' + - Ref: RestrictedIncomingTrafficParamBlockedPort2 + restrictedIncomingTrafficParamBlockedPort3: + Fn::Not: + - Fn::Equals: + - '' + - Ref: RestrictedIncomingTrafficParamBlockedPort3 + restrictedIncomingTrafficParamBlockedPort4: + Fn::Not: + - Fn::Equals: + - '' + - Ref: RestrictedIncomingTrafficParamBlockedPort4 + restrictedIncomingTrafficParamBlockedPort5: + Fn::Not: + - Fn::Equals: + - '' + - Ref: RestrictedIncomingTrafficParamBlockedPort5 + s3AccountLevelPublicAccessBlocksPeriodicParamBlockPublicAcls: + Fn::Not: + - Fn::Equals: + - '' + - Ref: S3AccountLevelPublicAccessBlocksPeriodicParamBlockPublicAcls + s3AccountLevelPublicAccessBlocksPeriodicParamBlockPublicPolicy: + Fn::Not: + - Fn::Equals: + - '' + - Ref: S3AccountLevelPublicAccessBlocksPeriodicParamBlockPublicPolicy + s3AccountLevelPublicAccessBlocksPeriodicParamIgnorePublicAcls: + Fn::Not: + - Fn::Equals: + - '' + - Ref: S3AccountLevelPublicAccessBlocksPeriodicParamIgnorePublicAcls + s3AccountLevelPublicAccessBlocksPeriodicParamRestrictPublicBuckets: + Fn::Not: + - Fn::Equals: + - '' + - Ref: S3AccountLevelPublicAccessBlocksPeriodicParamRestrictPublicBuckets + vpcSgOpenOnlyToAuthorizedPortsParamAuthorizedTcpPorts: + Fn::Not: + - Fn::Equals: + - '' + - Ref: VpcSgOpenOnlyToAuthorizedPortsParamAuthorizedTcpPorts \ No newline at end of file diff --git a/modules/aws_config/SAS-Custom-Conformance-Pack.yaml b/modules/aws_config/SAS-Custom-Conformance-Pack.yaml new file mode 100644 index 00000000..030d6e13 --- /dev/null +++ b/modules/aws_config/SAS-Custom-Conformance-Pack.yaml @@ -0,0 +1,63 @@ +################################################################################## +# +# Conformance Pack: +# Deloitte Custom Conformance Pack +# +################################################################################## +Resources: + Ec2SecurityGroupAttachedToEniPeriodic: + Properties: + ConfigRuleName: ec2-security-group-attached-to-eni-periodic + Scope: + ComplianceResourceTypes: + - AWS::EC2::SecurityGroup + Source: + Owner: AWS + SourceIdentifier: EC2_SECURITY_GROUP_ATTACHED_TO_ENI_PERIODIC + Type: AWS::Config::ConfigRule + IamGroupHasUsersCheck: + Properties: + ConfigRuleName: iam-group-has-users-check + Scope: + ComplianceResourceTypes: + - AWS::IAM::Group + Source: + Owner: AWS + SourceIdentifier: IAM_GROUP_HAS_USERS_CHECK + Type: AWS::Config::ConfigRule + VpcNetworkAclUnusedCheck: + Properties: + ConfigRuleName: vpc-network-acl-unused-check + Scope: + ComplianceResourceTypes: + - AWS::EC2::NetworkAcl + Source: + Owner: AWS + SourceIdentifier: VPC_NETWORK_ACL_UNUSED_CHECK + Type: AWS::Config::ConfigRule + WafRegionalRuleNotEmpty: + Properties: + ConfigRuleName: waf-regional-rule-not-empty + Scope: + ComplianceResourceTypes: + - AWS::WAFRegional::Rule + Source: + Owner: AWS + SourceIdentifier: WAF_REGIONAL_RULE_NOT_EMPTY + Type: AWS::Config::ConfigRule + CloudtrailS3DataeventsEnabled: + Properties: + ConfigRuleName: cloudtrail-s3-dataevents-enabled + Source: + Owner: AWS + SourceIdentifier: CLOUDTRAIL_S3_DATAEVENTS_ENABLED + Type: AWS::Config::ConfigRule + AuditLogPolicyExists: + Properties: + ConfigRuleName: audit-log-policy-exists + Description: Establish and maintain an audit log management policy that defines your organization's logging requirements. This includes, but is not limited to, review and retention of audit logs. + Source: + Owner: AWS + SourceIdentifier: AWS_CONFIG_PROCESS_CHECK + Type: AWS::Config::ConfigRule + \ No newline at end of file diff --git a/modules/aws_config/main.tf b/modules/aws_config/main.tf new file mode 100644 index 00000000..847ecef4 --- /dev/null +++ b/modules/aws_config/main.tf @@ -0,0 +1,16 @@ +# ########################### CONFIG ENABLEMENT ############################### +resource "aws_config_conformance_pack" "NIST_conformance_pack" { + name = var.conformance_pack_name + template_s3_uri = "s3://awsconfigconforms-awsng-conformance-pack-${var.hub_environment}/Operational-Best-Practices-for-NIST-800-53-rev-5.yaml" +} + +resource "aws_config_conformance_pack" "NIST_SASCustom_conformance_pack" { + name = var.custom_conformance_pack_name + template_s3_uri = "s3://awsconfigconforms-awsng-conformance-pack-${var.hub_environment}/SAS-Custom-Conformance-Pack.yaml" +} + + + + + + diff --git a/modules/aws_config/outputs.tf b/modules/aws_config/outputs.tf new file mode 100644 index 00000000..27d2cf61 --- /dev/null +++ b/modules/aws_config/outputs.tf @@ -0,0 +1,8 @@ +/*output "config_rules" { + value = aws_config_config_rule.config_rules +}*/ + +# output "nist_bucket_arn" { +# description = "ARN of the bucket" +# value = var.config_external == "true" ? "arn:aws:s3:::sas-awsng-${var.spoke_account_id}-${var.location}-nist-bkt" : aws_s3_bucket.NIST_conformance_pack_bkt.arn +# } \ No newline at end of file diff --git a/modules/aws_config/variables.tf b/modules/aws_config/variables.tf new file mode 100644 index 00000000..fb995dcc --- /dev/null +++ b/modules/aws_config/variables.tf @@ -0,0 +1,21 @@ + +variable "conformance_pack_name" { + type = string + description = "NIST Conformance pack name which is supposed to be applied" +} + +variable "custom_conformance_pack_name" { + type = string + description = "NIST Conformance pack name which is supposed to be applied" +} + +variable "hub_environment" { + type = string + description = "environment for conformance pack" +} + +variable "tags" { + description = "The tags to associate with resources when enable_nist_features is set to true." + type = map(string) + default = {} +} diff --git a/variables.tf b/variables.tf index 91752361..b16e6a9c 100644 --- a/variables.tf +++ b/variables.tf @@ -782,5 +782,16 @@ variable "central_logging_bucket" { default = "" } +variable "conformance_pack_name" { + type = string + description = "name for aws config" + default = "Operational-Best-Practices-for-NIST-800-53-rev-5" + # default = "" +} +variable "custom_conformance_pack_name" { + type = string + description = "name for aws config" + default = "SAS-Custom-Conformance-Pack" +} From 21983741b894fd56e720dabedd8fda29d15675bd Mon Sep 17 00:00:00 2001 From: Deshmukh Date: Thu, 21 Nov 2024 16:31:18 +0530 Subject: [PATCH 19/40] IAM analyzer module added as part of NIST features --- main.tf | 11 ++++++ modules/aws_iam_analyzer/main.tf | 57 +++++++++++++++++++++++++++ modules/aws_iam_analyzer/outputs.tf | 0 modules/aws_iam_analyzer/variables.tf | 38 ++++++++++++++++++ 4 files changed, 106 insertions(+) create mode 100644 modules/aws_iam_analyzer/main.tf create mode 100644 modules/aws_iam_analyzer/outputs.tf create mode 100644 modules/aws_iam_analyzer/variables.tf diff --git a/main.tf b/main.tf index 25a097b7..a28577c7 100755 --- a/main.tf +++ b/main.tf @@ -402,3 +402,14 @@ module "nist_pack" { hub_environment = var.hub_environment tags = local.tags } + +###################### IAM Analyser ############################ +module "iam_access_analyzer" { + count = var.enable_nist_features == true ? 1 : 0 + source = "./modules/aws_iam_analyzer" + location = var.location + analyzer_type_external = "ACCOUNT" + analyzer_type_unused = "ACCOUNT_UNUSED_ACCESS" + tags = local.tags + +} diff --git a/modules/aws_iam_analyzer/main.tf b/modules/aws_iam_analyzer/main.tf new file mode 100644 index 00000000..95ec3a63 --- /dev/null +++ b/modules/aws_iam_analyzer/main.tf @@ -0,0 +1,57 @@ +# AWS IAM Access Analyzer External +resource "aws_accessanalyzer_analyzer" "aws_access_analyzer_external" { + analyzer_name = "sas-awsng-accessanalyzer-ext-${var.location}" + type = var.analyzer_type_external + tags = var.tags +} + +# AWS IAM Access Analyzer Unused +resource "aws_accessanalyzer_analyzer" "aws_access_analyzer_unused" { + analyzer_name = "sas-awsng-accessanalyzer-unused-${var.location}" + type = var.analyzer_type_unused + configuration { + unused_access { + unused_access_age = 90 + } + } + tags = var.tags +} + +# IAM Role for Access Analyzer +resource "aws_iam_role" "access_analyzer_role" { + name = "sas-awsng-iam-analyzer-${var.location}-role" + assume_role_policy = jsonencode({ + Version = "2012-10-17", + Statement = [{ + Effect = "Allow", + Principal = { + Service = "access-analyzer.amazonaws.com" + }, + Action = "sts:AssumeRole" + }] + }) + tags = var.tags +} + +# IAM Policy for Access Analyzer +resource "aws_iam_policy" "access_analyzer_policy" { + name = "sas-awsng-iam-analyzer-${var.location}-policy" + description = "IAM policy for Access Analyzer" + + policy = jsonencode({ + Version = "2012-10-17", + Statement = [{ + Effect = "Allow", + Action = "access-analyzer:*", + Resource = "*" + }] + }) + + tags = var.tags +} + +# Attach IAM Policy to IAM Role +resource "aws_iam_role_policy_attachment" "access_analyzer_policy_attachment" { + role = aws_iam_role.access_analyzer_role.name + policy_arn = aws_iam_policy.access_analyzer_policy.arn +} \ No newline at end of file diff --git a/modules/aws_iam_analyzer/outputs.tf b/modules/aws_iam_analyzer/outputs.tf new file mode 100644 index 00000000..e69de29b diff --git a/modules/aws_iam_analyzer/variables.tf b/modules/aws_iam_analyzer/variables.tf new file mode 100644 index 00000000..9291a9cd --- /dev/null +++ b/modules/aws_iam_analyzer/variables.tf @@ -0,0 +1,38 @@ +variable "location" { + type = string + description = "Region of deployment" +} + +variable "analyzer_type_external" { + type = string + description = "Result of the shell script" +} + +variable "analyzer_type_unused" { + type = string + description = "Result of the shell script" +} +variable "tags" { + description = "The tags to associate with resources when enable_nist_features is set to true." + type = map(string) + default = {} +} + +# variable "analyzer_external" { +# type = string +# default = "true" +# description = "Type of the resource" +# } + +# variable "existing_analyzer_arn" { +# description = "ARN value of the analyser" +# type = string +# } + +# variable "analyzer_name" { +# description = "Name of the analyser" +# type = string +# default = "sas-awsng-accessanalyzer-ext-eu-west-3" +# } + + From 41205fb24f955eccfa7c877461240a96b044cca7 Mon Sep 17 00:00:00 2001 From: Deshmukh Date: Thu, 21 Nov 2024 17:20:18 +0530 Subject: [PATCH 20/40] WAF and Web ACL rules creation as part of NIST enhancement --- main.tf | 13 ++++ modules/aws_waf/main.tf | 119 +++++++++++++++++++++++++++++++++++ modules/aws_waf/variables.tf | 34 ++++++++++ modules/aws_waf/waf_logs.tf | 80 +++++++++++++++++++++++ 4 files changed, 246 insertions(+) create mode 100644 modules/aws_waf/main.tf create mode 100644 modules/aws_waf/variables.tf create mode 100644 modules/aws_waf/waf_logs.tf diff --git a/main.tf b/main.tf index a28577c7..c7417aa3 100755 --- a/main.tf +++ b/main.tf @@ -413,3 +413,16 @@ module "iam_access_analyzer" { tags = local.tags } + +######### WAF & WAF LOGGING ######### +module "spoke_waf" { + count = var.enable_nist_features == true ? 1 : 0 + depends_on = [ module.spoke_logging_bucket] + source = "./modules/aws_waf" + local_s3_bucket_arn = var.enable_nist_features == false ? null : "arn:aws:s3:::aws-waf-logs-infra-${var.spoke_account_id}-${var.location}-bkt" + spoke_account_id = var.spoke_account_id + location = var.location + tags = local.tags + +} + diff --git a/modules/aws_waf/main.tf b/modules/aws_waf/main.tf new file mode 100644 index 00000000..165633cf --- /dev/null +++ b/modules/aws_waf/main.tf @@ -0,0 +1,119 @@ +###WAF Resource####### +resource "aws_wafv2_web_acl" "waf" { + name = "sas-awsng-${var.spoke_account_id}-acl" + description = "Web ACL for WAF" + scope = "REGIONAL" + default_action { + allow {} + } + visibility_config { + cloudwatch_metrics_enabled = true + metric_name = "myWebACL" + sampled_requests_enabled = true + } + rule { + name = "sas-awsng-BotControlRule" + priority = 1 + statement { + managed_rule_group_statement { + name = "AWSManagedRulesBotControlRuleSet" + vendor_name = "AWS" + version = "Version_3.0" + } + } + override_action { + count {} + } + visibility_config { + cloudwatch_metrics_enabled = true + metric_name = "bot-control-metrics" + sampled_requests_enabled = true + } + } + rule { + name = "sas-awsng-GeoRestrictionRule" + priority = 2 + action { + block {} + } + statement { + geo_match_statement { + country_codes = ["BY", "CU", "IR", "KP", "RU", "SY"] + } + } + visibility_config { + cloudwatch_metrics_enabled = true + metric_name = "GeoRestrictionRule" + sampled_requests_enabled = true + } + } + rule { + name = "sas-awsng-CoreRule" + priority = 3 + statement { + managed_rule_group_statement { + name = "AWSManagedRulesCommonRuleSet" + vendor_name = "AWS" + } + } + override_action { + count {} + } + visibility_config { + cloudwatch_metrics_enabled = true + metric_name = "CoreRuleSetRule" + sampled_requests_enabled = true + } + } + + # # AWS Managed IP Reputation List + rule { + name = "sas-awsng-IpReputationList" + priority = 4 + statement { + managed_rule_group_statement { + name = "AWSManagedRulesAmazonIpReputationList" + vendor_name = "AWS" + } + } + override_action { + none {} + } + visibility_config { + cloudwatch_metrics_enabled = true + metric_name = "IPReputationRule" + sampled_requests_enabled = true + } + } + + # Known Bad Inputs + rule { + name = "sas-awsng-Bad-Inputs-Rule" + priority = 5 + statement { + managed_rule_group_statement { + name = "AWSManagedRulesKnownBadInputsRuleSet" + vendor_name = "AWS" + } + } + override_action { + count {} + } + visibility_config { + cloudwatch_metrics_enabled = true + metric_name = "KnownBadInputsRule" + sampled_requests_enabled = true + } + } + tags = merge( + { + "Name" = format("%s", "sas-awsng-${var.spoke_account_id}-acl") + }, + var.tags + ) +} + + + + + diff --git a/modules/aws_waf/variables.tf b/modules/aws_waf/variables.tf new file mode 100644 index 00000000..8459090b --- /dev/null +++ b/modules/aws_waf/variables.tf @@ -0,0 +1,34 @@ +################################################################################ +# VPC FLOW LOGS TO S3 # +################################################################################ + +variable "local_s3_bucket_arn" { + description = "Local Spoke S3 Bucket ARN" + type = string +} + +variable "location" { + type = string + description = "Region of deployment" +} + +variable "spoke_account_id" { + description = "spoke account id for s3 deployment" + type = string +} + +# variable "waf_external" { +# type = string +# default = "true" +# description = "Type of the resource" +# } + +# variable "existing_waf_arn" { +# description = "existing arn values" +# type = string +# } + +variable "tags" { + description = "Map of common tags to be placed on the Resources only if NIST is set to true" + type = map(any) +} diff --git a/modules/aws_waf/waf_logs.tf b/modules/aws_waf/waf_logs.tf new file mode 100644 index 00000000..50bee17c --- /dev/null +++ b/modules/aws_waf/waf_logs.tf @@ -0,0 +1,80 @@ +resource "aws_iam_policy" "waf_logging_policy" { + depends_on = [aws_wafv2_web_acl.waf] + name = "sas-awsng-${var.location}-waf-policy" + policy = jsonencode({ + "Version" : "2012-10-17", + "Statement" : [ + { + "Action" : [ + "wafv2:PutLoggingConfiguration", + "wafv2:DeleteLoggingConfiguration" + ], + "Resource" : [ + "*" + ], + "Effect" : "Allow", + "Sid" : "LoggingConfigurationAPI" + }, + { + "Sid" : "WebACLLogDelivery", + "Action" : [ + "logs:CreateLogDelivery", + "logs:DeleteLogDelivery" + ], + "Resource" : "*", + "Effect" : "Allow" + }, + { + "Sid" : "WebACLLoggingS3", + "Action" : [ + "s3:PutBucketPolicy", + "s3:GetBucketPolicy" + ], + "Resource" : [ + var.local_s3_bucket_arn + ], + "Effect" : "Allow" + } + ] + }) + tags = var.tags + # policy = data.aws_iam_policy_document.waf_logging_policy.json +} + +resource "aws_iam_role" "waf_logging_role" { + depends_on = [aws_wafv2_web_acl.waf] + name = "sas-awsng-${var.location}-waf-logging-role" + assume_role_policy = < Date: Thu, 21 Nov 2024 22:29:23 +0530 Subject: [PATCH 21/40] Backup module added to create backup framework, rules, Vault to backup resources based on tag value --- examples/sample-input-nist.tfvars | 40 +++- main.tf | 19 ++ modules/aws_backup/iam_role.tf | 36 ++++ modules/aws_backup/main.tf | 328 ++++++++++++++++++++++++++++++ modules/aws_backup/outputs.tf | 9 + modules/aws_backup/variables.tf | 106 ++++++++++ modules/aws_backup/vault_kms.tf | 59 ++++++ variables.tf | 73 +++++++ 8 files changed, 661 insertions(+), 9 deletions(-) create mode 100644 modules/aws_backup/iam_role.tf create mode 100644 modules/aws_backup/main.tf create mode 100644 modules/aws_backup/outputs.tf create mode 100644 modules/aws_backup/variables.tf create mode 100644 modules/aws_backup/vault_kms.tf diff --git a/examples/sample-input-nist.tfvars b/examples/sample-input-nist.tfvars index 5cca0bb7..144906b9 100644 --- a/examples/sample-input-nist.tfvars +++ b/examples/sample-input-nist.tfvars @@ -4,8 +4,8 @@ # **************** REQUIRED VARIABLES **************** # These required variables' values MUST be provided by the User -prefix = "test" -location = "us-east-1" # e.g., "us-east-1" +prefix = "prd" +location = "ap-northeast-1" # e.g., "us-east-1" # **************** REQUIRED VARIABLES **************** # !NOTE! - Without specifying your CIDR block access rules, ingress traffic @@ -14,10 +14,19 @@ location = "us-east-1" # e.g., "us-east-1" #***************** CIDR Range for Spoke VPC ************** vpc_cidr = "10.80.16.0/22" -core_network_id = "core-network-0febf425a0504df84" hub = "CustomerSpokeUS" -hub_environment = "dev" -core_network_arn = "arn:aws:networkmanager::654654181786:core-network/core-network-0febf425a0504df84" +hub_environment = "prod" + + + org_id = "o-03y3m4pkl8" + central_restore_operator = "arn:aws:iam::992382826079:role/sascloud-awsng-central-restore-iam-role-prod" + central_backup_operator = "arn:aws:iam::992382826079:role/sascloud-awsng-central-backup-iam-role-prod" + central_backup_vault_us = "arn:aws:backup:us-east-1:992382826079:backup-vault:sascloud-awsng-central-backup-vault-prod" + central_backup_vault_eu = "arn:aws:backup:eu-central-1:992382826079:backup-vault:sascloud-awsng-central-backup-vault-prod" + central_logging_bucket = "arn:aws:s3:::sascloud-awsng-centralized-prod-logging-bkt" + core_network_id = "core-network-0f5411afa03340169" + core_network_arn = "arn:aws:networkmanager::396608809900:core-network/core-network-0f5411afa03340169" + # ********* Set to true to enable NIST complaint code *********** enable_nist_features = true @@ -47,7 +56,11 @@ tags = {} # e.g., { "key1" = "value1", "key2" = "value2" } # need an external database server remove the 'postgres_servers' # block below. postgres_servers = { - default = {}, + default = { + "storage_encrypted": true, + "deletion_protection": true, + "multi_az": true +}, } ## Cluster config @@ -62,6 +75,18 @@ storage_type = "ha" storage_type_backend = "ontap" enable_efs_encryption = true +# Jump Server +create_jump_vm = true +##### NIST Enablement#### + +create_public_ip = false ### Set false if enable_nist_feature is set to true +create_jump_public_ip = false ### Set false if enable_nist_feature is set to true +enable_ebs_encryption = true + +#template_s3_uri = "s3://sascloud-awsng-conformance-pack/Operational-Best-Practices-for-NIST-800-53-rev-5.yaml" +conformance_pack_name = "Operational-Best-Practices-for-NIST-800-53-rev-5" +spoke_account_id = "296062556962" + ## Cluster Node Pools config node_pools = { cas = { @@ -134,6 +159,3 @@ node_pools = { "metadata_http_put_response_hop_limit" = 1 } } - -# Jump Server -create_jump_vm = true diff --git a/main.tf b/main.tf index c7417aa3..66396bdd 100755 --- a/main.tf +++ b/main.tf @@ -426,3 +426,22 @@ module "spoke_waf" { } +# ####Backup##### +module "spoke_backup" { + count = var.enable_nist_features == true ? 1 : 0 + source = "./modules/aws_backup" + location = var.location + spoke_account_id = var.spoke_account_id + backup_account_id = var.backup_account_id + org_id = var.org_id + tags = local.tags + spoke_backup_rules = var.spoke_backup_rules + central_backup_operator = var.central_backup_operator + central_restore_operator = var.central_restore_operator + central_backup_vault_us = var.central_backup_vault_us + central_backup_vault_eu = var.central_backup_vault_eu + hub_environment = var.hub_environment + +} + + diff --git a/modules/aws_backup/iam_role.tf b/modules/aws_backup/iam_role.tf new file mode 100644 index 00000000..88f07679 --- /dev/null +++ b/modules/aws_backup/iam_role.tf @@ -0,0 +1,36 @@ +data "aws_iam_policy_document" "assume_role" { + + statement { + effect = "Allow" + actions = ["sts:AssumeRole"] + + principals { + type = "Service" + identifiers = ["backup.amazonaws.com"] + } + } +} + +resource "aws_iam_role" "backup_operator_role" { + name = "sas-awsng-${var.location}-${var.hub_environment}-backup-operator-role" + assume_role_policy = data.aws_iam_policy_document.assume_role.json + tags = var.tags +} + +resource "aws_iam_role_policy_attachment" "aws_managed_backup_operator" { + role = aws_iam_role.backup_operator_role.name + policy_arn = "arn:aws:iam::aws:policy/service-role/AWSBackupServiceRolePolicyForBackup" +} + +resource "aws_iam_role" "restore_operator_role" { + name = "sas-awsng-${var.location}-${var.hub_environment}-restore-operator-role" + assume_role_policy = data.aws_iam_policy_document.assume_role.json + tags = var.tags +} + +resource "aws_iam_role_policy_attachment" "aws_managed_restore_operator" { + role = aws_iam_role.restore_operator_role.name + policy_arn = "arn:aws:iam::aws:policy/service-role/AWSBackupServiceRolePolicyForRestores" +} + + diff --git a/modules/aws_backup/main.tf b/modules/aws_backup/main.tf new file mode 100644 index 00000000..c499bfc7 --- /dev/null +++ b/modules/aws_backup/main.tf @@ -0,0 +1,328 @@ +resource "aws_backup_vault" "spoke" { + name = "sas-awsng-${var.spoke_account_id}-backup-vault" + kms_key_arn = aws_kms_key.spoke_vault_key.arn + tags = merge( + var.tags, + { + Name = "sas-awsng-${var.spoke_account_id}-backup-vault" + } + ) + +} + +resource "aws_backup_vault_lock_configuration" "spoke" { + backup_vault_name = aws_backup_vault.spoke.id + changeable_for_days = "7" + max_retention_days = "30" + min_retention_days = "7" + depends_on = [aws_backup_vault.spoke] +} + +resource "aws_backup_vault_policy" "spoke" { + backup_vault_name = aws_backup_vault.spoke.name + depends_on = [aws_backup_vault.spoke, aws_iam_role.restore_operator_role, aws_iam_role.backup_operator_role] + policy = < Date: Fri, 22 Nov 2024 14:01:24 +0530 Subject: [PATCH 22/40] Enabling VPC flow logs and creating log config for resolver rules for query logging --- main.tf | 2 ++ modules/aws_vpc/main.tf | 27 +++++++++++++++++++++++++++ modules/aws_vpc/variables.tf | 5 +++++ 3 files changed, 34 insertions(+) diff --git a/main.tf b/main.tf index 66396bdd..2dcc5f05 100755 --- a/main.tf +++ b/main.tf @@ -15,6 +15,7 @@ provider "aws" { secret_key = var.aws_secret_access_key token = var.aws_session_token + } data "aws_eks_cluster_auth" "cluster" { @@ -96,6 +97,7 @@ module "vpc" { hub_environment = var.hub_environment hub = var.hub vpc_nist_endpoints = var.vpc_nist_endpoints + local_s3_bucket_arn = var.enable_nist_features == false ? null : "arn:aws:s3:::aws-waf-logs-infra-${var.spoke_account_id}-${var.location}-bkt" } # EKS Setup - https://github.com/terraform-aws-modules/terraform-aws-eks diff --git a/modules/aws_vpc/main.tf b/modules/aws_vpc/main.tf index badd17fe..04b4b29a 100644 --- a/modules/aws_vpc/main.tf +++ b/modules/aws_vpc/main.tf @@ -462,4 +462,31 @@ resource "aws_route53_resolver_rule_association" "rule" { count = var.enable_nist_features == true ? 1 : 0 resolver_rule_id = data.aws_route53_resolver_rule.rule[0].id vpc_id = aws_vpc.vpc[0].id +} + +################# +# Enabling VPC flow logs +################# +resource "aws_flow_log" "flow_logs" { + count = var.enable_nist_features == true ? 1 : 0 + vpc_id = aws_vpc.vpc[0].id + log_destination = "${var.local_s3_bucket_arn}/vpc-flow" + log_destination_type = "s3" + traffic_type = "ALL" +} + +################# +# Enabling DNS query logging +################# +resource "aws_route53_resolver_query_log_config" "log_create" { + count = var.enable_nist_features == true ? 1 : 0 + name = "sas-awsng-${var.hub_environment}-query-logging-${var.region}" + destination_arn = "${var.local_s3_bucket_arn}/dns-query" +} + +#### To be enabled per VPC +resource "aws_route53_resolver_query_log_config_association" "log_association" { + count = var.enable_nist_features == true ? 1 : 0 + resolver_query_log_config_id = aws_route53_resolver_query_log_config.log_create[0].id + resource_id = local.vpc_id } \ No newline at end of file diff --git a/modules/aws_vpc/variables.tf b/modules/aws_vpc/variables.tf index 585117dd..b14380eb 100644 --- a/modules/aws_vpc/variables.tf +++ b/modules/aws_vpc/variables.tf @@ -212,3 +212,8 @@ variable "vpc_nist_endpoints" { "ec2messages" = "Interface" } } + +variable "local_s3_bucket_arn" { + description = "Local Spoke S3 Bucket ARN" + type = string +} \ No newline at end of file From 193c99e3de67e5ac4af85245f70b17e293da3c9e Mon Sep 17 00:00:00 2001 From: Deshmukh Date: Fri, 22 Nov 2024 15:46:34 +0530 Subject: [PATCH 23/40] udoating the aws_s3 module policy --- main.tf | 1 + modules/aws_s3/main.tf | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/main.tf b/main.tf index 2dcc5f05..5a2c66b1 100755 --- a/main.tf +++ b/main.tf @@ -98,6 +98,7 @@ module "vpc" { hub = var.hub vpc_nist_endpoints = var.vpc_nist_endpoints local_s3_bucket_arn = var.enable_nist_features == false ? null : "arn:aws:s3:::aws-waf-logs-infra-${var.spoke_account_id}-${var.location}-bkt" + depends_on = [module.spoke_logging_bucket] } # EKS Setup - https://github.com/terraform-aws-modules/terraform-aws-eks diff --git a/modules/aws_s3/main.tf b/modules/aws_s3/main.tf index 960fd0ac..7bed064e 100644 --- a/modules/aws_s3/main.tf +++ b/modules/aws_s3/main.tf @@ -3,6 +3,7 @@ data "aws_caller_identity" "current" {} + resource "aws_s3_bucket" "local_s3_bucket" { bucket = "aws-waf-logs-infra-${var.spoke_account_id}-${var.location}-bkt" force_destroy = var.force_destroy @@ -100,7 +101,7 @@ data "aws_iam_policy_document" "replication_json" { resources = [ "${aws_s3_bucket.local_s3_bucket.arn}/*", "aws_s3_bucket.local_s3_bucket.arn", - "var.central_logging_bucket/*", + "${var.central_logging_bucket}/*", "var.central_logging_bucket" ] } @@ -185,7 +186,7 @@ resource "aws_s3_bucket_policy" "allow_access_from_another_account" { "AWS": "arn:aws:iam::${local.account_id}:root" }, "Action": "s3:PutObject", - "Resource": "aws_s3_bucket.local_s3_bucket.arn/*" + "Resource": "${aws_s3_bucket.local_s3_bucket.arn}/*" } ] } From a2eb9640900f41439f19755c01bd8c884ea2357a Mon Sep 17 00:00:00 2001 From: Deshmukh Date: Fri, 22 Nov 2024 18:29:44 +0530 Subject: [PATCH 24/40] adding the backup tag to ec2,efs and fsx resources to enable backup --- examples/sample-input-nist.tfvars | 4 ++-- main.tf | 2 +- modules/aws_s3/main.tf | 4 ++-- modules/aws_vm/main.tf | 7 ++++--- vms.tf | 8 ++++---- 5 files changed, 13 insertions(+), 12 deletions(-) diff --git a/examples/sample-input-nist.tfvars b/examples/sample-input-nist.tfvars index 144906b9..22bf1e5e 100644 --- a/examples/sample-input-nist.tfvars +++ b/examples/sample-input-nist.tfvars @@ -4,7 +4,7 @@ # **************** REQUIRED VARIABLES **************** # These required variables' values MUST be provided by the User -prefix = "prd" +prefix = "dev" location = "ap-northeast-1" # e.g., "us-east-1" # **************** REQUIRED VARIABLES **************** @@ -85,7 +85,7 @@ enable_ebs_encryption = true #template_s3_uri = "s3://sascloud-awsng-conformance-pack/Operational-Best-Practices-for-NIST-800-53-rev-5.yaml" conformance_pack_name = "Operational-Best-Practices-for-NIST-800-53-rev-5" -spoke_account_id = "296062556962" +spoke_account_id = "637423594384" ## Cluster Node Pools config node_pools = { diff --git a/main.tf b/main.tf index 5a2c66b1..c5651ddb 100755 --- a/main.tf +++ b/main.tf @@ -312,7 +312,7 @@ module "postgresql" { tags = merge(local.tags, { "Backup" = var.enable_nist_features == true ? "Enabled" : null }) # DB subnet group - use public subnet if public access is requested - publicly_accessible = length(local.postgres_public_access_cidrs) > 0 ? false : true + publicly_accessible = length(local.postgres_public_access_cidrs) > 0 && var.enable_nist_features == true ? false : true subnet_ids = length(local.postgres_public_access_cidrs) > 0 ? length(module.vpc.public_subnets) > 0 ? module.vpc.database_subnets : module.vpc.database_subnets : module.vpc.database_subnets # DB parameter group diff --git a/modules/aws_s3/main.tf b/modules/aws_s3/main.tf index 7bed064e..9ffe0649 100644 --- a/modules/aws_s3/main.tf +++ b/modules/aws_s3/main.tf @@ -100,9 +100,9 @@ data "aws_iam_policy_document" "replication_json" { ] resources = [ "${aws_s3_bucket.local_s3_bucket.arn}/*", - "aws_s3_bucket.local_s3_bucket.arn", + "${aws_s3_bucket.local_s3_bucket.arn}", "${var.central_logging_bucket}/*", - "var.central_logging_bucket" + "${var.central_logging_bucket}" ] } statement { diff --git a/modules/aws_vm/main.tf b/modules/aws_vm/main.tf index bf6440ae..d0cf3085 100644 --- a/modules/aws_vm/main.tf +++ b/modules/aws_vm/main.tf @@ -92,13 +92,14 @@ resource "aws_instance" "vm" { kms_key_id = var.ebs_cmk_key tags = merge( { - Name : "${var.name}-root-vol" + Name : "${var.name}-root-vol", + "Backup" = var.enable_nist_features == true ? "Enabled" : null }, var.tags ) } - tags = merge(var.tags, tomap({ Name : "${var.name}-vm" })) + tags = merge(var.tags, tomap({ Name : "${var.name}-vm", "Backup" = var.enable_nist_features == true ? "Enabled" : null })) lifecycle { ignore_changes = [ @@ -130,7 +131,7 @@ resource "aws_ebs_volume" "raid_disk" { size = var.data_disk_size type = var.data_disk_type iops = var.data_disk_iops - tags = merge(var.tags, tomap({ Name : "${var.name}-vm" })) + tags = merge(var.tags, tomap({ Name : "${var.name}-vm", "Backup" = var.enable_nist_features == true ? "Enabled" : null })) encrypted = var.enable_ebs_encryption kms_key_id = var.ebs_cmk_key } diff --git a/vms.tf b/vms.tf index 87beeec9..3d418384 100644 --- a/vms.tf +++ b/vms.tf @@ -31,7 +31,7 @@ resource "aws_fsx_ontap_file_system" "ontap-fs" { throughput_capacity = var.aws_fsx_ontap_file_system_throughput_capacity preferred_subnet_id = module.vpc.private_subnets[0] security_group_ids = [local.workers_security_group_id] - tags = merge(local.tags, { "Name" : "${var.prefix}-ontap-fs" }) + tags = merge(local.tags, { "Name" : "${var.prefix}-ontap-fs", "Backup" = var.enable_nist_features == true ? "Enabled" : null }) kms_key_id = lookup(local.kms_keys, "fsx_key", null) depends_on = [module.ontap] } @@ -42,7 +42,7 @@ resource "aws_fsx_ontap_storage_virtual_machine" "ontap-svm" { count = local.storage_type_backend == "ontap" ? 1 : 0 file_system_id = aws_fsx_ontap_file_system.ontap-fs[0].id name = "${var.prefix}-ontap-svm" - tags = merge(local.tags, { "Name" : "${var.prefix}-ontap-svm" }) + tags = merge(local.tags, { "Name" : "${var.prefix}-ontap-svm", "Backup" = var.enable_nist_features == true ? "Enabled" : null }) } # A default volume gets created with the svm, we may want another @@ -54,7 +54,7 @@ resource "aws_fsx_ontap_volume" "ontap-vol" { size_in_megabytes = aws_fsx_ontap_file_system.ontap-fs[0].storage_capacity * 1024 # any whole number in the range of 20–314572800 to specify the size in mebibytes (MiB) storage_efficiency_enabled = true storage_virtual_machine_id = aws_fsx_ontap_storage_virtual_machine.ontap-svm[0].id - tags = merge(local.tags, { "Name" : "${var.prefix}-ontap-vol" }) + tags = merge(local.tags, { "Name" : "${var.prefix}-ontap-vol", "Backup" = var.enable_nist_features == true ? "Enabled" : null }) } # EFS File System - https://www.terraform.io/docs/providers/aws/r/efs_file_system.html @@ -64,7 +64,7 @@ resource "aws_efs_file_system" "efs-fs" { performance_mode = var.efs_performance_mode throughput_mode = var.efs_throughput_mode provisioned_throughput_in_mibps = var.efs_throughput_mode == "provisioned" ? var.efs_throughput_rate : null - tags = merge(local.tags, { "Name" : "${var.prefix}-efs" }) + tags = merge(local.tags, { "Name" : "${var.prefix}-efs", "Backup" = var.enable_nist_features == true ? "Enabled" : null }) encrypted = var.enable_efs_encryption kms_key_id = lookup(local.kms_keys, "efs_key", null) } From 8868d415acd9df0da85ee08168036a37d3c952f4 Mon Sep 17 00:00:00 2001 From: Deshmukh Date: Fri, 22 Nov 2024 21:53:20 +0530 Subject: [PATCH 25/40] updated condition postgres public accessibility --- main.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/main.tf b/main.tf index c5651ddb..ffe931a7 100755 --- a/main.tf +++ b/main.tf @@ -312,7 +312,7 @@ module "postgresql" { tags = merge(local.tags, { "Backup" = var.enable_nist_features == true ? "Enabled" : null }) # DB subnet group - use public subnet if public access is requested - publicly_accessible = length(local.postgres_public_access_cidrs) > 0 && var.enable_nist_features == true ? false : true + publicly_accessible = var.enable_nist_features == true ? false : true subnet_ids = length(local.postgres_public_access_cidrs) > 0 ? length(module.vpc.public_subnets) > 0 ? module.vpc.database_subnets : module.vpc.database_subnets : module.vpc.database_subnets # DB parameter group From 1c5cb6fb374e55b52cf45141d715f23ec0ac4953 Mon Sep 17 00:00:00 2001 From: Deshmukh Date: Fri, 22 Nov 2024 22:15:08 +0530 Subject: [PATCH 26/40] Creating resource_checker shell scripts to avoid creation of duplicate resources --- locals.tf | 10 ++++ main.tf | 29 +++++++++--- modules/resource_checker/analyzer_checker.sh | 38 +++++++++++++++ modules/resource_checker/bucket_checker.sh | 38 +++++++++++++++ modules/resource_checker/check_backupvault.sh | 39 ++++++++++++++++ modules/resource_checker/check_waf.sh | 39 ++++++++++++++++ modules/resource_checker/main.tf | 46 +++++++++++++++++++ modules/resource_checker/outputs.tf | 21 +++++++++ modules/resource_checker/variables.tf | 33 +++++++++++++ 9 files changed, 286 insertions(+), 7 deletions(-) create mode 100644 modules/resource_checker/analyzer_checker.sh create mode 100644 modules/resource_checker/bucket_checker.sh create mode 100644 modules/resource_checker/check_backupvault.sh create mode 100644 modules/resource_checker/check_waf.sh create mode 100644 modules/resource_checker/main.tf create mode 100644 modules/resource_checker/outputs.tf create mode 100644 modules/resource_checker/variables.tf diff --git a/locals.tf b/locals.tf index 876ee262..6efec262 100755 --- a/locals.tf +++ b/locals.tf @@ -210,4 +210,14 @@ locals { rds_performance_insight = var.enable_nist_features == true ? true : false rds_performance_retention_period = var.enable_nist_features == true ? 7 : 0 + ###nist-resource-chcker + bucket_exists = try(module.resource_checker[0].bucket_external["exists"], "false") + waf_exists = try(module.resource_checker[0].waf_external["exists"], "false") + waf_arn = try(module.resource_checker[0].waf_external["arn"], "") + backup_exists = try(module.resource_checker[0].backup_external["exists"], "false") + backup_arn = try(module.resource_checker[0].backup_external["arn"], "") + analyzer_exists = try(module.resource_checker[0].analyzer_external["exists"], "false") + analyzer_arn = try(module.resource_checker[0].analyzer_external["arn"], "") + + } diff --git a/main.tf b/main.tf index ffe931a7..13d8d656 100755 --- a/main.tf +++ b/main.tf @@ -97,7 +97,7 @@ module "vpc" { hub_environment = var.hub_environment hub = var.hub vpc_nist_endpoints = var.vpc_nist_endpoints - local_s3_bucket_arn = var.enable_nist_features == false ? null : "arn:aws:s3:::aws-waf-logs-infra-${var.spoke_account_id}-${var.location}-bkt" + local_s3_bucket_arn = var.enable_nist_features == false ? null : local.bucket_exists == "false" ? module.spoke_logging_bucket[0].local_s3_bucket_arn : "arn:aws:s3:::aws-waf-logs-infra-${var.spoke_account_id}-${var.location}-bkt" depends_on = [module.spoke_logging_bucket] } @@ -387,13 +387,14 @@ module "cloudwatch" { ##########Spoke bucket for centralized logging######## module "spoke_logging_bucket" { - count = var.enable_nist_features == true ? 1 : 0 + count = var.enable_nist_features == true && local.bucket_exists == "false" ? 1 : 0 source = "./modules/aws_s3" central_logging_bucket = var.central_logging_bucket location = var.location spoke_account_id = var.spoke_account_id tags = local.tags hub_environment = var.hub_environment + depends_on = [module.resource_checker] } ###################################Config Conformance Pack############################ @@ -408,21 +409,22 @@ module "nist_pack" { ###################### IAM Analyser ############################ module "iam_access_analyzer" { - count = var.enable_nist_features == true ? 1 : 0 + count = var.enable_nist_features == true && local.analyzer_exists == "false" ? 1 : 0 source = "./modules/aws_iam_analyzer" location = var.location analyzer_type_external = "ACCOUNT" analyzer_type_unused = "ACCOUNT_UNUSED_ACCESS" tags = local.tags + depends_on = [module.resource_checker] } ######### WAF & WAF LOGGING ######### module "spoke_waf" { - count = var.enable_nist_features == true ? 1 : 0 - depends_on = [ module.spoke_logging_bucket] + count = var.enable_nist_features == true && local.waf_exists == "false" ? 1 : 0 + depends_on = [ module.spoke_logging_bucket , module.resource_checker] source = "./modules/aws_waf" - local_s3_bucket_arn = var.enable_nist_features == false ? null : "arn:aws:s3:::aws-waf-logs-infra-${var.spoke_account_id}-${var.location}-bkt" + local_s3_bucket_arn = var.enable_nist_features == false ? null : local.bucket_exists == "false" ? module.spoke_logging_bucket[0].local_s3_bucket_arn : "arn:aws:s3:::aws-waf-logs-infra-${var.spoke_account_id}-${var.location}-bkt" spoke_account_id = var.spoke_account_id location = var.location tags = local.tags @@ -431,7 +433,7 @@ module "spoke_waf" { # ####Backup##### module "spoke_backup" { - count = var.enable_nist_features == true ? 1 : 0 + count = var.enable_nist_features == true && local.backup_exists == "false" ? 1 : 0 source = "./modules/aws_backup" location = var.location spoke_account_id = var.spoke_account_id @@ -444,7 +446,20 @@ module "spoke_backup" { central_backup_vault_us = var.central_backup_vault_us central_backup_vault_eu = var.central_backup_vault_eu hub_environment = var.hub_environment + depends_on = [module.resource_checker] } +########## Resource Checker ######### + +module "resource_checker" { + count = var.enable_nist_features == true ? 1 : 0 + source = "./modules/resource_checker" + location = var.location + spoke_account_id = var.spoke_account_id + aws_access_key_id = var.aws_access_key_id + aws_secret_access_key = var.aws_secret_access_key + aws_session_token = var.aws_session_token + analyzer_name = var.analyzer_name +} diff --git a/modules/resource_checker/analyzer_checker.sh b/modules/resource_checker/analyzer_checker.sh new file mode 100644 index 00000000..3daf9539 --- /dev/null +++ b/modules/resource_checker/analyzer_checker.sh @@ -0,0 +1,38 @@ +#!/usr/bin/env bash +set -e +location=$1 +ANALYZER_NAME="sas-awsng-accessanalyzer-ext-$location" +export AWS_ACCESS_KEY_ID=$2 +export AWS_SECRET_ACCESS_KEY=$3 +export AWS_SESSION_TOKEN=$4 + +RETRY_COUNT=3 # Number of retries +RETRY_DELAY=3 # Delay in seconds between retries +# Function to check the existence of WAF +check_analyzer() { + local attempt=1 + while [ $attempt -le $RETRY_COUNT ]; do + result=$(aws accessanalyzer list-analyzers --region $location --query "analyzers[?name=='$ANALYZER_NAME']" --output json ) + if [ $? -eq 0 ]; then + arn=$(echo "$result" | jq -r '.[0].arn // empty') + if [ -n "$arn" ]; then + echo "{\"exists\": \"true\", \"arn\": \"$arn\"}" + exit 0 + # else + # echo "{\"exists\": \"false\", \"arn\": \"\"}" + # exit 0 + fi + else + # echo "Attempt $attempt failed. Retrying in $RETRY_DELAY seconds..." + sleep $RETRY_DELAY + fi + attempt=$((attempt + 1)) + done + # Final failure + echo "{\"exists\": \"false\", \"arn\": \"\"}" + exit 0 +} +# Run the WAF check +check_analyzer + + diff --git a/modules/resource_checker/bucket_checker.sh b/modules/resource_checker/bucket_checker.sh new file mode 100644 index 00000000..d6e54225 --- /dev/null +++ b/modules/resource_checker/bucket_checker.sh @@ -0,0 +1,38 @@ +#!/usr/bin/env bash +set -e +spoke_account_id=$1 +location=$2 +export AWS_ACCESS_KEY_ID=$3 +export AWS_SECRET_ACCESS_KEY=$4 +export AWS_SESSION_TOKEN=$5 +BUCKET_NAME="aws-waf-logs-infra-${spoke_account_id}-${location}-bkt" +RETRY_COUNT=3 # Number of retries +RETRY_DELAY=3 # Delay in seconds between retries +# Function to check the existence of the S3 bucket +check_bucket() { + local attempt=1 + while [ $attempt -le $RETRY_COUNT ]; do + result=$(aws s3api list-buckets --region "$location" --query "Buckets[?Name=='$BUCKET_NAME']" --output json) + + if [ $? -eq 0 ]; then + # Check if the bucket exists by examining the output + if [ "$(echo "$result" | jq 'length')" -gt 0 ]; then + echo "{\"exists\": \"true\"}" + exit 0 + else + echo "{\"exists\": \"false\"}" + exit 0 + fi + else + # If the command fails, wait and retry + sleep $RETRY_DELAY + fi + attempt=$((attempt + 1)) + done + # Final failure case + echo "{\"exists\": \"false\"}" + exit 1 +} + +# Run the S3 bucket check +check_bucket \ No newline at end of file diff --git a/modules/resource_checker/check_backupvault.sh b/modules/resource_checker/check_backupvault.sh new file mode 100644 index 00000000..66974c71 --- /dev/null +++ b/modules/resource_checker/check_backupvault.sh @@ -0,0 +1,39 @@ +#!/usr/bin/env bash +set -e +spoke_account_id=$1 +location=$2 +export AWS_ACCESS_KEY_ID=$3 +export AWS_SECRET_ACCESS_KEY=$4 +export AWS_SESSION_TOKEN=$5 + +VAULT_NAME=$6; +RETRY_COUNT=3 # Number of retries +RETRY_DELAY=3 # Delay in seconds between retries +# Function to check the existence of WAF +check_backup() { + local attempt=1 + while [ $attempt -le $RETRY_COUNT ]; do + result=$(aws backup list-backup-vaults --region $location --query "BackupVaultList[?BackupVaultName=='$VAULT_NAME']" --output json) + if [ $? -eq 0 ]; then + arn=$(echo "$result" | jq -r '.[0].BackupVaultArn // empty') + if [ -n "$arn" ]; then + echo "{\"exists\": \"true\", \"arn\": \"$arn\"}" + exit 0 + # else + # echo "{\"exists\": \"false\", \"arn\": \"\"}" + # exit 0 + fi + else + # echo "Attempt $attempt failed. Retrying in $RETRY_DELAY seconds..." + sleep $RETRY_DELAY + fi + attempt=$((attempt + 1)) + done + # Final failure + echo "{\"exists\": \"false\", \"arn\": \"\"}" + exit 0 +} +# Run the WAF check +check_backup + + diff --git a/modules/resource_checker/check_waf.sh b/modules/resource_checker/check_waf.sh new file mode 100644 index 00000000..dd3e3d50 --- /dev/null +++ b/modules/resource_checker/check_waf.sh @@ -0,0 +1,39 @@ +#!/usr/bin/env bash +set -e +spoke_account_id=$1 +location=$2 +export AWS_ACCESS_KEY_ID=$3 +export AWS_SECRET_ACCESS_KEY=$4 +export AWS_SESSION_TOKEN=$5 + +WAF_NAME="sas-awsng-${spoke_account_id}-acl" +RETRY_COUNT=3 # Number of retries +RETRY_DELAY=3 # Delay in seconds between retries +# Function to check the existence of WAF +check_waf() { + local attempt=1 + while [ $attempt -le $RETRY_COUNT ]; do + result=$(aws wafv2 list-web-acls --scope REGIONAL --region "$location" --query "WebACLs[?Name=='$WAF_NAME']" --output json) + if [ $? -eq 0 ]; then + arn=$(echo "$result" | jq -r '.[0].ARN // empty') + if [ -n "$arn" ]; then + echo "{\"exists\": \"true\", \"arn\": \"$arn\"}" + exit 0 + else + echo "{\"exists\": \"false\", \"arn\": \"\"}" + exit 0 + fi + else + # echo "Attempt $attempt failed. Retrying in $RETRY_DELAY seconds..." + sleep $RETRY_DELAY + fi + attempt=$((attempt + 1)) + done + # Final failure + echo "{\"exists\": \"false\", \"arn\": \"\"}" + exit 0 +} +# Run the WAF check +check_waf + + diff --git a/modules/resource_checker/main.tf b/modules/resource_checker/main.tf new file mode 100644 index 00000000..0cb07cb6 --- /dev/null +++ b/modules/resource_checker/main.tf @@ -0,0 +1,46 @@ +data "external" "waf_checker_tool" { + program = ["bash", "${path.module}/check_waf.sh", var.spoke_account_id, var.location, var.aws_access_key_id, var.aws_secret_access_key, var.aws_session_token] + query = { + "spoke_account_id" = var.spoke_account_id + "location" = var.location + "access_key" = var.aws_access_key_id + "secret_key" = var.aws_secret_access_key + "token" = var.aws_session_token + } +} + +data "external" "bucket_checker_tool" { + program = ["bash", "${path.module}/bucket_checker.sh", var.spoke_account_id, var.location, var.aws_access_key_id, var.aws_secret_access_key, var.aws_session_token] + query = { + "spoke_account_id" = var.spoke_account_id + "location" = var.location + "access_key" = var.aws_access_key_id + "secret_key" = var.aws_secret_access_key + "token" = var.aws_session_token + } +} + +data "external" "analyzer_checker_tool" { + program = ["bash", "${path.module}/analyzer_checker.sh", var.location, var.aws_access_key_id, var.aws_secret_access_key, var.aws_session_token] + query = { + "location" = var.location + "analyzer_name" = var.analyzer_name + "access_key" = var.aws_access_key_id + "secret_key" = var.aws_secret_access_key + "token" = var.aws_session_token + } +} + +data "external" "vault_checker_tool" { + program = ["bash", "${path.module}/check_backupvault.sh", var.spoke_account_id, var.location, var.aws_access_key_id, var.aws_secret_access_key, var.aws_session_token, "sas-awsng-${var.spoke_account_id}-backup-vault"] + query = { + "spoke_account_id" = var.spoke_account_id + "location" = var.location + "access_key" = var.aws_access_key_id + "secret_key" = var.aws_secret_access_key + "token" = var.aws_session_token + "VAULT_NAME" = "sas-awsng-${var.spoke_account_id}-backup-vault" + } +} + + diff --git a/modules/resource_checker/outputs.tf b/modules/resource_checker/outputs.tf new file mode 100644 index 00000000..f4e25f99 --- /dev/null +++ b/modules/resource_checker/outputs.tf @@ -0,0 +1,21 @@ +output "waf_external" { + description = "Result of the shell script" + value = data.external.waf_checker_tool.result +} + +output "bucket_external" { + description = "Result of the shell script" + value = data.external.bucket_checker_tool.result +} + + +output "analyzer_external" { + description = "Result of the shell script" + value = data.external.analyzer_checker_tool.result +} + +output "backup_external" { + description = "Result of the shell script" + value = data.external.vault_checker_tool.result +} + diff --git a/modules/resource_checker/variables.tf b/modules/resource_checker/variables.tf new file mode 100644 index 00000000..984f0986 --- /dev/null +++ b/modules/resource_checker/variables.tf @@ -0,0 +1,33 @@ +variable "spoke_account_id" { + type = string + description = "Account number" +} + +variable "location" { + type = string + description = "Region of deployment" +} + +variable "analyzer_name" { + description = "analyzer name" + type = string +} + +variable "aws_session_token" { + description = "Session token for temporary credentials." + type = string + default = "" +} + +variable "aws_access_key_id" { + description = "Static credential key." + type = string + default = "" +} + +variable "aws_secret_access_key" { + description = "Static credential secret." + type = string + default = "" +} + From 84835431065a0ca47a4aae3f4421ba6b225cea73 Mon Sep 17 00:00:00 2001 From: Deshmukh Date: Wed, 4 Dec 2024 17:41:49 +0530 Subject: [PATCH 27/40] reverted the postgres public accessible attribute logic --- main.tf | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/main.tf b/main.tf index 13d8d656..feac989b 100755 --- a/main.tf +++ b/main.tf @@ -99,6 +99,7 @@ module "vpc" { vpc_nist_endpoints = var.vpc_nist_endpoints local_s3_bucket_arn = var.enable_nist_features == false ? null : local.bucket_exists == "false" ? module.spoke_logging_bucket[0].local_s3_bucket_arn : "arn:aws:s3:::aws-waf-logs-infra-${var.spoke_account_id}-${var.location}-bkt" depends_on = [module.spoke_logging_bucket] + } # EKS Setup - https://github.com/terraform-aws-modules/terraform-aws-eks @@ -312,7 +313,7 @@ module "postgresql" { tags = merge(local.tags, { "Backup" = var.enable_nist_features == true ? "Enabled" : null }) # DB subnet group - use public subnet if public access is requested - publicly_accessible = var.enable_nist_features == true ? false : true + publicly_accessible = length(local.postgres_public_access_cidrs) > 0 && var.enable_nist_features == false ? true : false subnet_ids = length(local.postgres_public_access_cidrs) > 0 ? length(module.vpc.public_subnets) > 0 ? module.vpc.database_subnets : module.vpc.database_subnets : module.vpc.database_subnets # DB parameter group From 681aef191fc332f8622803e6dfaa189146668b3e Mon Sep 17 00:00:00 2001 From: Deshmukh Date: Wed, 4 Dec 2024 17:48:37 +0530 Subject: [PATCH 28/40] added varaible for the logging_account in aws_s3 module --- locals.tf | 2 +- main.tf | 19 ++++++++++--------- modules/aws_s3/main.tf | 2 +- modules/aws_s3/variables.tf | 5 +++++ outputs.tf | 2 +- variables.tf | 6 +++++- vms.tf | 6 +++--- 7 files changed, 26 insertions(+), 16 deletions(-) diff --git a/locals.tf b/locals.tf index 6efec262..1f79c882 100755 --- a/locals.tf +++ b/locals.tf @@ -210,7 +210,7 @@ locals { rds_performance_insight = var.enable_nist_features == true ? true : false rds_performance_retention_period = var.enable_nist_features == true ? 7 : 0 - ###nist-resource-chcker + ###nist-resource-chcker bucket_exists = try(module.resource_checker[0].bucket_external["exists"], "false") waf_exists = try(module.resource_checker[0].waf_external["exists"], "false") waf_arn = try(module.resource_checker[0].waf_external["arn"], "") diff --git a/main.tf b/main.tf index feac989b..2b910c64 100755 --- a/main.tf +++ b/main.tf @@ -97,8 +97,8 @@ module "vpc" { hub_environment = var.hub_environment hub = var.hub vpc_nist_endpoints = var.vpc_nist_endpoints - local_s3_bucket_arn = var.enable_nist_features == false ? null : local.bucket_exists == "false" ? module.spoke_logging_bucket[0].local_s3_bucket_arn : "arn:aws:s3:::aws-waf-logs-infra-${var.spoke_account_id}-${var.location}-bkt" - depends_on = [module.spoke_logging_bucket] + local_s3_bucket_arn = var.enable_nist_features == false ? null : local.bucket_exists == "false" ? module.spoke_logging_bucket[0].local_s3_bucket_arn : "arn:aws:s3:::aws-waf-logs-infra-${var.spoke_account_id}-${var.location}-bkt" + depends_on = [module.spoke_logging_bucket] } @@ -313,7 +313,7 @@ module "postgresql" { tags = merge(local.tags, { "Backup" = var.enable_nist_features == true ? "Enabled" : null }) # DB subnet group - use public subnet if public access is requested - publicly_accessible = length(local.postgres_public_access_cidrs) > 0 && var.enable_nist_features == false ? true : false + publicly_accessible = length(local.postgres_public_access_cidrs) > 0 && var.enable_nist_features == false ? true : false subnet_ids = length(local.postgres_public_access_cidrs) > 0 ? length(module.vpc.public_subnets) > 0 ? module.vpc.database_subnets : module.vpc.database_subnets : module.vpc.database_subnets # DB parameter group @@ -395,12 +395,13 @@ module "spoke_logging_bucket" { spoke_account_id = var.spoke_account_id tags = local.tags hub_environment = var.hub_environment - depends_on = [module.resource_checker] + logging_account = var.logging_account + depends_on = [module.resource_checker] } ###################################Config Conformance Pack############################ module "nist_pack" { - count = var.enable_nist_features == true ? 1 : 0 + count = var.enable_nist_features == true ? 1 : 0 source = "./modules/aws_config" conformance_pack_name = var.conformance_pack_name custom_conformance_pack_name = var.custom_conformance_pack_name @@ -416,15 +417,15 @@ module "iam_access_analyzer" { analyzer_type_external = "ACCOUNT" analyzer_type_unused = "ACCOUNT_UNUSED_ACCESS" tags = local.tags - depends_on = [module.resource_checker] + depends_on = [module.resource_checker] } ######### WAF & WAF LOGGING ######### module "spoke_waf" { - count = var.enable_nist_features == true && local.waf_exists == "false" ? 1 : 0 - depends_on = [ module.spoke_logging_bucket , module.resource_checker] - source = "./modules/aws_waf" + count = var.enable_nist_features == true && local.waf_exists == "false" ? 1 : 0 + depends_on = [module.spoke_logging_bucket, module.resource_checker] + source = "./modules/aws_waf" local_s3_bucket_arn = var.enable_nist_features == false ? null : local.bucket_exists == "false" ? module.spoke_logging_bucket[0].local_s3_bucket_arn : "arn:aws:s3:::aws-waf-logs-infra-${var.spoke_account_id}-${var.location}-bkt" spoke_account_id = var.spoke_account_id location = var.location diff --git a/modules/aws_s3/main.tf b/modules/aws_s3/main.tf index 9ffe0649..c42cd187 100644 --- a/modules/aws_s3/main.tf +++ b/modules/aws_s3/main.tf @@ -76,7 +76,7 @@ data "aws_iam_policy_document" "assume_role_local" { } principals { type = "AWS" - identifiers = ["arn:aws:iam::730335345263:role/sascloud-awsng-logging-cross-account-iam-role"] + identifiers = ["arn:aws:iam::${var.logging_account}:role/sascloud-awsng-logging-cross-account-iam-role"] } actions = ["sts:AssumeRole"] } diff --git a/modules/aws_s3/variables.tf b/modules/aws_s3/variables.tf index b2c956a7..2956758c 100644 --- a/modules/aws_s3/variables.tf +++ b/modules/aws_s3/variables.tf @@ -41,3 +41,8 @@ variable "prefixes" { default = ["vpc-flow", "alb-nlb", "dns-query"] } +variable "logging_account" { + description = "Central logging accoutn ID" + type = string +} + diff --git a/outputs.tf b/outputs.tf index 6e5e38f9..e8723bb6 100755 --- a/outputs.tf +++ b/outputs.tf @@ -122,7 +122,7 @@ output "postgres_servers" { output "nat_ip" { description = "List of public Elastic IPs created for AWS NAT Gateway." - value = var.enable_nist_features == true ? null : module.vpc.nat_public_ips[0] + value = var.enable_nist_features == true ? null : module.vpc.nat_public_ips[0] } output "prefix" { diff --git a/variables.tf b/variables.tf index 2688606a..e01c40b6 100644 --- a/variables.tf +++ b/variables.tf @@ -779,7 +779,7 @@ variable "analyzer_name" { variable "central_logging_bucket" { type = string description = "Centralized logging bucket" - default = "" + default = "" } variable "conformance_pack_name" { @@ -865,6 +865,10 @@ variable "org_id" { default = "" } +variable "logging_account" { + description = "Central logging accoutn ID" + type = string +} diff --git a/vms.tf b/vms.tf index 3d418384..27fd533e 100644 --- a/vms.tf +++ b/vms.tf @@ -33,7 +33,7 @@ resource "aws_fsx_ontap_file_system" "ontap-fs" { security_group_ids = [local.workers_security_group_id] tags = merge(local.tags, { "Name" : "${var.prefix}-ontap-fs", "Backup" = var.enable_nist_features == true ? "Enabled" : null }) kms_key_id = lookup(local.kms_keys, "fsx_key", null) - depends_on = [module.ontap] + depends_on = [module.ontap] } # ONTAP storage virtual machine and volume resources @@ -180,6 +180,6 @@ module "nfs" { ssh_public_key = local.ssh_public_key enable_ebs_encryption = var.enable_ebs_encryption - cloud_init = data.cloudinit_config.nfs[0].rendered - ebs_cmk_key = lookup(local.kms_keys, "ebs_key", null) + cloud_init = data.cloudinit_config.nfs[0].rendered + ebs_cmk_key = lookup(local.kms_keys, "ebs_key", null) } From 46f30bfd4764645cf58737a13487cf85281af15d Mon Sep 17 00:00:00 2001 From: Deshmukh Date: Wed, 4 Dec 2024 18:19:42 +0530 Subject: [PATCH 29/40] formatted the sample-input-nist.tfvars --- examples/sample-input-nist.tfvars | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/examples/sample-input-nist.tfvars b/examples/sample-input-nist.tfvars index 22bf1e5e..0f338520 100644 --- a/examples/sample-input-nist.tfvars +++ b/examples/sample-input-nist.tfvars @@ -4,8 +4,8 @@ # **************** REQUIRED VARIABLES **************** # These required variables' values MUST be provided by the User -prefix = "dev" -location = "ap-northeast-1" # e.g., "us-east-1" +prefix = "" +location = "" # e.g., "us-east-1" # **************** REQUIRED VARIABLES **************** # !NOTE! - Without specifying your CIDR block access rules, ingress traffic @@ -14,23 +14,24 @@ location = "ap-northeast-1" # e.g., "us-east-1" #***************** CIDR Range for Spoke VPC ************** vpc_cidr = "10.80.16.0/22" -hub = "CustomerSpokeUS" -hub_environment = "prod" +hub = "" +hub_environment = "" # dev or prod - org_id = "o-03y3m4pkl8" - central_restore_operator = "arn:aws:iam::992382826079:role/sascloud-awsng-central-restore-iam-role-prod" - central_backup_operator = "arn:aws:iam::992382826079:role/sascloud-awsng-central-backup-iam-role-prod" - central_backup_vault_us = "arn:aws:backup:us-east-1:992382826079:backup-vault:sascloud-awsng-central-backup-vault-prod" - central_backup_vault_eu = "arn:aws:backup:eu-central-1:992382826079:backup-vault:sascloud-awsng-central-backup-vault-prod" - central_logging_bucket = "arn:aws:s3:::sascloud-awsng-centralized-prod-logging-bkt" - core_network_id = "core-network-0f5411afa03340169" - core_network_arn = "arn:aws:networkmanager::396608809900:core-network/core-network-0f5411afa03340169" + org_id = "" + central_restore_operator = "" + central_backup_operator = "" + central_backup_vault_us = "" + central_backup_vault_eu = "" + central_logging_bucket = "" + core_network_id = "" + core_network_arn = "" # ********* Set to true to enable NIST complaint code *********** enable_nist_features = true -backup_account_id = "992382826079" +backup_account_id = "" +logging_account = "" #***************** Additional CIDR ranges for Spoke VPC ************* @@ -85,7 +86,7 @@ enable_ebs_encryption = true #template_s3_uri = "s3://sascloud-awsng-conformance-pack/Operational-Best-Practices-for-NIST-800-53-rev-5.yaml" conformance_pack_name = "Operational-Best-Practices-for-NIST-800-53-rev-5" -spoke_account_id = "637423594384" +spoke_account_id = "" ## Cluster Node Pools config node_pools = { From ca8587a5e06bc7c9b73936b1832849e09b12db9f Mon Sep 17 00:00:00 2001 From: Deshmukh Date: Tue, 10 Dec 2024 16:03:34 +0530 Subject: [PATCH 30/40] modified the Cloudwatch module --- examples/sample-input-nist.tfvars | 2 +- main.tf | 88 ++++++++-------- modules/aws_cloudwatch/main.tf | 158 +++++++++++++++++++++++++--- modules/aws_cloudwatch/outputs.tf | 4 + modules/aws_cloudwatch/variables.tf | 69 ++++++++++++ 5 files changed, 264 insertions(+), 57 deletions(-) create mode 100644 modules/aws_cloudwatch/outputs.tf diff --git a/examples/sample-input-nist.tfvars b/examples/sample-input-nist.tfvars index 0f338520..88fabf4d 100644 --- a/examples/sample-input-nist.tfvars +++ b/examples/sample-input-nist.tfvars @@ -159,4 +159,4 @@ node_pools = { "metadata_http_tokens" = "required" "metadata_http_put_response_hop_limit" = 1 } -} +} \ No newline at end of file diff --git a/main.tf b/main.tf index 2b910c64..1fd5e9f2 100755 --- a/main.tf +++ b/main.tf @@ -181,48 +181,48 @@ module "eks" { # To add the current caller identity as an administrator enable_cluster_creator_admin_permissions = true - access_entries = { - # access entry with cluster and namespace scoped policies - cluster_creator = { - kubernetes_groups = ["rbac.authorization.k8s.io"] - principal_arn = data.aws_caller_identity.terraform.arn - user_name = local.aws_caller_identity_user_name - type = "STANDARD" - - policy_associations = { - cluster_creator_assoc = { - policy_arn = "arn:aws:eks::aws:cluster-access-policy/AmazonEKSClusterAdminPolicy" - access_scope = { - type = "cluster" - } - }, - namespace_creator_assoc = { - policy_arn = "arn:aws:eks::aws:cluster-access-policy/AmazonEKSAdminPolicy" - access_scope = { - type = "namespace" - namespaces = ["kube-system"] - } - } - }, - }, - } - - iam_role_additional_policies = { - "additional" : "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly" - } - - ## Use this to define any values that are common and applicable to all Node Groups - eks_managed_node_group_defaults = { - create_security_group = false - vpc_security_group_ids = [local.workers_security_group_id] - - # BYO - EKS Workers IAM Role - create_iam_role = var.workers_iam_role_arn == null ? true : false - iam_role_arn = var.workers_iam_role_arn - } - - ## Any individual Node Group customizations should go here - eks_managed_node_groups = local.node_groups +# access_entries = { +# # access entry with cluster and namespace scoped policies +# cluster_creator = { +# kubernetes_groups = ["rbac.authorization.k8s.io"] +# principal_arn = data.aws_caller_identity.terraform.arn +# user_name = local.aws_caller_identity_user_name +# type = "STANDARD" + +# policy_associations = { +# cluster_creator_assoc = { +# policy_arn = "arn:aws:eks::aws:cluster-access-policy/AmazonEKSClusterAdminPolicy" +# access_scope = { +# type = "cluster" +# } +# }, +# namespace_creator_assoc = { +# policy_arn = "arn:aws:eks::aws:cluster-access-policy/AmazonEKSAdminPolicy" +# access_scope = { +# type = "namespace" +# namespaces = ["kube-system"] +# } +# } +# }, +# }, +# } + +# iam_role_additional_policies = { +# "additional" : "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly" +# } + +# ## Use this to define any values that are common and applicable to all Node Groups +# eks_managed_node_group_defaults = { +# create_security_group = false +# vpc_security_group_ids = [local.workers_security_group_id] + +# # BYO - EKS Workers IAM Role +# create_iam_role = var.workers_iam_role_arn == null ? true : false +# iam_role_arn = var.workers_iam_role_arn +# } + +# ## Any individual Node Group customizations should go here +# eks_managed_node_groups = local.node_groups } module "autoscaling" { @@ -384,6 +384,10 @@ module "cloudwatch" { storage_type_backend = var.storage_type_backend efs_id = local.efs_id fsx_id = local.fsx_id + spoke_account_id = var.spoke_account_id + location = var.location + hub_environment = var.hub_environment + } ##########Spoke bucket for centralized logging######## diff --git a/modules/aws_cloudwatch/main.tf b/modules/aws_cloudwatch/main.tf index 2df57381..68ac7514 100644 --- a/modules/aws_cloudwatch/main.tf +++ b/modules/aws_cloudwatch/main.tf @@ -1,13 +1,125 @@ # # SNS Notification resource "aws_sns_topic" "user_updates" { name = "SAS-AWS-NextGen-SNS-topic" - kms_master_key_id = "alias/aws/sns" + kms_master_key_id = aws_kms_alias.sns_kms.target_key_id + tags = var.tags } + +data "aws_iam_policy_document" "sns_topic_policy" { + policy_id = "__default_policy_ID" + + statement { + actions = [ + "SNS:GetTopicAttributes", + "SNS:SetTopicAttributes", + "SNS:AddPermission", + "SNS:RemovePermission", + "SNS:DeleteTopic", + "SNS:Subscribe", + "SNS:ListSubscriptionsByTopic", + "SNS:Publish", + "SNS:Receive" + ] + condition { + test = "StringEquals" + variable = "AWS:SourceOwner" + values = [ + var.spoke_account_id + ] + } + effect = "Allow" + principals { + type = "AWS" + identifiers = ["*"] + } + resources = [ + aws_sns_topic.user_updates.arn + ] + sid = "__default_statement_ID" + } + + statement { + actions = ["sns:Publish"] + sid = "SNSEncryptionIntegrationWithCloudWatch" + effect = "Allow" + condition { + test = "StringEquals" + variable = "AWS:SourceOwner" + values = [ + var.spoke_account_id + ] + } + principals { + type = "Service" + identifiers = ["cloudwatch.amazonaws.com"] + } + + resources = [ + aws_sns_topic.user_updates.arn + ] + } +} + +resource "aws_sns_topic_policy" "policy_attachment" { + arn = aws_sns_topic.user_updates.arn + policy = data.aws_iam_policy_document.sns_topic_policy.json +} + resource "aws_sns_topic_subscription" "user_updates_email_target" { topic_arn = aws_sns_topic.user_updates.arn protocol = "https" - endpoint = "https://srvc_azure_monitor:Za7zlnEMLLHckpE@sasdev.service-now.com/api/sn_em_connector/em/inbound_event?source=aws" + endpoint = var.hub_environment == "prod" ? "https://srvc_em_aws_cloudwatch:5_SAtJEy9LuYTb)UKC9rHXvM@sas.service-now.com/api/sn_em_connector/em/inbound_event?source=aws" : "https://srvc_azure_monitor:Za7zlnEMLLHckpE@sasdev.service-now.com/api/sn_em_connector/em/inbound_event?source=aws" } + +resource "aws_kms_key" "cloudwatch_to_sns" { + enable_key_rotation = true + rotation_period_in_days = 90 + description = "KMS CMK key for CloudWatch to SNS Integration" + policy = jsonencode( + { + "Version" : "2012-10-17", + "Id" : "kms-sns-${var.hub_environment}-${var.location}", + "Statement" : [ + { + "Sid" : "Allow access through for all principals in the account that are authorized to use the key", + "Effect" : "Allow", + "Principal" : { + "AWS" : [ + "arn:aws:iam::${var.spoke_account_id}:root" + ] + }, + "Action" : "kms:*", + "Resource" : "*" + }, + { + "Sid" : "SNSEncryptionIntegrationWithCloudWatch", + "Effect" : "Allow", + "Principal" : { + "Service" : [ + "cloudwatch.amazonaws.com" + ] + }, + "Action" : [ + "kms:GenerateDataKey*", + "kms:DescribeKey", + "kms:Decrypt" + ], + "Resource" : "*" + } + ] + } + ) + + tags = { + managedBy = "Terraform" + } +} + +resource "aws_kms_alias" "sns_kms" { + name = "alias/${var.prefix}-sns-key" + target_key_id = aws_kms_key.cloudwatch_to_sns.key_id +} + # ########## RDS Postgres Instances ######### # # CloudWatch Alarm for RDS CPU Utilization @@ -21,7 +133,7 @@ resource "aws_cloudwatch_metric_alarm" "rds_cpu_utilization" { statistic = "Average" threshold = var.cpu_threshold actions_enabled = true - alarm_description = "Alarm if CPU utilization exceeds threshold" + alarm_description = "Severity-02 - CloudWatch Alert : [AWS] [NextGen] on RDS : The CPU Utilization for ${var.prefix}-default-pgsql is above the threshold for defined threshold" alarm_actions = [aws_sns_topic.user_updates.arn] dimensions = { DBInstanceIdentifier = "${var.prefix}-default-pgsql" //var.instance_id @@ -38,7 +150,7 @@ resource "aws_cloudwatch_metric_alarm" "rds_write_iops" { period = 900 statistic = "Average" threshold = 1000 # Adjust the threshold based on your requirements - alarm_description = "Alarm when RDS write IOPS exceeds the threshold" + alarm_description = "Severity-02- CloudWatch Alert : [AWS] [NextGen] on RDS : The read IOPS for ${var.prefix}-default-pgsql is above the threshold for defined threshold" actions_enabled = true alarm_actions = [aws_sns_topic.user_updates.arn] dimensions = { @@ -56,7 +168,7 @@ resource "aws_cloudwatch_metric_alarm" "rds_read_iops" { period = 900 statistic = "Average" threshold = 1000 # Adjust the threshold based on your requirements - alarm_description = "Alarm when RDS read IOPS exceeds the threshold" + alarm_description = "Severity-02 - CloudWatch Alert : [AWS] [NextGen] on RDS : The write IOPS for ${var.prefix}-default-pgsql is above the threshold for defined threshold" actions_enabled = true alarm_actions = [aws_sns_topic.user_updates.arn] dimensions = { @@ -74,7 +186,7 @@ resource "aws_cloudwatch_metric_alarm" "rds_network_receive_throughput" { period = 900 statistic = "Average" threshold = 1000000 # Adjust the threshold based on your requirements - alarm_description = "Alarm when RDS network receive throughput exceeds the threshold" + alarm_description = "Severity-02 - CloudWatch Alert : [AWS] [NextGen] on RDS : The Network receive throughput for ${var.prefix}-default-pgsql is above the threshold for defined threshold" actions_enabled = true alarm_actions = [aws_sns_topic.user_updates.arn] dimensions = { @@ -93,7 +205,7 @@ resource "aws_cloudwatch_metric_alarm" "rds_network_transmit_throughput" { period = 900 statistic = "Average" threshold = 1000000 # Adjust the threshold based on your requirements - alarm_description = "Alarm when RDS network transmit throughput exceeds the threshold" + alarm_description = "Severity-02 - CloudWatch Alert : [AWS] [NextGen] on RDS : The Network transmit throughput for ${var.prefix}-default-pgsql is above the threshold for defined threshold" actions_enabled = true alarm_actions = [aws_sns_topic.user_updates.arn] dimensions = { @@ -111,7 +223,7 @@ resource "aws_cloudwatch_metric_alarm" "rds_freeable_memory" { period = 900 statistic = "Average" threshold = 500000000 # Adjust the threshold based on your requirements (in bytes) - alarm_description = "Alarm when RDS free memory is below the threshold" + alarm_description = "Severity-02 - CloudWatch Alert : [AWS] [NextGen] on RDS : The Free memory for ${var.prefix}-default-pgsql is above the threshold for defined threshold" actions_enabled = true alarm_actions = [aws_sns_topic.user_updates.arn] dimensions = { @@ -129,7 +241,7 @@ resource "aws_cloudwatch_metric_alarm" "rds_free_storage" { period = 900 statistic = "Average" threshold = 10000000000 # Adjust the threshold based on your requirements (in bytes) - alarm_description = "Alarm when RDS free disk space is below the threshold" + alarm_description = "Severity-02 - CloudWatch Alert : [AWS] [NextGen] on RDS : The disk space Utilization for ${var.prefix}-default-pgsql is above the threshold for defined threshold" actions_enabled = true alarm_actions = [aws_sns_topic.user_updates.arn] # Add SNS topic ARN for notifications dimensions = { @@ -148,7 +260,7 @@ resource "aws_cloudwatch_metric_alarm" "efs_client_connections" { period = "900" # 5 minutes statistic = "Average" threshold = "90" # Set your desired threshold - alarm_description = "Alarm when EFS client connections exceed 10" + alarm_description = "Severity-03 - CloudWatch Alert : [AWS] [NextGen] on EFS : The Client connection for ${var.prefix}-efs is above the threshold for defined threshold" alarm_actions = [aws_sns_topic.user_updates.arn] # Add SNS topic ARN for notifications dimensions = { FileSystemId = var.efs_id @@ -163,8 +275,8 @@ resource "aws_cloudwatch_metric_alarm" "efs_total_io_bytes" { namespace = "AWS/EFS" period = "900" # 5 minutes statistic = "Sum" - threshold = "1000000" # Set your desired threshold - alarm_description = "Alarm when EFS total IO bytes exceed 1,000,000" + threshold = "9000000000" # Set your desired threshold + alarm_description = "Severity-03 - CloudWatch Alert : [AWS] [NextGen] on EFS : The IO bytes for ${var.prefix}-efs is above the threshold for defined threshold" alarm_actions = [aws_sns_topic.user_updates.arn] # Add SNS topic ARN for notifications dimensions = { FileSystemId = var.efs_id @@ -183,7 +295,7 @@ resource "aws_cloudwatch_metric_alarm" "fsx_storage_capacity" { period = 900 statistic = "Average" threshold = 90 # Change threshold percentage as needed - alarm_description = "Alarm when FSx storage capacity exceeds 90%." + alarm_description = "Severity-03 - CloudWatch Alert : [AWS] [NextGen] on FSx : The Storage capacity for ${var.prefix}-fsx is above the threshold for defined threshold" alarm_actions = [aws_sns_topic.user_updates.arn] # Add SNS topic ARN for notifications dimensions = { FileSystemId = var.fsx_id @@ -200,12 +312,30 @@ resource "aws_cloudwatch_metric_alarm" "fsx_storage_used" { period = 900 statistic = "Average" threshold = 90 # Change threshold percentage as needed - alarm_description = "Alarm when FSx storage used exceeds 90%." + alarm_description = "Severity-03 - CloudWatch Alert : [AWS] [NextGen] on FSx : The Storage used for ${var.prefix}-fsx is above the threshold for defined threshold" alarm_actions = [aws_sns_topic.user_updates.arn] # Add SNS topic ARN for notifications dimensions = { FileSystemId = var.fsx_id } } +# ######## CloudWatch Billing Alarm ######## +resource "aws_cloudwatch_metric_alarm" "billing_alarm" { + alarm_name = "SAS_NextGen_billing_alarm" + comparison_operator = "GreaterThanThreshold" + evaluation_periods = "1" + metric_name = "EstimatedCharges" + namespace = "AWS/Billing" + period = "21600" + statistic = "Maximum" + threshold = var.billing_threshold + alarm_description = "Severity-03 - CloudWatch Alert : [AWS] [NextGen] on resource billing : The Billing for the resources is above the threshold for defined threshold" + actions_enabled = true + alarm_actions = [aws_sns_topic.user_updates.arn] + + dimensions = { + Currency = "USD" + } +} diff --git a/modules/aws_cloudwatch/outputs.tf b/modules/aws_cloudwatch/outputs.tf new file mode 100644 index 00000000..3c04e88a --- /dev/null +++ b/modules/aws_cloudwatch/outputs.tf @@ -0,0 +1,4 @@ +output "sns_arn" { + description = "Sns arn o/p" + value = aws_sns_topic.user_updates.arn +} diff --git a/modules/aws_cloudwatch/variables.tf b/modules/aws_cloudwatch/variables.tf index bd692646..6d147545 100644 --- a/modules/aws_cloudwatch/variables.tf +++ b/modules/aws_cloudwatch/variables.tf @@ -9,6 +9,20 @@ variable "cpu_threshold" { default = 80 } + +variable "billing_threshold" { + description = "Threshold for CPU utilization" + type = number + default = 2500 +} + + +variable "enable_nist_features" { + description = "A flag to enable NIST features under development for this project" + type = bool + default = false # set it to true for NIST enchancements +} + variable "storage_type_backend" { description = "The storage backend used for the chosen storage type. Defaults to 'nfs' for storage_type='standard'. Defaults to 'efs for storage_type='ha'. 'efs' and 'ontap' are valid choices for storage_type='ha'." type = string @@ -31,3 +45,58 @@ variable "fsx_id" { type = string } +variable "cloudwatch_monitor_severity" { + type = map(number) + default = { + "threshold_active_flow" = "100" + "threshold_processed_bytes" = "4000000" + "threshold_unhealthy_host" = "1" + "threshold_peak_packets" = "1000" + "cpu_threshold" = "90" + "ram_threshold" = "90" + "disk_utilization" = "90" + "ebs_read_threshold" = "9000" + "ebs_write_threshold" = "9000" + "billing_threshold" = "6000" + "ec2statuscheck" = "1" + } +} + +variable "cloudwatch_monitor_thresholds" { + type = map(string) + default = { + "threshold_active_flow" = "Severity3" + "threshold_processed_bytes" = "Severity3" + "threshold_unhealthy_host" = "Severity2" + "threshold_peak_packets" = "Severity3" + "cpu_threshold" = "Severity2" + "ram_threshold" = "Severity2" + "disk_utilization" = "Severity2" + "ebs_read_threshold" = "Severity2" + "ebs_write_threshold" = "Severity2" + "billing_threshold" = "Severity2" + "ec2statuscheck" = "Severity2" + } +} + +variable "tags" { + description = "The tags to associate with resources when enable_nist_features is set to true." + type = map(string) + default = {} +} + +variable "hub_environment" { + description = "name of the hub_environment" + type = string +} + +variable "location" { + description = "Region of deployment" + type = string +} + +variable "spoke_account_id" { + description = "spoke account id for s3 deployment" + type = string +} + From 92b71f2bcade05162ecb45df47388e9115befb61 Mon Sep 17 00:00:00 2001 From: Deshmukh Date: Thu, 12 Dec 2024 16:28:47 +0530 Subject: [PATCH 31/40] updated the backup rules --- examples/sample-input-nist.tfvars | 30 ++++++----- main.tf | 85 ++++++++++++++++--------------- modules/aws_backup/iam_role.tf | 27 +++++++++- modules/aws_cloudwatch/main.tf | 8 +-- modules/aws_s3/outputs.tf | 4 +- variables.tf | 33 ++++++++---- 6 files changed, 114 insertions(+), 73 deletions(-) diff --git a/examples/sample-input-nist.tfvars b/examples/sample-input-nist.tfvars index 88fabf4d..62810a7d 100644 --- a/examples/sample-input-nist.tfvars +++ b/examples/sample-input-nist.tfvars @@ -4,8 +4,8 @@ # **************** REQUIRED VARIABLES **************** # These required variables' values MUST be provided by the User -prefix = "" -location = "" # e.g., "us-east-1" +prefix = "testindev" +location = "us-east-1" # e.g., "us-east-1" # **************** REQUIRED VARIABLES **************** # !NOTE! - Without specifying your CIDR block access rules, ingress traffic @@ -14,24 +14,26 @@ location = "" # e.g., "us-east-1" #***************** CIDR Range for Spoke VPC ************** vpc_cidr = "10.80.16.0/22" -hub = "" -hub_environment = "" # dev or prod +hub = "CustomerSpokeUS" +hub_environment = "prod" # dev or prod + + + org_id = "o-03y3m4pkl8" + central_restore_operator = "arn:aws:iam::992382826079:role/sascloud-awsng-central-restore-iam-role-prod" + central_backup_operator = "arn:aws:iam::992382826079:role/sascloud-awsng-central-backup-iam-role-prod" + central_backup_vault_us = "arn:aws:backup:us-east-1:992382826079:backup-vault:sascloud-awsng-central-backup-vault-prod" + central_backup_vault_eu = "arn:aws:backup:eu-central-1:992382826079:backup-vault:sascloud-awsng-central-backup-vault-prod" + central_logging_bucket = "arn:aws:s3:::sascloud-awsng-centralized-prod-logging-bkt" + core_network_id = "core-network-0f5411afa03340169" + core_network_arn = "arn:aws:networkmanager::396608809900:core-network/core-network-0f5411afa03340169" - org_id = "" - central_restore_operator = "" - central_backup_operator = "" - central_backup_vault_us = "" - central_backup_vault_eu = "" - central_logging_bucket = "" - core_network_id = "" - core_network_arn = "" # ********* Set to true to enable NIST complaint code *********** enable_nist_features = true -backup_account_id = "" -logging_account = "" +backup_account_id = "992382826079" +logging_account = "730335345263" #***************** Additional CIDR ranges for Spoke VPC ************* diff --git a/main.tf b/main.tf index 1fd5e9f2..e9644bea 100755 --- a/main.tf +++ b/main.tf @@ -16,6 +16,7 @@ provider "aws" { token = var.aws_session_token + } data "aws_eks_cluster_auth" "cluster" { @@ -181,48 +182,48 @@ module "eks" { # To add the current caller identity as an administrator enable_cluster_creator_admin_permissions = true -# access_entries = { -# # access entry with cluster and namespace scoped policies -# cluster_creator = { -# kubernetes_groups = ["rbac.authorization.k8s.io"] -# principal_arn = data.aws_caller_identity.terraform.arn -# user_name = local.aws_caller_identity_user_name -# type = "STANDARD" - -# policy_associations = { -# cluster_creator_assoc = { -# policy_arn = "arn:aws:eks::aws:cluster-access-policy/AmazonEKSClusterAdminPolicy" -# access_scope = { -# type = "cluster" -# } -# }, -# namespace_creator_assoc = { -# policy_arn = "arn:aws:eks::aws:cluster-access-policy/AmazonEKSAdminPolicy" -# access_scope = { -# type = "namespace" -# namespaces = ["kube-system"] -# } -# } -# }, -# }, -# } - -# iam_role_additional_policies = { -# "additional" : "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly" -# } - -# ## Use this to define any values that are common and applicable to all Node Groups -# eks_managed_node_group_defaults = { -# create_security_group = false -# vpc_security_group_ids = [local.workers_security_group_id] - -# # BYO - EKS Workers IAM Role -# create_iam_role = var.workers_iam_role_arn == null ? true : false -# iam_role_arn = var.workers_iam_role_arn -# } - -# ## Any individual Node Group customizations should go here -# eks_managed_node_groups = local.node_groups + # access_entries = { + # # access entry with cluster and namespace scoped policies + # cluster_creator = { + # kubernetes_groups = ["rbac.authorization.k8s.io"] + # principal_arn = data.aws_caller_identity.terraform.arn + # user_name = local.aws_caller_identity_user_name + # type = "STANDARD" + + # policy_associations = { + # cluster_creator_assoc = { + # policy_arn = "arn:aws:eks::aws:cluster-access-policy/AmazonEKSClusterAdminPolicy" + # access_scope = { + # type = "cluster" + # } + # }, + # namespace_creator_assoc = { + # policy_arn = "arn:aws:eks::aws:cluster-access-policy/AmazonEKSAdminPolicy" + # access_scope = { + # type = "namespace" + # namespaces = ["kube-system"] + # } + # } + # }, + # }, + # } + + iam_role_additional_policies = { + "additional" : "arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly" + } + + ## Use this to define any values that are common and applicable to all Node Groups + eks_managed_node_group_defaults = { + create_security_group = false + vpc_security_group_ids = [local.workers_security_group_id] + + # BYO - EKS Workers IAM Role + create_iam_role = var.workers_iam_role_arn == null ? true : false + iam_role_arn = var.workers_iam_role_arn + } + + ## Any individual Node Group customizations should go here + eks_managed_node_groups = local.node_groups } module "autoscaling" { diff --git a/modules/aws_backup/iam_role.tf b/modules/aws_backup/iam_role.tf index 88f07679..352b1614 100644 --- a/modules/aws_backup/iam_role.tf +++ b/modules/aws_backup/iam_role.tf @@ -1,3 +1,7 @@ +locals { + policy_list = ["arn:aws:iam::aws:policy/service-role/AWSBackupServiceRolePolicyForRestores", "${aws_iam_policy.ec2_pass_policy.arn}"] +} + data "aws_iam_policy_document" "assume_role" { statement { @@ -23,7 +27,7 @@ resource "aws_iam_role_policy_attachment" "aws_managed_backup_operator" { } resource "aws_iam_role" "restore_operator_role" { - name = "sas-awsng-${var.location}-${var.hub_environment}-restore-operator-role" + name = "sas-awsng-${var.location}-${var.hub_environment}-backup-restore-operator-role" assume_role_policy = data.aws_iam_policy_document.assume_role.json tags = var.tags } @@ -33,4 +37,25 @@ resource "aws_iam_role_policy_attachment" "aws_managed_restore_operator" { policy_arn = "arn:aws:iam::aws:policy/service-role/AWSBackupServiceRolePolicyForRestores" } +data "aws_iam_policy_document" "ec2_pass" { + statement { + effect = "Allow" + actions = ["iam:PassRole"] + resources = ["arn:aws:iam::${var.spoke_account_id}:role/*"] + } +} + +resource "aws_iam_policy" "ec2_pass_policy" { + name = "sascloud-ec2-pass-policy-${var.hub_environment}-${var.location}" + policy = data.aws_iam_policy_document.ec2_pass.json +} + + +resource "aws_iam_role_policy_attachment" "aws_managed_ec2_restore_operator" { + depends_on = [aws_iam_policy.ec2_pass_policy] + for_each = { for k, v in local.policy_list : k => v } + role = aws_iam_role.restore_operator_role.name + policy_arn = each.value +} + diff --git a/modules/aws_cloudwatch/main.tf b/modules/aws_cloudwatch/main.tf index 68ac7514..474a174e 100644 --- a/modules/aws_cloudwatch/main.tf +++ b/modules/aws_cloudwatch/main.tf @@ -294,11 +294,13 @@ resource "aws_cloudwatch_metric_alarm" "fsx_storage_capacity" { namespace = "AWS/FSx" period = 900 statistic = "Average" - threshold = 90 # Change threshold percentage as needed + threshold = 9000000000 # Change threshold percentage as needed alarm_description = "Severity-03 - CloudWatch Alert : [AWS] [NextGen] on FSx : The Storage capacity for ${var.prefix}-fsx is above the threshold for defined threshold" alarm_actions = [aws_sns_topic.user_updates.arn] # Add SNS topic ARN for notifications - dimensions = { + dimensions = { FileSystemId = var.fsx_id + DataType = "All" + StorageTier = "SSD" } } # # # Alarm for storage used @@ -311,7 +313,7 @@ resource "aws_cloudwatch_metric_alarm" "fsx_storage_used" { namespace = "AWS/FSx" period = 900 statistic = "Average" - threshold = 90 # Change threshold percentage as needed + threshold = 9000000000 # Change threshold percentage as needed alarm_description = "Severity-03 - CloudWatch Alert : [AWS] [NextGen] on FSx : The Storage used for ${var.prefix}-fsx is above the threshold for defined threshold" alarm_actions = [aws_sns_topic.user_updates.arn] # Add SNS topic ARN for notifications dimensions = { diff --git a/modules/aws_s3/outputs.tf b/modules/aws_s3/outputs.tf index cc4182da..502705d3 100644 --- a/modules/aws_s3/outputs.tf +++ b/modules/aws_s3/outputs.tf @@ -1,12 +1,12 @@ output "local_s3_bucket_arn" { description = "ARN of the bucket" - value = var.bucket_external == "true" ? "arn:aws:s3:::aws-waf-logs-sas-infra-${var.spoke_account_id}-${var.location}-bkt" : aws_s3_bucket.local_s3_bucket.arn + value = var.bucket_external == "true" ? "aws-waf-logs-infra-${var.spoke_account_id}-${var.location}-bkt" : aws_s3_bucket.local_s3_bucket.arn } output "bucket_name" { description = "S3 name" - value = var.bucket_external == "true" ? "aws-waf-logs-sas-infra-${var.spoke_account_id}-${var.location}-bkt" : aws_s3_bucket.local_s3_bucket.id + value = var.bucket_external == "true" ? "aws-waf-logs-infra-${var.spoke_account_id}-${var.location}-bkt" : aws_s3_bucket.local_s3_bucket.id } diff --git a/variables.tf b/variables.tf index e01c40b6..75f3e4bd 100644 --- a/variables.tf +++ b/variables.tf @@ -730,21 +730,25 @@ variable "additional_cidr_ranges" { variable "hub_environment" { description = "name of the hub_environment" type = string + default = "" } variable "core_network_id" { description = "Cloud WAN: Core network ID from Global networking account" type = string + default = "" } variable "hub" { description = "Name of the Hub: for e.g, CustomerSpokeUS or CustomerSpokeEU " type = string + default = "" } variable "core_network_arn" { description = "Core network ARN" type = string + default = "" } variable "vpc_nist_endpoints" { @@ -760,6 +764,7 @@ variable "vpc_nist_endpoints" { variable "backup_account_id" { type = string description = "Central backup account number for backup and logging" + default = "" } @@ -799,29 +804,25 @@ variable "custom_conformance_pack_name" { variable "central_backup_operator" { type = string description = "IAM role for backup module " - # default = "arn:aws:iam::992382826079:role/sascloud-awsng-central-backup-iam-role-dev" - default = "" + default = "" } variable "central_restore_operator" { type = string description = "IAM role for restoration" - # default = "arn:aws:iam::992382826079:role/sascloud-awsng-central-restore-iam-role-dev" - default = "" + default = "" } variable "central_backup_vault_us" { type = string description = "Backup vault" - # default = "arn:aws:backup:us-east-1:992382826079:backup-vault:sascloud-awsng-central-backup-vault-dev" - default = "" + default = "" } variable "central_backup_vault_eu" { type = string description = "Backup vault" - # default = "arn:aws:backup:eu-central-1:992382826079:backup-vault:sascloud-awsng-central-backup-vault-dev" - default = "" + default = "" } variable "spoke_backup_rules" { @@ -848,11 +849,20 @@ variable "spoke_backup_rules" { })) })) default = [{ - "name" : "backup_rule", - "schedule" : "cron(30 16 ? * * *)" + name = "backup_rule_daily" + schedule = "cron(0 23 ? * 1-5,7 *)" + recovery_point_tags = {} lifecycle = { - delete_after = "21" + delete_after = 14 } + }, + { + name = "backup_rule_weekly" + schedule = "cron(0 23 ? * 6 *)" + recovery_point_tags = {} + lifecycle = { + delete_after = 60 + } }] } @@ -868,6 +878,7 @@ variable "org_id" { variable "logging_account" { description = "Central logging accoutn ID" type = string + default = "" } From 0547254a438532579da28d54081c2f4ca8a28ee2 Mon Sep 17 00:00:00 2001 From: Deshmukh Date: Wed, 18 Dec 2024 15:27:12 +0530 Subject: [PATCH 32/40] made changes on backup module --- main.tf | 1 + modules/aws_backup/main.tf | 245 +++++++++++++++++++++++++++++--- modules/aws_backup/variables.tf | 16 +++ modules/aws_s3/outputs.tf | 2 +- variables.tf | 126 ++++++++++++---- 5 files changed, 340 insertions(+), 50 deletions(-) diff --git a/main.tf b/main.tf index e9644bea..f538bd3a 100755 --- a/main.tf +++ b/main.tf @@ -455,6 +455,7 @@ module "spoke_backup" { hub_environment = var.hub_environment depends_on = [module.resource_checker] + } ########## Resource Checker ######### diff --git a/modules/aws_backup/main.tf b/modules/aws_backup/main.tf index c499bfc7..07cf4ce6 100644 --- a/modules/aws_backup/main.tf +++ b/modules/aws_backup/main.tf @@ -1,3 +1,5 @@ + + resource "aws_backup_vault" "spoke" { name = "sas-awsng-${var.spoke_account_id}-backup-vault" kms_key_arn = aws_kms_key.spoke_vault_key.arn @@ -235,16 +237,181 @@ resource "aws_backup_framework" "backup_compliance_framework" { } } - - +# locals { +# location_vault_map = { +# "us-east-1" = "arn:aws:backup:${var.location}:${var.backup_account_id}:backup-vault:sascloud-awsng-central-backup-vault-${var.hub_environment}" +# "eu-central-1" = "arn:aws:backup:${var.location}:${var.backup_account_id}:backup-vault:sascloud-awsng-central-backup-vault-${var.hub_environment}" +# "ca-central-1" = "arn:aws:backup:${var.location}:${var.backup_account_id}:backup-vault:sascloud-awsng-central-backup-vault-${var.hub_environment}" +# "eu-west-1" = "arn:aws:backup:${var.location}:${var.backup_account_id}:backup-vault:sascloud-awsng-central-backup-vault-${var.hub_environment}" +# "ap-southeast-1" = "arn:aws:backup:${var.location}:${var.backup_account_id}:backup-vault:sascloud-awsng-central-backup-vault-${var.hub_environment}" +# "ap-northeast-1" = "arn:aws:backup:${var.location}:${var.backup_account_id}:backup-vault:sascloud-awsng-central-backup-vault-${var.hub_environment}" +# "ap-south-1" = "arn:aws:backup:${var.location}:${var.backup_account_id}:backup-vault:sascloud-awsng-central-backup-vault-${var.hub_environment}" +# "eu-west-3" = "arn:aws:backup:${var.location}:${var.backup_account_id}:backup-vault:sascloud-awsng-central-backup-vault-${var.hub_environment}" +# "us-west-1" = "arn:aws:backup:${var.location}:${var.backup_account_id}:backup-vault:sascloud-awsng-central-backup-vault-${var.hub_environment}" +# } +# } + +# resource "aws_backup_plan" "spoke" { +# name = "sas-awsng-${var.spoke_account_id}-backup-plan" + +# dynamic "rule" { +# for_each = var.spoke_backup_rules +# content { +# rule_name = rule.value.name +# target_vault_name = aws_backup_vault.spoke.name +# schedule = rule.value.schedule +# start_window = rule.value.start_window +# completion_window = rule.value.completion_window +# recovery_point_tags = rule.value.recovery_point_tags +# enable_continuous_backup = rule.value.enable_continuous_backup + +# dynamic "lifecycle" { +# for_each = lookup(rule.value, "lifecycle", null) != null ? [true] : [] +# content { +# cold_storage_after = rule.value.lifecycle.cold_storage_after +# delete_after = rule.value.lifecycle.delete_after +# } +# } + +# # Copy action for EFS +# dynamic "copy_action" { +# for_each = contains(["efs_backup_rule_daily", "efs_backup_rule_weekly"], rule.value.name) ? [true] : [] + +# content { +# destination_vault_arn = var.central_backup_vault_us # Example for US + +# dynamic "selection_tag" { +# for_each = [for t in rule.value.recovery_point_tags : t if t.key == "Backup" && t.value == "efs"] + +# content { +# type = "STRINGEQUALS" +# key = "Backup" +# value = "efs" +# } +# } + +# dynamic "lifecycle" { +# for_each = try(lookup(rule.value.copy_action, "lifecycle", null), null) != null ? [true] : [] + +# content { +# cold_storage_after = rule.value.copy_action.lifecycle.cold_storage_after +# delete_after = rule.value.copy_action.lifecycle.delete_after +# } +# } +# } +# } + +# # Copy action for RDS +# dynamic "copy_action" { +# for_each = contains(["rds_backup_rule_daily", "rds_backup_rule_weekly"], rule.value.name) ? [true] : [] + +# content { +# destination_vault_arn = lookup(local.location_vault_map, var.location, null) + +# dynamic "selection_tag" { +# for_each = [for t in rule.value.recovery_point_tags : t if t.key == "Backup" && t.value == "rds"] + +# content { +# type = "STRINGEQUALS" +# key = "Backup" +# value = "rds" +# } +# } + +# dynamic "lifecycle" { +# for_each = try(lookup(rule.value.copy_action, "lifecycle", null), null) != null ? [true] : [] + +# content { +# cold_storage_after = rule.value.copy_action.lifecycle.cold_storage_after +# delete_after = rule.value.copy_action.lifecycle.delete_after +# } +# } +# } +# } + +# # Copy action for FSx +# dynamic "copy_action" { +# for_each = contains(["fsx_backup_rule_daily", "fsx_backup_rule_weekly"], rule.value.name) ? [true] : [] + +# content { +# destination_vault_arn = var.central_backup_vault_us # Example for US or a different FSx target + +# dynamic "selection_tag" { +# for_each = [for t in rule.value.recovery_point_tags : t if t.key == "Backup" && t.value == "fsx"] + +# content { +# type = "STRINGEQUALS" +# key = "Backup" +# value = "fsx" +# } +# } + +# dynamic "lifecycle" { +# for_each = try(lookup(rule.value.copy_action, "lifecycle", null), null) != null ? [true] : [] + +# content { +# cold_storage_after = rule.value.copy_action.lifecycle.cold_storage_after +# delete_after = rule.value.copy_action.lifecycle.delete_after +# } +# } +# } +# } + +# } +# } + +# dynamic "advanced_backup_setting" { +# for_each = var.advanced_backup_setting != null ? [true] : [] +# content { +# backup_options = var.advanced_backup_setting.backup_options +# resource_type = var.advanced_backup_setting.resource_type +# } +# } + +# tags = merge( +# var.tags, +# { +# Name = "sas-awsng-${var.spoke_account_id}-backup-plan", +# PolicyOwner = "NextGen" +# } +# ) +# } + +# resource "aws_backup_selection" "spoke" { +# iam_role_arn = aws_iam_role.backup_operator_role.arn +# name = "sas-awsng-${var.spoke_account_id}-backup-selection" +# plan_id = aws_backup_plan.spoke.id + +# dynamic "selection_tag" { +# for_each = ["efs", "rds", "fsx"] + +# content { +# type = "STRINGEQUALS" +# key = "Backup" +# value = selection_tag.value +# } +# } +#} + +locals { + location_vault_map = { + "us-east-1" = "arn:aws:backup:${var.location}:${var.backup_account_id}:backup-vault:sascloud-awsng-central-backup-vault-${var.hub_environment}" + "eu-central-1" = "arn:aws:backup:${var.location}:${var.backup_account_id}:backup-vault:sascloud-awsng-central-backup-vault-${var.hub_environment}" + "ca-central-1" = "arn:aws:backup:${var.location}:${var.backup_account_id}:backup-vault:sascloud-awsng-central-backup-vault-${var.hub_environment}" + "eu-west-1" = "arn:aws:backup:${var.location}:${var.backup_account_id}:backup-vault:sascloud-awsng-central-backup-vault-${var.hub_environment}" + "ap-southeast-1" = "arn:aws:backup:${var.location}:${var.backup_account_id}:backup-vault:sascloud-awsng-central-backup-vault-${var.hub_environment}" + "ap-northeast-1" = "arn:aws:backup:${var.location}:${var.backup_account_id}:backup-vault:sascloud-awsng-central-backup-vault-${var.hub_environment}" + "ap-south-1" = "arn:aws:backup:${var.location}:${var.backup_account_id}:backup-vault:sascloud-awsng-central-backup-vault-${var.hub_environment}" + "eu-west-3" = "arn:aws:backup:${var.location}:${var.backup_account_id}:backup-vault:sascloud-awsng-central-backup-vault-${var.hub_environment}" + "us-west-1" = "arn:aws:backup:${var.location}:${var.backup_account_id}:backup-vault:sascloud-awsng-central-backup-vault-${var.hub_environment}" + } +} resource "aws_backup_plan" "spoke" { - name = "sas-awsng-${var.spoke_account_id}-backup-plan" dynamic "rule" { for_each = var.spoke_backup_rules - content { rule_name = rule.value.name target_vault_name = aws_backup_vault.spoke.name @@ -256,45 +423,78 @@ resource "aws_backup_plan" "spoke" { dynamic "lifecycle" { for_each = lookup(rule.value, "lifecycle", null) != null ? [true] : [] - content { cold_storage_after = rule.value.lifecycle.cold_storage_after delete_after = rule.value.lifecycle.delete_after } } - copy_action { - destination_vault_arn = var.central_backup_vault_us + # Apply copy action for EFS to US vault + dynamic "copy_action" { + for_each = contains(["efs_backup_rule_daily", "efs_backup_rule_weekly"], rule.value.name) ? [true] : [] + + content { + destination_vault_arn = var.central_backup_vault_us + + dynamic "lifecycle" { + for_each = try(lookup(rule.value.copy_action, "lifecycle", null), null) != null ? [true] : [] + + content { + cold_storage_after = rule.value.copy_action.lifecycle.cold_storage_after + delete_after = rule.value.copy_action.lifecycle.delete_after + } + } + } + } + + # Apply copy action for EFS to EU vault + dynamic "copy_action" { + for_each = contains(["efs_backup_rule_daily", "efs_backup_rule_weekly"], rule.value.name) ? [true] : [] - dynamic "lifecycle" { - for_each = try(lookup(rule.value.copy_action, "lifecycle", null), null) != null ? [true] : [] + content { + destination_vault_arn = var.central_backup_vault_eu + + dynamic "lifecycle" { + for_each = try(lookup(rule.value.copy_action, "lifecycle", null), null) != null ? [true] : [] - content { - cold_storage_after = rule.value.copy_action.lifecycle.cold_storage_after - delete_after = rule.value.copy_action.lifecycle.delete_after + content { + cold_storage_after = rule.value.copy_action.lifecycle.cold_storage_after + delete_after = rule.value.copy_action.lifecycle.delete_after + } } } } - copy_action { - destination_vault_arn = var.central_backup_vault_eu - - dynamic "lifecycle" { - for_each = try(lookup(rule.value.copy_action, "lifecycle", null), null) != null ? [true] : [] - - content { - cold_storage_after = rule.value.copy_action.lifecycle.cold_storage_after - delete_after = rule.value.copy_action.lifecycle.delete_after + # Apply region-based copy action for RDS + dynamic "copy_action" { + for_each = contains(["rds_backup_rule_daily", "rds_backup_rule_weekly"], rule.value.name) ? [true] : [] + + content { + destination_vault_arn = lookup(local.location_vault_map, var.location, null) + + dynamic "lifecycle" { + for_each = try(lookup(rule.value.copy_action, "lifecycle", null), null) != null ? [true] : [] + + content { + cold_storage_after = rule.value.copy_action.lifecycle.cold_storage_after + delete_after = rule.value.copy_action.lifecycle.delete_after + } } } } + # # No copy action for FSx + # dynamic "copy_action" { + # for_each = contains(rule.value.name, "fsx") ? [] : [true] + # content { + # destination_vault_arn = aws_backup_vault.spoke.arn + # } + # } } } dynamic "advanced_backup_setting" { for_each = var.advanced_backup_setting != null ? [true] : [] - content { backup_options = var.advanced_backup_setting.backup_options resource_type = var.advanced_backup_setting.resource_type @@ -311,7 +511,6 @@ resource "aws_backup_plan" "spoke" { } resource "aws_backup_selection" "spoke" { - iam_role_arn = aws_iam_role.backup_operator_role.arn name = "sas-awsng-${var.spoke_account_id}-backup-selection" plan_id = aws_backup_plan.spoke.id diff --git a/modules/aws_backup/variables.tf b/modules/aws_backup/variables.tf index b5875dc0..9c4ccb10 100644 --- a/modules/aws_backup/variables.tf +++ b/modules/aws_backup/variables.tf @@ -104,3 +104,19 @@ variable "hub_environment" { type = string } +# variable "location_vault_map" { +# description = "A map of regions to backup vault ARNs for RDS" +# type = map(string) +# default = { +# "us-east-1" = "arn:aws:backup:${local.region}:${var.backup_account_id}:backup-vault:sascloud-awsng-central-backup-vault-${var.hub_environment}" +# "eu-central-1" = "arn:aws:backup:${var.location}:${var.backup_account_id}:backup-vault:sascloud-awsng-central-backup-vault-${var.hub_environment}" +# "ca-central-1" = "arn:aws:backup:${var.location}:${var.backup_account_id}:backup-vault:sascloud-awsng-central-backup-vault-${var.hub_environment}" +# "eu-west-1" = "arn:aws:backup:${var.location}:${var.backup_account_id}:backup-vault:sascloud-awsng-central-backup-vault-${var.hub_environment}" +# "ap-southeast-1" = "arn:aws:backup:${var.location}:${var.backup_account_id}:backup-vault:sascloud-awsng-central-backup-vault-${var.hub_environment}" +# "ap-northeast-1" = "arn:aws:backup:${var.location}:${var.backup_account_id}:backup-vault:sascloud-awsng-central-backup-vault-${var.hub_environment}" +# "ap-south-1" = "arn:aws:backup:${var.location}:${var.backup_account_id}:backup-vault:sascloud-awsng-central-backup-vault-${var.hub_environment}" +# "eu-west-3" = "arn:aws:backup:${var.location}:${var.backup_account_id}:backup-vault:sascloud-awsng-central-backup-vault-${var.hub_environment}" +# "us-west-1" = "arn:aws:backup:${var.location}:${var.backup_account_id}:backup-vault:sascloud-awsng-central-backup-vault-${var.hub_environment}" +# } +# } + diff --git a/modules/aws_s3/outputs.tf b/modules/aws_s3/outputs.tf index 502705d3..1cf97031 100644 --- a/modules/aws_s3/outputs.tf +++ b/modules/aws_s3/outputs.tf @@ -1,7 +1,7 @@ output "local_s3_bucket_arn" { description = "ARN of the bucket" - value = var.bucket_external == "true" ? "aws-waf-logs-infra-${var.spoke_account_id}-${var.location}-bkt" : aws_s3_bucket.local_s3_bucket.arn + value = var.bucket_external == "true" ? "arn:aws:s3:::aws-waf-logs-infra-${var.spoke_account_id}-${var.location}-bkt" : aws_s3_bucket.local_s3_bucket.arn } output "bucket_name" { diff --git a/variables.tf b/variables.tf index 75f3e4bd..f2d41864 100644 --- a/variables.tf +++ b/variables.tf @@ -825,6 +825,62 @@ variable "central_backup_vault_eu" { default = "" } +# variable "spoke_backup_rules" { +# description = "Backup control rules: Schedule indicates the time frame of backup" +# type = list(object({ +# name = string +# schedule = optional(string) +# enable_continuous_backup = optional(bool) +# start_window = optional(number) +# completion_window = optional(number) +# recovery_point_tags = optional(map(string)) +# lifecycle = optional(object({ +# cold_storage_after = optional(number) +# delete_after = optional(number) +# opt_in_to_archive_for_supported_resources = optional(bool) +# })) +# copy_action = optional(object({ +# destination_vault_arn = optional(string) +# lifecycle = optional(object({ +# cold_storage_after = optional(number) +# delete_after = optional(number) +# opt_in_to_archive_for_supported_resources = optional(bool) +# })) +# })) +# })) +# default = [{ +# name = "backup_rule_daily" +# schedule = "cron(0 23 ? * 1-5,7 *)" +# recovery_point_tags = {} +# lifecycle = { +# delete_after = 14 +# } +# }, +# { +# name = "backup_rule_weekly" +# schedule = "cron(0 23 ? * 6 *)" +# recovery_point_tags = {} +# lifecycle = { +# delete_after = 60 +# } +# }] + +# } + + +variable "org_id" { + type = string + description = "organization ID required to enable the conformance pack" + # default = "o-03y3m4pkl8" + default = "" +} + +variable "logging_account" { + description = "Central logging accoutn ID" + type = string + default = "" +} + variable "spoke_backup_rules" { description = "Backup control rules: Schedule indicates the time frame of backup" type = list(object({ @@ -849,37 +905,55 @@ variable "spoke_backup_rules" { })) })) default = [{ - name = "backup_rule_daily" - schedule = "cron(0 23 ? * 1-5,7 *)" + name = "efs_backup_rule_daily" + schedule = "cron(0 23 ? * 1-5,7 *)" recovery_point_tags = {} lifecycle = { delete_after = 14 } - }, + }, + { + name = "efs_backup_rule_weekly" + schedule = "cron(0 23 ? * 6 *)" + recovery_point_tags = {} + lifecycle = { + delete_after = 60 + } + }, + { + name = "rds_backup_rule_daily" + schedule = "cron(0 23 ? * 1-5,7 *)" + recovery_point_tags = {} + lifecycle = { + delete_after = 60 + } + }, { - name = "backup_rule_weekly" - schedule = "cron(0 23 ? * 6 *)" - recovery_point_tags = {} - lifecycle = { - delete_after = 60 - } - }] - -} - - -variable "org_id" { - type = string - description = "organization ID required to enable the conformance pack" - # default = "o-03y3m4pkl8" - default = "" -} - -variable "logging_account" { - description = "Central logging accoutn ID" - type = string - default = "" -} + name = "rds_backup_rule_weekly" + schedule = "cron(0 23 ? * 6 *)" + recovery_point_tags = {} + lifecycle = { + delete_after = 60 + } +}] +} + +# variable "location_vault_map" { +# description = "A map of regions to backup vault ARNs for RDS" +# type = map(string) +# default = { +# "us-east-1" = "arn:aws:backup:${var.location}:${var.backup_account_id}:backup-vault:sascloud-awsng-central-backup-vault-${var.hub_environment}" +# "eu-central-1" = "arn:aws:backup:${var.location}:${var.backup_account_id}:backup-vault:sascloud-awsng-central-backup-vault-${var.hub_environment}" +# "ca-central-1" = "arn:aws:backup:${var.location}:${var.backup_account_id}:backup-vault:sascloud-awsng-central-backup-vault-${var.hub_environment}" +# "eu-west-1" = "arn:aws:backup:${var.location}:${var.backup_account_id}:backup-vault:sascloud-awsng-central-backup-vault-${var.hub_environment}" +# "ap-southeast-1" = "arn:aws:backup:${var.location}:${var.backup_account_id}:backup-vault:sascloud-awsng-central-backup-vault-${var.hub_environment}" +# "ap-northeast-1" = "arn:aws:backup:${var.location}:${var.backup_account_id}:backup-vault:sascloud-awsng-central-backup-vault-${var.hub_environment}" +# "ap-south-1" = "arn:aws:backup:${var.location}:${var.backup_account_id}:backup-vault:sascloud-awsng-central-backup-vault-${var.hub_environment}" +# "eu-west-3" = "arn:aws:backup:${var.location}:${var.backup_account_id}:backup-vault:sascloud-awsng-central-backup-vault-${var.hub_environment}" +# "us-west-1" = "arn:aws:backup:${var.location}:${var.backup_account_id}:backup-vault:sascloud-awsng-central-backup-vault-${var.hub_environment}" +# } +# } + From 34065542d0748135d38c8ea41afdc998acc63a3b Mon Sep 17 00:00:00 2001 From: Deshmukh Date: Thu, 19 Dec 2024 10:32:04 +0530 Subject: [PATCH 33/40] modified th backup module --- main.tf | 5 +- modules/aws_backup/iam_role.tf | 6 +- modules/aws_backup/main.tf | 277 ++++---------------------- modules/aws_backup/variables.tf | 94 ++++++--- modules/aws_s3/main.tf | 6 +- modules/aws_waf/main.tf | 12 +- modules/resource_checker/check_waf.sh | 2 +- variables.tf | 245 +++++++++++++++++------ 8 files changed, 320 insertions(+), 327 deletions(-) diff --git a/main.tf b/main.tf index f538bd3a..927b671f 100755 --- a/main.tf +++ b/main.tf @@ -311,7 +311,7 @@ module "postgresql" { # disable backups to create DB faster backup_retention_period = each.value.backup_retention_days - tags = merge(local.tags, { "Backup" = var.enable_nist_features == true ? "Enabled" : null }) + tags = merge(local.tags, { "RDSBackup" = var.enable_nist_features == true ? "Enabled" : null }) # DB subnet group - use public subnet if public access is requested publicly_accessible = length(local.postgres_public_access_cidrs) > 0 && var.enable_nist_features == false ? true : false @@ -454,6 +454,9 @@ module "spoke_backup" { central_backup_vault_eu = var.central_backup_vault_eu hub_environment = var.hub_environment depends_on = [module.resource_checker] + selection_tag = var.selection_tag + prefix = var.prefix + } diff --git a/modules/aws_backup/iam_role.tf b/modules/aws_backup/iam_role.tf index 352b1614..a47c8582 100644 --- a/modules/aws_backup/iam_role.tf +++ b/modules/aws_backup/iam_role.tf @@ -16,7 +16,7 @@ data "aws_iam_policy_document" "assume_role" { } resource "aws_iam_role" "backup_operator_role" { - name = "sas-awsng-${var.location}-${var.hub_environment}-backup-operator-role" + name = "${var.prefix}-${var.location}-${var.hub_environment}-backup-operator-role" assume_role_policy = data.aws_iam_policy_document.assume_role.json tags = var.tags } @@ -27,7 +27,7 @@ resource "aws_iam_role_policy_attachment" "aws_managed_backup_operator" { } resource "aws_iam_role" "restore_operator_role" { - name = "sas-awsng-${var.location}-${var.hub_environment}-backup-restore-operator-role" + name = "${var.prefix}-${var.location}-${var.hub_environment}-backup-restore-operator-role" assume_role_policy = data.aws_iam_policy_document.assume_role.json tags = var.tags } @@ -46,7 +46,7 @@ data "aws_iam_policy_document" "ec2_pass" { } resource "aws_iam_policy" "ec2_pass_policy" { - name = "sascloud-ec2-pass-policy-${var.hub_environment}-${var.location}" + name = "${var.prefix}-ec2-pass-policy-${var.hub_environment}-${var.location}" policy = data.aws_iam_policy_document.ec2_pass.json } diff --git a/modules/aws_backup/main.tf b/modules/aws_backup/main.tf index 07cf4ce6..386977b8 100644 --- a/modules/aws_backup/main.tf +++ b/modules/aws_backup/main.tf @@ -1,7 +1,7 @@ resource "aws_backup_vault" "spoke" { - name = "sas-awsng-${var.spoke_account_id}-backup-vault" + name = "ng-${var.spoke_account_id}-backup-vault" kms_key_arn = aws_kms_key.spoke_vault_key.arn tags = merge( var.tags, @@ -92,7 +92,7 @@ data "aws_caller_identity" "current" {} resource "aws_backup_framework" "backup_compliance_framework" { depends_on = [ aws_backup_vault.spoke ] - name = "sas_awsng_${var.spoke_account_id}_backup_framework" + name = "ng_backup_framework" description = "This framework validates Recovery Points created by AWS Backup" control { name = "BACKUP_RECOVERY_POINT_MINIMUM_RETENTION_CHECK" @@ -232,166 +232,11 @@ resource "aws_backup_framework" "backup_compliance_framework" { } tags = { - "Name" = "sas-awsng-${var.spoke_account_id}-backup-framework" + "Name" = "${var.prefix}-${var.spoke_account_id}-backup-framework" ManagedBy = "Terraform" } } -# locals { -# location_vault_map = { -# "us-east-1" = "arn:aws:backup:${var.location}:${var.backup_account_id}:backup-vault:sascloud-awsng-central-backup-vault-${var.hub_environment}" -# "eu-central-1" = "arn:aws:backup:${var.location}:${var.backup_account_id}:backup-vault:sascloud-awsng-central-backup-vault-${var.hub_environment}" -# "ca-central-1" = "arn:aws:backup:${var.location}:${var.backup_account_id}:backup-vault:sascloud-awsng-central-backup-vault-${var.hub_environment}" -# "eu-west-1" = "arn:aws:backup:${var.location}:${var.backup_account_id}:backup-vault:sascloud-awsng-central-backup-vault-${var.hub_environment}" -# "ap-southeast-1" = "arn:aws:backup:${var.location}:${var.backup_account_id}:backup-vault:sascloud-awsng-central-backup-vault-${var.hub_environment}" -# "ap-northeast-1" = "arn:aws:backup:${var.location}:${var.backup_account_id}:backup-vault:sascloud-awsng-central-backup-vault-${var.hub_environment}" -# "ap-south-1" = "arn:aws:backup:${var.location}:${var.backup_account_id}:backup-vault:sascloud-awsng-central-backup-vault-${var.hub_environment}" -# "eu-west-3" = "arn:aws:backup:${var.location}:${var.backup_account_id}:backup-vault:sascloud-awsng-central-backup-vault-${var.hub_environment}" -# "us-west-1" = "arn:aws:backup:${var.location}:${var.backup_account_id}:backup-vault:sascloud-awsng-central-backup-vault-${var.hub_environment}" -# } -# } - -# resource "aws_backup_plan" "spoke" { -# name = "sas-awsng-${var.spoke_account_id}-backup-plan" - -# dynamic "rule" { -# for_each = var.spoke_backup_rules -# content { -# rule_name = rule.value.name -# target_vault_name = aws_backup_vault.spoke.name -# schedule = rule.value.schedule -# start_window = rule.value.start_window -# completion_window = rule.value.completion_window -# recovery_point_tags = rule.value.recovery_point_tags -# enable_continuous_backup = rule.value.enable_continuous_backup - -# dynamic "lifecycle" { -# for_each = lookup(rule.value, "lifecycle", null) != null ? [true] : [] -# content { -# cold_storage_after = rule.value.lifecycle.cold_storage_after -# delete_after = rule.value.lifecycle.delete_after -# } -# } - -# # Copy action for EFS -# dynamic "copy_action" { -# for_each = contains(["efs_backup_rule_daily", "efs_backup_rule_weekly"], rule.value.name) ? [true] : [] - -# content { -# destination_vault_arn = var.central_backup_vault_us # Example for US - -# dynamic "selection_tag" { -# for_each = [for t in rule.value.recovery_point_tags : t if t.key == "Backup" && t.value == "efs"] - -# content { -# type = "STRINGEQUALS" -# key = "Backup" -# value = "efs" -# } -# } - -# dynamic "lifecycle" { -# for_each = try(lookup(rule.value.copy_action, "lifecycle", null), null) != null ? [true] : [] - -# content { -# cold_storage_after = rule.value.copy_action.lifecycle.cold_storage_after -# delete_after = rule.value.copy_action.lifecycle.delete_after -# } -# } -# } -# } - -# # Copy action for RDS -# dynamic "copy_action" { -# for_each = contains(["rds_backup_rule_daily", "rds_backup_rule_weekly"], rule.value.name) ? [true] : [] - -# content { -# destination_vault_arn = lookup(local.location_vault_map, var.location, null) - -# dynamic "selection_tag" { -# for_each = [for t in rule.value.recovery_point_tags : t if t.key == "Backup" && t.value == "rds"] - -# content { -# type = "STRINGEQUALS" -# key = "Backup" -# value = "rds" -# } -# } - -# dynamic "lifecycle" { -# for_each = try(lookup(rule.value.copy_action, "lifecycle", null), null) != null ? [true] : [] - -# content { -# cold_storage_after = rule.value.copy_action.lifecycle.cold_storage_after -# delete_after = rule.value.copy_action.lifecycle.delete_after -# } -# } -# } -# } - -# # Copy action for FSx -# dynamic "copy_action" { -# for_each = contains(["fsx_backup_rule_daily", "fsx_backup_rule_weekly"], rule.value.name) ? [true] : [] - -# content { -# destination_vault_arn = var.central_backup_vault_us # Example for US or a different FSx target - -# dynamic "selection_tag" { -# for_each = [for t in rule.value.recovery_point_tags : t if t.key == "Backup" && t.value == "fsx"] - -# content { -# type = "STRINGEQUALS" -# key = "Backup" -# value = "fsx" -# } -# } - -# dynamic "lifecycle" { -# for_each = try(lookup(rule.value.copy_action, "lifecycle", null), null) != null ? [true] : [] - -# content { -# cold_storage_after = rule.value.copy_action.lifecycle.cold_storage_after -# delete_after = rule.value.copy_action.lifecycle.delete_after -# } -# } -# } -# } - -# } -# } - -# dynamic "advanced_backup_setting" { -# for_each = var.advanced_backup_setting != null ? [true] : [] -# content { -# backup_options = var.advanced_backup_setting.backup_options -# resource_type = var.advanced_backup_setting.resource_type -# } -# } - -# tags = merge( -# var.tags, -# { -# Name = "sas-awsng-${var.spoke_account_id}-backup-plan", -# PolicyOwner = "NextGen" -# } -# ) -# } - -# resource "aws_backup_selection" "spoke" { -# iam_role_arn = aws_iam_role.backup_operator_role.arn -# name = "sas-awsng-${var.spoke_account_id}-backup-selection" -# plan_id = aws_backup_plan.spoke.id - -# dynamic "selection_tag" { -# for_each = ["efs", "rds", "fsx"] - -# content { -# type = "STRINGEQUALS" -# key = "Backup" -# value = selection_tag.value -# } -# } -#} locals { location_vault_map = { @@ -406,12 +251,13 @@ locals { "us-west-1" = "arn:aws:backup:${var.location}:${var.backup_account_id}:backup-vault:sascloud-awsng-central-backup-vault-${var.hub_environment}" } } - + resource "aws_backup_plan" "spoke" { - name = "sas-awsng-${var.spoke_account_id}-backup-plan" - + for_each = var.spoke_backup_rules + name = "sas-awsng-${var.spoke_account_id}-backup-plan-${each.key}" + dynamic "rule" { - for_each = var.spoke_backup_rules + for_each = each.value["scope"] content { rule_name = rule.value.name target_vault_name = aws_backup_vault.spoke.name @@ -420,7 +266,7 @@ resource "aws_backup_plan" "spoke" { completion_window = rule.value.completion_window recovery_point_tags = rule.value.recovery_point_tags enable_continuous_backup = rule.value.enable_continuous_backup - + dynamic "lifecycle" { for_each = lookup(rule.value, "lifecycle", null) != null ? [true] : [] content { @@ -428,71 +274,34 @@ resource "aws_backup_plan" "spoke" { delete_after = rule.value.lifecycle.delete_after } } - - # Apply copy action for EFS to US vault - dynamic "copy_action" { - for_each = contains(["efs_backup_rule_daily", "efs_backup_rule_weekly"], rule.value.name) ? [true] : [] - - content { - destination_vault_arn = var.central_backup_vault_us - - dynamic "lifecycle" { - for_each = try(lookup(rule.value.copy_action, "lifecycle", null), null) != null ? [true] : [] - - content { - cold_storage_after = rule.value.copy_action.lifecycle.cold_storage_after - delete_after = rule.value.copy_action.lifecycle.delete_after - } - } - } - } - - # Apply copy action for EFS to EU vault - dynamic "copy_action" { - for_each = contains(["efs_backup_rule_daily", "efs_backup_rule_weekly"], rule.value.name) ? [true] : [] - - content { - destination_vault_arn = var.central_backup_vault_eu - - dynamic "lifecycle" { - for_each = try(lookup(rule.value.copy_action, "lifecycle", null), null) != null ? [true] : [] - - content { - cold_storage_after = rule.value.copy_action.lifecycle.cold_storage_after - delete_after = rule.value.copy_action.lifecycle.delete_after - } + + # Apply copy action for all except RDS to US vault + copy_action { + destination_vault_arn = strcontains(each.key, "spoke") ? var.central_backup_vault_us : lookup(local.location_vault_map, var.location, null) + dynamic "lifecycle" { + for_each = try(lookup(rule.value.copy_action, "lifecycle", null), null) != null ? [true] : [] + content { + cold_storage_after = rule.value.copy_action.lifecycle.cold_storage_after + delete_after = rule.value.copy_action.lifecycle.delete_after } } } - - # Apply region-based copy action for RDS - dynamic "copy_action" { - for_each = contains(["rds_backup_rule_daily", "rds_backup_rule_weekly"], rule.value.name) ? [true] : [] - - content { - destination_vault_arn = lookup(local.location_vault_map, var.location, null) - - dynamic "lifecycle" { - for_each = try(lookup(rule.value.copy_action, "lifecycle", null), null) != null ? [true] : [] - - content { - cold_storage_after = rule.value.copy_action.lifecycle.cold_storage_after - delete_after = rule.value.copy_action.lifecycle.delete_after - } + + # Apply copy action for all except RDS to EU vault + copy_action { + destination_vault_arn = strcontains(each.key, "spoke") ? var.central_backup_vault_eu : lookup(local.location_vault_map, var.location, null) + dynamic "lifecycle" { + for_each = try(lookup(rule.value.copy_action, "lifecycle", null), null) != null ? [true] : [] + content { + cold_storage_after = rule.value.copy_action.lifecycle.cold_storage_after + delete_after = rule.value.copy_action.lifecycle.delete_after } } } - - # # No copy action for FSx - # dynamic "copy_action" { - # for_each = contains(rule.value.name, "fsx") ? [] : [true] - # content { - # destination_vault_arn = aws_backup_vault.spoke.arn - # } - # } } } - + + dynamic "advanced_backup_setting" { for_each = var.advanced_backup_setting != null ? [true] : [] content { @@ -500,28 +309,30 @@ resource "aws_backup_plan" "spoke" { resource_type = var.advanced_backup_setting.resource_type } } - + tags = merge( var.tags, { - Name = "sas-awsng-${var.spoke_account_id}-backup-plan", + Name = "sas-awsng-${var.spoke_account_id}-backup-plan-${each.key}", PolicyOwner = "NextGen" } ) } - -resource "aws_backup_selection" "spoke" { + +resource "aws_backup_selection" "sasng" { + for_each = var.selection_tag iam_role_arn = aws_iam_role.backup_operator_role.arn - name = "sas-awsng-${var.spoke_account_id}-backup-selection" - plan_id = aws_backup_plan.spoke.id - - selection_tag { - type = "STRINGEQUALS" - key = "Backup" - value = "Enabled" + name = "sas-awsng-${var.spoke_account_id}-backup-selection-${each.key}" + plan_id = strcontains(each.key, "spoke") ? aws_backup_plan.spoke["spoke"].id : aws_backup_plan.spoke["rds"].id + + dynamic "selection_tag" { + for_each = strcontains(each.key, "spoke") || strcontains(each.key, "rds") ? each.value.name : [] + content { + type = selection_tag.value.type + key = selection_tag.value.key + value = selection_tag.value.value + } } } - - diff --git a/modules/aws_backup/variables.tf b/modules/aws_backup/variables.tf index 9c4ccb10..bbf4893a 100644 --- a/modules/aws_backup/variables.tf +++ b/modules/aws_backup/variables.tf @@ -45,32 +45,32 @@ variable "tags" { } -variable "spoke_backup_rules" { - description = "AWS Spoke Backup Rules data structure" - type = list(object({ - name = string - schedule = optional(string) - enable_continuous_backup = optional(bool) - start_window = optional(number) - completion_window = optional(number) - recovery_point_tags = optional(map(string)) - lifecycle = optional(object({ - cold_storage_after = optional(number) - delete_after = optional(number) - opt_in_to_archive_for_supported_resources = optional(bool) - })) - copy_action = optional(object({ - destination_vault_arn = optional(string) - lifecycle = optional(object({ - cold_storage_after = optional(number) - delete_after = optional(number) - opt_in_to_archive_for_supported_resources = optional(bool) - })) - })) - })) +# variable "spoke_backup_rules" { +# description = "AWS Spoke Backup Rules data structure" +# type = list(object({ +# name = string +# schedule = optional(string) +# enable_continuous_backup = optional(bool) +# start_window = optional(number) +# completion_window = optional(number) +# recovery_point_tags = optional(map(string)) +# lifecycle = optional(object({ +# cold_storage_after = optional(number) +# delete_after = optional(number) +# opt_in_to_archive_for_supported_resources = optional(bool) +# })) +# copy_action = optional(object({ +# destination_vault_arn = optional(string) +# lifecycle = optional(object({ +# cold_storage_after = optional(number) +# delete_after = optional(number) +# opt_in_to_archive_for_supported_resources = optional(bool) +# })) +# })) +# })) -} +# } variable "advanced_backup_setting" { description = "AWS backup options" @@ -120,3 +120,49 @@ variable "hub_environment" { # } # } +variable "selection_tag" { + type = map(object({ + name = list(object({ + type = string + key = string + value = string + })) + })) +} + +variable "prefix" { + description = "A prefix used in the name for all cloud resources created by this script. The prefix string must start with a lowercase letter and contain only alphanumeric characters and hyphens or dashes (-), but cannot start or end with '-'." + type = string + + validation { + condition = can(regex("^[a-z][-0-9a-z]*[0-9a-z]$", var.prefix)) + error_message = "ERROR: Value of 'prefix'\n * must start with lowercase letter\n * can only contain lowercase letters, numbers, hyphens, or dashes (-), but cannot start or end with '-'." + } +} + +variable "spoke_backup_rules" { + description = "Backup control rules: Schedule indicates the time frame of backup" + type = map(object({ + scope = list(object({ + name = string + schedule = optional(string) + enable_continuous_backup = optional(bool) + start_window = optional(number) + completion_window = optional(number) + recovery_point_tags = optional(map(string)) + lifecycle = optional(object({ + cold_storage_after = optional(number) + delete_after = optional(number) + opt_in_to_archive_for_supported_resources = optional(bool) + })) + copy_action = optional(object({ + destination_vault_arn = optional(string) + lifecycle = optional(object({ + cold_storage_after = optional(number) + delete_after = optional(number) + opt_in_to_archive_for_supported_resources = optional(bool) + })) + })) + })) + })) +} diff --git a/modules/aws_s3/main.tf b/modules/aws_s3/main.tf index c42cd187..76df7c6c 100644 --- a/modules/aws_s3/main.tf +++ b/modules/aws_s3/main.tf @@ -82,7 +82,7 @@ data "aws_iam_policy_document" "assume_role_local" { } } resource "aws_iam_role" "replication_role_local" { - name = "sas-awsng-${var.location}-${var.hub_environment}-replication-role" + name = "replication-role-${var.location}-${var.hub_environment}" assume_role_policy = data.aws_iam_policy_document.assume_role_local.json tags = var.tags } @@ -193,7 +193,7 @@ resource "aws_s3_bucket_policy" "allow_access_from_another_account" { EOF } resource "aws_iam_policy" "replication_policy_local" { - name = "sas-awsng-${var.location}-${var.hub_environment}-replication-policy" + name = "replication-policy${var.location}-${var.hub_environment}" policy = data.aws_iam_policy_document.replication_json.json tags = var.tags } @@ -215,7 +215,7 @@ resource "aws_s3_bucket_replication_configuration" "replication_local_config" { status = "Disabled" } destination { - account = 730335345263 + account = var.logging_account access_control_translation { owner = "Destination" } diff --git a/modules/aws_waf/main.tf b/modules/aws_waf/main.tf index 165633cf..84872686 100644 --- a/modules/aws_waf/main.tf +++ b/modules/aws_waf/main.tf @@ -12,7 +12,7 @@ resource "aws_wafv2_web_acl" "waf" { sampled_requests_enabled = true } rule { - name = "sas-awsng-BotControlRule" + name = "iac-awsng-BotControlRule" priority = 1 statement { managed_rule_group_statement { @@ -31,7 +31,7 @@ resource "aws_wafv2_web_acl" "waf" { } } rule { - name = "sas-awsng-GeoRestrictionRule" + name = "iac-awsng-GeoRestrictionRule" priority = 2 action { block {} @@ -48,7 +48,7 @@ resource "aws_wafv2_web_acl" "waf" { } } rule { - name = "sas-awsng-CoreRule" + name = "iac-awsng-CoreRule" priority = 3 statement { managed_rule_group_statement { @@ -68,7 +68,7 @@ resource "aws_wafv2_web_acl" "waf" { # # AWS Managed IP Reputation List rule { - name = "sas-awsng-IpReputationList" + name = "iac-awsng-IpReputationList" priority = 4 statement { managed_rule_group_statement { @@ -88,7 +88,7 @@ resource "aws_wafv2_web_acl" "waf" { # Known Bad Inputs rule { - name = "sas-awsng-Bad-Inputs-Rule" + name = "iac-awsng-Bad-Inputs-Rule" priority = 5 statement { managed_rule_group_statement { @@ -107,7 +107,7 @@ resource "aws_wafv2_web_acl" "waf" { } tags = merge( { - "Name" = format("%s", "sas-awsng-${var.spoke_account_id}-acl") + "Name" = format("%s", "iac-awsng-${var.spoke_account_id}-acl") }, var.tags ) diff --git a/modules/resource_checker/check_waf.sh b/modules/resource_checker/check_waf.sh index dd3e3d50..195d5a11 100644 --- a/modules/resource_checker/check_waf.sh +++ b/modules/resource_checker/check_waf.sh @@ -6,7 +6,7 @@ export AWS_ACCESS_KEY_ID=$3 export AWS_SECRET_ACCESS_KEY=$4 export AWS_SESSION_TOKEN=$5 -WAF_NAME="sas-awsng-${spoke_account_id}-acl" +WAF_NAME="iac-awsng-${spoke_account_id}-acl" RETRY_COUNT=3 # Number of retries RETRY_DELAY=3 # Delay in seconds between retries # Function to check the existence of WAF diff --git a/variables.tf b/variables.tf index f2d41864..98b882dd 100644 --- a/variables.tf +++ b/variables.tf @@ -881,62 +881,62 @@ variable "logging_account" { default = "" } -variable "spoke_backup_rules" { - description = "Backup control rules: Schedule indicates the time frame of backup" - type = list(object({ - name = string - schedule = optional(string) - enable_continuous_backup = optional(bool) - start_window = optional(number) - completion_window = optional(number) - recovery_point_tags = optional(map(string)) - lifecycle = optional(object({ - cold_storage_after = optional(number) - delete_after = optional(number) - opt_in_to_archive_for_supported_resources = optional(bool) - })) - copy_action = optional(object({ - destination_vault_arn = optional(string) - lifecycle = optional(object({ - cold_storage_after = optional(number) - delete_after = optional(number) - opt_in_to_archive_for_supported_resources = optional(bool) - })) - })) - })) - default = [{ - name = "efs_backup_rule_daily" - schedule = "cron(0 23 ? * 1-5,7 *)" - recovery_point_tags = {} - lifecycle = { - delete_after = 14 - } - }, - { - name = "efs_backup_rule_weekly" - schedule = "cron(0 23 ? * 6 *)" - recovery_point_tags = {} - lifecycle = { - delete_after = 60 - } - }, - { - name = "rds_backup_rule_daily" - schedule = "cron(0 23 ? * 1-5,7 *)" - recovery_point_tags = {} - lifecycle = { - delete_after = 60 - } - }, - { - name = "rds_backup_rule_weekly" - schedule = "cron(0 23 ? * 6 *)" - recovery_point_tags = {} - lifecycle = { - delete_after = 60 - } -}] -} +# variable "spoke_backup_rules" { +# description = "Backup control rules: Schedule indicates the time frame of backup" +# type = list(object({ +# name = string +# schedule = optional(string) +# enable_continuous_backup = optional(bool) +# start_window = optional(number) +# completion_window = optional(number) +# recovery_point_tags = optional(map(string)) +# lifecycle = optional(object({ +# cold_storage_after = optional(number) +# delete_after = optional(number) +# opt_in_to_archive_for_supported_resources = optional(bool) +# })) +# copy_action = optional(object({ +# destination_vault_arn = optional(string) +# lifecycle = optional(object({ +# cold_storage_after = optional(number) +# delete_after = optional(number) +# opt_in_to_archive_for_supported_resources = optional(bool) +# })) +# })) +# })) +# default = [{ +# name = "efs_backup_rule_daily" +# schedule = "cron(0 23 ? * 1-5,7 *)" +# recovery_point_tags = {} +# lifecycle = { +# delete_after = 14 +# } +# }, +# { +# name = "efs_backup_rule_weekly" +# schedule = "cron(0 23 ? * 6 *)" +# recovery_point_tags = {} +# lifecycle = { +# delete_after = 60 +# } +# }, +# { +# name = "rds_backup_rule_daily" +# schedule = "cron(0 23 ? * 1-5,7 *)" +# recovery_point_tags = {} +# lifecycle = { +# delete_after = 60 +# } +# }, +# { +# name = "rds_backup_rule_weekly" +# schedule = "cron(0 23 ? * 6 *)" +# recovery_point_tags = {} +# lifecycle = { +# delete_after = 60 +# } +# }] +# } # variable "location_vault_map" { # description = "A map of regions to backup vault ARNs for RDS" @@ -955,5 +955,138 @@ variable "spoke_backup_rules" { # } +variable "selection_tag" { + type = map(object({ + name = list(object({ + type = string + key = string + value = string + })) + })) + default = { + spoke = { + name = [{ + type = "STRINGEQUALS" + key = "Backup" + value = "Enabled" + }] + } + rds = { + name = [{ + type = "STRINGEQUALS" + key = "RDSBackup" + value = "Enabled" + }] + } } +} +# variable "spoke_backup_rules" { +# description = "Backup control rules: Schedule indicates the time frame of backup" +# type = list(object({ +# name = string +# schedule = optional(string) +# enable_continuous_backup = optional(bool) +# start_window = optional(number) +# completion_window = optional(number) +# recovery_point_tags = optional(map(string)) +# lifecycle = optional(object({ +# cold_storage_after = optional(number) +# delete_after = optional(number) +# opt_in_to_archive_for_supported_resources = optional(bool) +# })) +# copy_action = optional(object({ +# destination_vault_arn = optional(string) +# lifecycle = optional(object({ +# cold_storage_after = optional(number) +# delete_after = optional(number) +# opt_in_to_archive_for_supported_resources = optional(bool) +# })) +# })) +# })) +# default = [{ +# name = "backup_rule_daily" +# schedule = "cron(0 23 ? * 1-5,7 *)" +# recovery_point_tags = {} +# lifecycle = { +# delete_after = 14 +# } +# }, +# { +# name = "backup_rule_weekly" +# schedule = "cron(0 23 ? * 6 *)" +# recovery_point_tags = {} +# lifecycle = { +# delete_after = 60 +# } +# }] +# } + + +variable "spoke_backup_rules" { + description = "Backup control rules: Schedule indicates the time frame of backup" + type = map(object({ + scope = list(object({ + name = string + schedule = optional(string) + enable_continuous_backup = optional(bool) + start_window = optional(number) + completion_window = optional(number) + recovery_point_tags = optional(map(string)) + lifecycle = optional(object({ + cold_storage_after = optional(number) + delete_after = optional(number) + opt_in_to_archive_for_supported_resources = optional(bool) + })) + copy_action = optional(object({ + destination_vault_arn = optional(string) + lifecycle = optional(object({ + cold_storage_after = optional(number) + delete_after = optional(number) + opt_in_to_archive_for_supported_resources = optional(bool) + })) + })) + })) + })) + default = { + spoke = { + scope = [{ + name = "backup_rule_daily" + schedule = "cron(0 23 ? * 1-5,7 *)" + recovery_point_tags = {} + lifecycle = { + delete_after = 14 + } + }, + { + name = "backup_rule_weekly" + schedule = "cron(0 23 ? * 6 *)" + recovery_point_tags = {} + lifecycle = { + delete_after = 60 + } + } + ] + } + rds = { + scope = [{ + name = "backup_rule_daily" + schedule = "cron(0 23 ? * 1-5,7 *)" + recovery_point_tags = {} + lifecycle = { + delete_after = 14 + } + }, + { + name = "backup_rule_weekly" + schedule = "cron(0 23 ? * 6 *)" + recovery_point_tags = {} + lifecycle = { + delete_after = 60 + } + } + ] + } + } +} + From e1b7c87a22d72e6f660b15bd58be04ee69984655 Mon Sep 17 00:00:00 2001 From: Deshmukh Date: Thu, 19 Dec 2024 10:34:34 +0530 Subject: [PATCH 34/40] changed the IAM external analyser naming to eliminate sas-awsng --- modules/aws_iam_analyzer/main.tf | 8 ++++---- modules/resource_checker/analyzer_checker.sh | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/modules/aws_iam_analyzer/main.tf b/modules/aws_iam_analyzer/main.tf index 95ec3a63..f8a6e56c 100644 --- a/modules/aws_iam_analyzer/main.tf +++ b/modules/aws_iam_analyzer/main.tf @@ -1,13 +1,13 @@ # AWS IAM Access Analyzer External resource "aws_accessanalyzer_analyzer" "aws_access_analyzer_external" { - analyzer_name = "sas-awsng-accessanalyzer-ext-${var.location}" + analyzer_name = "nextgen-accessanalyzer-ext-${var.location}" type = var.analyzer_type_external tags = var.tags } # AWS IAM Access Analyzer Unused resource "aws_accessanalyzer_analyzer" "aws_access_analyzer_unused" { - analyzer_name = "sas-awsng-accessanalyzer-unused-${var.location}" + analyzer_name = "nextgen-accessanalyzer-unused-${var.location}" type = var.analyzer_type_unused configuration { unused_access { @@ -19,7 +19,7 @@ resource "aws_accessanalyzer_analyzer" "aws_access_analyzer_unused" { # IAM Role for Access Analyzer resource "aws_iam_role" "access_analyzer_role" { - name = "sas-awsng-iam-analyzer-${var.location}-role" + name = "nextgen-iam-analyzer-${var.location}-role" assume_role_policy = jsonencode({ Version = "2012-10-17", Statement = [{ @@ -35,7 +35,7 @@ resource "aws_iam_role" "access_analyzer_role" { # IAM Policy for Access Analyzer resource "aws_iam_policy" "access_analyzer_policy" { - name = "sas-awsng-iam-analyzer-${var.location}-policy" + name = "nextgen-iam-analyzer-${var.location}-policy" description = "IAM policy for Access Analyzer" policy = jsonencode({ diff --git a/modules/resource_checker/analyzer_checker.sh b/modules/resource_checker/analyzer_checker.sh index 3daf9539..00f6e944 100644 --- a/modules/resource_checker/analyzer_checker.sh +++ b/modules/resource_checker/analyzer_checker.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash set -e location=$1 -ANALYZER_NAME="sas-awsng-accessanalyzer-ext-$location" +ANALYZER_NAME="nextgen-accessanalyzer-ext-$location" export AWS_ACCESS_KEY_ID=$2 export AWS_SECRET_ACCESS_KEY=$3 export AWS_SESSION_TOKEN=$4 From d84075b89fb81d448768c8aed911effe00813f5a Mon Sep 17 00:00:00 2001 From: Deshmukh Date: Thu, 19 Dec 2024 10:35:21 +0530 Subject: [PATCH 35/40] changed the WAF rules naming to eliminate sas-awsng --- modules/aws_waf/main.tf | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/modules/aws_waf/main.tf b/modules/aws_waf/main.tf index 84872686..12756e6a 100644 --- a/modules/aws_waf/main.tf +++ b/modules/aws_waf/main.tf @@ -12,7 +12,7 @@ resource "aws_wafv2_web_acl" "waf" { sampled_requests_enabled = true } rule { - name = "iac-awsng-BotControlRule" + name = "nextgen-awsng-BotControlRule" priority = 1 statement { managed_rule_group_statement { @@ -31,7 +31,7 @@ resource "aws_wafv2_web_acl" "waf" { } } rule { - name = "iac-awsng-GeoRestrictionRule" + name = "nextgen-awsng-GeoRestrictionRule" priority = 2 action { block {} @@ -48,7 +48,7 @@ resource "aws_wafv2_web_acl" "waf" { } } rule { - name = "iac-awsng-CoreRule" + name = "nextgen-awsng-CoreRule" priority = 3 statement { managed_rule_group_statement { @@ -68,7 +68,7 @@ resource "aws_wafv2_web_acl" "waf" { # # AWS Managed IP Reputation List rule { - name = "iac-awsng-IpReputationList" + name = "nextgen-awsng-IpReputationList" priority = 4 statement { managed_rule_group_statement { @@ -88,7 +88,7 @@ resource "aws_wafv2_web_acl" "waf" { # Known Bad Inputs rule { - name = "iac-awsng-Bad-Inputs-Rule" + name = "nextgen-awsng-Bad-Inputs-Rule" priority = 5 statement { managed_rule_group_statement { @@ -107,7 +107,7 @@ resource "aws_wafv2_web_acl" "waf" { } tags = merge( { - "Name" = format("%s", "iac-awsng-${var.spoke_account_id}-acl") + "Name" = format("%s", "nextgen-awsng-${var.spoke_account_id}-acl") }, var.tags ) From 4960518af4dc695e07ec38e355e7f8d26fe37455 Mon Sep 17 00:00:00 2001 From: Deshmukh Date: Thu, 19 Dec 2024 16:10:13 +0530 Subject: [PATCH 36/40] cleaned up the backup module --- modules/aws_backup/variables.tf | 54 +---------- variables.tf | 158 +------------------------------- 2 files changed, 7 insertions(+), 205 deletions(-) diff --git a/modules/aws_backup/variables.tf b/modules/aws_backup/variables.tf index bbf4893a..ee4e3e8d 100644 --- a/modules/aws_backup/variables.tf +++ b/modules/aws_backup/variables.tf @@ -28,10 +28,6 @@ variable "location" { type = string } -# variable "environment" { -# description = "Environment" -# type = string -# } variable "org_id" { description = "AWS organization id" @@ -45,33 +41,8 @@ variable "tags" { } -# variable "spoke_backup_rules" { -# description = "AWS Spoke Backup Rules data structure" -# type = list(object({ -# name = string -# schedule = optional(string) -# enable_continuous_backup = optional(bool) -# start_window = optional(number) -# completion_window = optional(number) -# recovery_point_tags = optional(map(string)) -# lifecycle = optional(object({ -# cold_storage_after = optional(number) -# delete_after = optional(number) -# opt_in_to_archive_for_supported_resources = optional(bool) -# })) -# copy_action = optional(object({ -# destination_vault_arn = optional(string) -# lifecycle = optional(object({ -# cold_storage_after = optional(number) -# delete_after = optional(number) -# opt_in_to_archive_for_supported_resources = optional(bool) -# })) -# })) -# })) -# } - variable "advanced_backup_setting" { description = "AWS backup options" type = object({ @@ -83,11 +54,11 @@ variable "advanced_backup_setting" { -# variable "backup_external" { -# type = string -# default = "true" -# description = "Result from resource checker module" -# } +variable "backup_external" { + type = string + default = "true" + description = "Result from resource checker module" +} variable "spoke_account_id" { description = "spoke account id for s3 deployment" @@ -104,21 +75,6 @@ variable "hub_environment" { type = string } -# variable "location_vault_map" { -# description = "A map of regions to backup vault ARNs for RDS" -# type = map(string) -# default = { -# "us-east-1" = "arn:aws:backup:${local.region}:${var.backup_account_id}:backup-vault:sascloud-awsng-central-backup-vault-${var.hub_environment}" -# "eu-central-1" = "arn:aws:backup:${var.location}:${var.backup_account_id}:backup-vault:sascloud-awsng-central-backup-vault-${var.hub_environment}" -# "ca-central-1" = "arn:aws:backup:${var.location}:${var.backup_account_id}:backup-vault:sascloud-awsng-central-backup-vault-${var.hub_environment}" -# "eu-west-1" = "arn:aws:backup:${var.location}:${var.backup_account_id}:backup-vault:sascloud-awsng-central-backup-vault-${var.hub_environment}" -# "ap-southeast-1" = "arn:aws:backup:${var.location}:${var.backup_account_id}:backup-vault:sascloud-awsng-central-backup-vault-${var.hub_environment}" -# "ap-northeast-1" = "arn:aws:backup:${var.location}:${var.backup_account_id}:backup-vault:sascloud-awsng-central-backup-vault-${var.hub_environment}" -# "ap-south-1" = "arn:aws:backup:${var.location}:${var.backup_account_id}:backup-vault:sascloud-awsng-central-backup-vault-${var.hub_environment}" -# "eu-west-3" = "arn:aws:backup:${var.location}:${var.backup_account_id}:backup-vault:sascloud-awsng-central-backup-vault-${var.hub_environment}" -# "us-west-1" = "arn:aws:backup:${var.location}:${var.backup_account_id}:backup-vault:sascloud-awsng-central-backup-vault-${var.hub_environment}" -# } -# } variable "selection_tag" { type = map(object({ diff --git a/variables.tf b/variables.tf index 98b882dd..0a965fa4 100644 --- a/variables.tf +++ b/variables.tf @@ -825,48 +825,6 @@ variable "central_backup_vault_eu" { default = "" } -# variable "spoke_backup_rules" { -# description = "Backup control rules: Schedule indicates the time frame of backup" -# type = list(object({ -# name = string -# schedule = optional(string) -# enable_continuous_backup = optional(bool) -# start_window = optional(number) -# completion_window = optional(number) -# recovery_point_tags = optional(map(string)) -# lifecycle = optional(object({ -# cold_storage_after = optional(number) -# delete_after = optional(number) -# opt_in_to_archive_for_supported_resources = optional(bool) -# })) -# copy_action = optional(object({ -# destination_vault_arn = optional(string) -# lifecycle = optional(object({ -# cold_storage_after = optional(number) -# delete_after = optional(number) -# opt_in_to_archive_for_supported_resources = optional(bool) -# })) -# })) -# })) -# default = [{ -# name = "backup_rule_daily" -# schedule = "cron(0 23 ? * 1-5,7 *)" -# recovery_point_tags = {} -# lifecycle = { -# delete_after = 14 -# } -# }, -# { -# name = "backup_rule_weekly" -# schedule = "cron(0 23 ? * 6 *)" -# recovery_point_tags = {} -# lifecycle = { -# delete_after = 60 -# } -# }] - -# } - variable "org_id" { type = string @@ -881,79 +839,8 @@ variable "logging_account" { default = "" } -# variable "spoke_backup_rules" { -# description = "Backup control rules: Schedule indicates the time frame of backup" -# type = list(object({ -# name = string -# schedule = optional(string) -# enable_continuous_backup = optional(bool) -# start_window = optional(number) -# completion_window = optional(number) -# recovery_point_tags = optional(map(string)) -# lifecycle = optional(object({ -# cold_storage_after = optional(number) -# delete_after = optional(number) -# opt_in_to_archive_for_supported_resources = optional(bool) -# })) -# copy_action = optional(object({ -# destination_vault_arn = optional(string) -# lifecycle = optional(object({ -# cold_storage_after = optional(number) -# delete_after = optional(number) -# opt_in_to_archive_for_supported_resources = optional(bool) -# })) -# })) -# })) -# default = [{ -# name = "efs_backup_rule_daily" -# schedule = "cron(0 23 ? * 1-5,7 *)" -# recovery_point_tags = {} -# lifecycle = { -# delete_after = 14 -# } -# }, -# { -# name = "efs_backup_rule_weekly" -# schedule = "cron(0 23 ? * 6 *)" -# recovery_point_tags = {} -# lifecycle = { -# delete_after = 60 -# } -# }, -# { -# name = "rds_backup_rule_daily" -# schedule = "cron(0 23 ? * 1-5,7 *)" -# recovery_point_tags = {} -# lifecycle = { -# delete_after = 60 -# } -# }, -# { -# name = "rds_backup_rule_weekly" -# schedule = "cron(0 23 ? * 6 *)" -# recovery_point_tags = {} -# lifecycle = { -# delete_after = 60 -# } -# }] -# } - -# variable "location_vault_map" { -# description = "A map of regions to backup vault ARNs for RDS" -# type = map(string) -# default = { -# "us-east-1" = "arn:aws:backup:${var.location}:${var.backup_account_id}:backup-vault:sascloud-awsng-central-backup-vault-${var.hub_environment}" -# "eu-central-1" = "arn:aws:backup:${var.location}:${var.backup_account_id}:backup-vault:sascloud-awsng-central-backup-vault-${var.hub_environment}" -# "ca-central-1" = "arn:aws:backup:${var.location}:${var.backup_account_id}:backup-vault:sascloud-awsng-central-backup-vault-${var.hub_environment}" -# "eu-west-1" = "arn:aws:backup:${var.location}:${var.backup_account_id}:backup-vault:sascloud-awsng-central-backup-vault-${var.hub_environment}" -# "ap-southeast-1" = "arn:aws:backup:${var.location}:${var.backup_account_id}:backup-vault:sascloud-awsng-central-backup-vault-${var.hub_environment}" -# "ap-northeast-1" = "arn:aws:backup:${var.location}:${var.backup_account_id}:backup-vault:sascloud-awsng-central-backup-vault-${var.hub_environment}" -# "ap-south-1" = "arn:aws:backup:${var.location}:${var.backup_account_id}:backup-vault:sascloud-awsng-central-backup-vault-${var.hub_environment}" -# "eu-west-3" = "arn:aws:backup:${var.location}:${var.backup_account_id}:backup-vault:sascloud-awsng-central-backup-vault-${var.hub_environment}" -# "us-west-1" = "arn:aws:backup:${var.location}:${var.backup_account_id}:backup-vault:sascloud-awsng-central-backup-vault-${var.hub_environment}" -# } -# } - + + variable "selection_tag" { type = map(object({ @@ -979,47 +866,6 @@ variable "selection_tag" { }] } } } -# variable "spoke_backup_rules" { -# description = "Backup control rules: Schedule indicates the time frame of backup" -# type = list(object({ -# name = string -# schedule = optional(string) -# enable_continuous_backup = optional(bool) -# start_window = optional(number) -# completion_window = optional(number) -# recovery_point_tags = optional(map(string)) -# lifecycle = optional(object({ -# cold_storage_after = optional(number) -# delete_after = optional(number) -# opt_in_to_archive_for_supported_resources = optional(bool) -# })) -# copy_action = optional(object({ -# destination_vault_arn = optional(string) -# lifecycle = optional(object({ -# cold_storage_after = optional(number) -# delete_after = optional(number) -# opt_in_to_archive_for_supported_resources = optional(bool) -# })) -# })) -# })) -# default = [{ -# name = "backup_rule_daily" -# schedule = "cron(0 23 ? * 1-5,7 *)" -# recovery_point_tags = {} -# lifecycle = { -# delete_after = 14 -# } -# }, -# { -# name = "backup_rule_weekly" -# schedule = "cron(0 23 ? * 6 *)" -# recovery_point_tags = {} -# lifecycle = { -# delete_after = 60 -# } -# }] -# } - variable "spoke_backup_rules" { description = "Backup control rules: Schedule indicates the time frame of backup" From d584859749857e0b67ffa8f722c1c0098a00471d Mon Sep 17 00:00:00 2001 From: Deshmukh Date: Thu, 19 Dec 2024 16:16:52 +0530 Subject: [PATCH 37/40] added comments on backup module --- modules/aws_backup/iam_role.tf | 1 + modules/aws_backup/main.tf | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/modules/aws_backup/iam_role.tf b/modules/aws_backup/iam_role.tf index a47c8582..5177560f 100644 --- a/modules/aws_backup/iam_role.tf +++ b/modules/aws_backup/iam_role.tf @@ -15,6 +15,7 @@ data "aws_iam_policy_document" "assume_role" { } } +#### IAM rle for backup #### resource "aws_iam_role" "backup_operator_role" { name = "${var.prefix}-${var.location}-${var.hub_environment}-backup-operator-role" assume_role_policy = data.aws_iam_policy_document.assume_role.json diff --git a/modules/aws_backup/main.tf b/modules/aws_backup/main.tf index 386977b8..b4d91134 100644 --- a/modules/aws_backup/main.tf +++ b/modules/aws_backup/main.tf @@ -1,5 +1,5 @@ - +### backup valut creation ### resource "aws_backup_vault" "spoke" { name = "ng-${var.spoke_account_id}-backup-vault" kms_key_arn = aws_kms_key.spoke_vault_key.arn @@ -20,6 +20,8 @@ resource "aws_backup_vault_lock_configuration" "spoke" { depends_on = [aws_backup_vault.spoke] } + +### Vault policy and controls ### resource "aws_backup_vault_policy" "spoke" { backup_vault_name = aws_backup_vault.spoke.name depends_on = [aws_backup_vault.spoke, aws_iam_role.restore_operator_role, aws_iam_role.backup_operator_role] @@ -89,7 +91,7 @@ EOF data "aws_caller_identity" "current" {} - +### Backup framework ### resource "aws_backup_framework" "backup_compliance_framework" { depends_on = [ aws_backup_vault.spoke ] name = "ng_backup_framework" From ea9afa00b2933f788b61d1d466c20e75a4f89d6b Mon Sep 17 00:00:00 2001 From: Deshmukh Date: Thu, 19 Dec 2024 16:18:29 +0530 Subject: [PATCH 38/40] modified sample tfvars file --- examples/sample-input-nist.tfvars | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/examples/sample-input-nist.tfvars b/examples/sample-input-nist.tfvars index 62810a7d..0e723bab 100644 --- a/examples/sample-input-nist.tfvars +++ b/examples/sample-input-nist.tfvars @@ -14,26 +14,26 @@ location = "us-east-1" # e.g., "us-east-1" #***************** CIDR Range for Spoke VPC ************** vpc_cidr = "10.80.16.0/22" -hub = "CustomerSpokeUS" -hub_environment = "prod" # dev or prod +hub = "" +hub_environment = "" # dev or prod - org_id = "o-03y3m4pkl8" - central_restore_operator = "arn:aws:iam::992382826079:role/sascloud-awsng-central-restore-iam-role-prod" - central_backup_operator = "arn:aws:iam::992382826079:role/sascloud-awsng-central-backup-iam-role-prod" - central_backup_vault_us = "arn:aws:backup:us-east-1:992382826079:backup-vault:sascloud-awsng-central-backup-vault-prod" - central_backup_vault_eu = "arn:aws:backup:eu-central-1:992382826079:backup-vault:sascloud-awsng-central-backup-vault-prod" - central_logging_bucket = "arn:aws:s3:::sascloud-awsng-centralized-prod-logging-bkt" - core_network_id = "core-network-0f5411afa03340169" - core_network_arn = "arn:aws:networkmanager::396608809900:core-network/core-network-0f5411afa03340169" + org_id = "" + central_restore_operator = "arn:aws:iam:::role/" + central_backup_operator = "arn:aws:iam:::role/" + central_backup_vault_us = "arn:aws:iam:::role/" + central_backup_vault_eu = "arn:aws:iam:::role/" + central_logging_bucket = "" + core_network_id = "" + core_network_arn = "" # ********* Set to true to enable NIST complaint code *********** enable_nist_features = true -backup_account_id = "992382826079" -logging_account = "730335345263" +backup_account_id = "" +logging_account = "" #***************** Additional CIDR ranges for Spoke VPC ************* From 57809ed5a30d9d8e218c5c4ce3650b48cbfa81fe Mon Sep 17 00:00:00 2001 From: Deshmukh Date: Tue, 24 Dec 2024 19:05:17 +0530 Subject: [PATCH 39/40] updated the vault name --- modules/aws_backup/main.tf | 2 +- modules/resource_checker/main.tf | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/aws_backup/main.tf b/modules/aws_backup/main.tf index b4d91134..dee96578 100644 --- a/modules/aws_backup/main.tf +++ b/modules/aws_backup/main.tf @@ -6,7 +6,7 @@ resource "aws_backup_vault" "spoke" { tags = merge( var.tags, { - Name = "sas-awsng-${var.spoke_account_id}-backup-vault" + Name = "ng-${var.spoke_account_id}-backup-vault" } ) diff --git a/modules/resource_checker/main.tf b/modules/resource_checker/main.tf index 0cb07cb6..845c7a6d 100644 --- a/modules/resource_checker/main.tf +++ b/modules/resource_checker/main.tf @@ -39,7 +39,7 @@ data "external" "vault_checker_tool" { "access_key" = var.aws_access_key_id "secret_key" = var.aws_secret_access_key "token" = var.aws_session_token - "VAULT_NAME" = "sas-awsng-${var.spoke_account_id}-backup-vault" + "VAULT_NAME" = "ng-${var.spoke_account_id}-backup-vault" } } From f20d62daefe7b5273354a46aee3373e2347d786a Mon Sep 17 00:00:00 2001 From: Jeff Owens Date: Thu, 2 Jan 2025 12:16:42 -0500 Subject: [PATCH 40/40] chmod after terraform init Signed-off-by: Jeff Owens --- Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 3a41d036..0d95a637 100644 --- a/Dockerfile +++ b/Dockerfile @@ -16,9 +16,9 @@ RUN yum -y install git openssh jq which \ && curl -sLO https://storage.googleapis.com/kubernetes-release/release/v$KUBECTL_VERSION/bin/linux/amd64/kubectl \ && chmod 755 ./kubectl /viya4-iac-aws/docker-entrypoint.sh \ && mv ./kubectl /usr/local/bin/kubectl \ - && chmod g=u -R /etc/passwd /etc/group /viya4-iac-aws \ && git config --system --add safe.directory /viya4-iac-aws \ - && terraform init + && terraform init \ + && chmod g=u -R /etc/passwd /etc/group /viya4-iac-aws ENV TF_VAR_iac_tooling=docker ENTRYPOINT ["/viya4-iac-aws/docker-entrypoint.sh"]