From 04875cd20105036db049f27c5c7433b3225817df Mon Sep 17 00:00:00 2001 From: Kurt Portelli Date: Mon, 24 Jul 2023 23:56:55 +0200 Subject: [PATCH] initial commit --- README.md | 5 + aws/network/README.md | 0 aws/network/examples/default/main.tf | 52 ++++++++ aws/network/main.tf | 176 +++++++++++++++++++++++++++ aws/network/outputs.tf | 52 ++++++++ aws/network/route_table_v2.tf | 73 +++++++++++ aws/network/variables.tf | 96 +++++++++++++++ aws/rds/README.md | 82 +++++++++++++ aws/rds/examples/default/main.tf | 43 +++++++ aws/rds/main.tf | 73 +++++++++++ aws/rds/outputs.tf | 7 ++ aws/rds/variables.tf | 120 ++++++++++++++++++ aws/redis/README.md | 29 +++++ aws/redis/main.tf | 112 +++++++++++++++++ aws/redis/outputs.tf | 11 ++ aws/redis/refactor.tf | 4 + aws/redis/variables.tf | 74 +++++++++++ 17 files changed, 1009 insertions(+) create mode 100644 aws/network/README.md create mode 100644 aws/network/examples/default/main.tf create mode 100644 aws/network/main.tf create mode 100644 aws/network/outputs.tf create mode 100644 aws/network/route_table_v2.tf create mode 100644 aws/network/variables.tf create mode 100644 aws/rds/README.md create mode 100644 aws/rds/examples/default/main.tf create mode 100644 aws/rds/main.tf create mode 100644 aws/rds/outputs.tf create mode 100644 aws/rds/variables.tf create mode 100644 aws/redis/README.md create mode 100644 aws/redis/main.tf create mode 100644 aws/redis/outputs.tf create mode 100644 aws/redis/refactor.tf create mode 100644 aws/redis/variables.tf diff --git a/README.md b/README.md index ff28bba..b7aee37 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,7 @@ # terraform-modules A collection of terraform modules to standardize network creation and common interactions in aws + +- aws + - network + - rds + - redis \ No newline at end of file diff --git a/aws/network/README.md b/aws/network/README.md new file mode 100644 index 0000000..e69de29 diff --git a/aws/network/examples/default/main.tf b/aws/network/examples/default/main.tf new file mode 100644 index 0000000..ae07ece --- /dev/null +++ b/aws/network/examples/default/main.tf @@ -0,0 +1,52 @@ +provider "aws" { + region = "us-west-2" +} + +module "network" { + source = "../.." + + az_zones = data.aws_availability_zones.current.names + region = "us-west-2" + vpc_sub = "10.66" + + name = "test-vpc" + deployment_env = "test-vpc" + + extra_private_routes = [] + extra_public_routes = [] +} + +data "aws_availability_zones" "current" { + state = "available" +} + +data "aws_caller_identity" "current" {} + +output "public_routes" { + value = [ + for index, route in flatten(module.network.public_route_tables.*.route) : + "${try(route.gateway_id, route.vpc_peering_connection_id)}/${route.cidr_block}" + ] +} + +output "public_routes_v2" { + value = [ + for route in module.network.public_routes_v2 : + "${try(route.gateway_id, route.vpc_peering_connection_id)}/${route.destination_cidr_block}" + ] +} + + +output "private_routes" { + value = [ + for index, route in flatten(module.network.private_route_tables.*.route) : + "${try(route.nat_gateway_id, route.vpc_peering_connection_id)}/${route.cidr_block}" + ] +} + +output "private_routes_v2" { + value = [ + for route in module.network.private_routes_v2 : + "${try(route.nat_gateway_id, route.vpc_peering_connection_id)}/${route.destination_cidr_block}" + ] +} diff --git a/aws/network/main.tf b/aws/network/main.tf new file mode 100644 index 0000000..d6a376e --- /dev/null +++ b/aws/network/main.tf @@ -0,0 +1,176 @@ +terraform { + required_version = ">= 1.0.0" +} + +resource "aws_vpc" "default" { + cidr_block = format("%s.0.0/16", var.vpc_sub) + enable_dns_hostnames = true + tags = { + Name = "${var.name}-vpc" + Description = "VPC for ${var.name}" + } +} + +/* Public Subnet */ +resource "aws_subnet" "public" { + count = length(var.az_zones) + vpc_id = aws_vpc.default.id + + cidr_block = cidrsubnet(format("%s.0.0/21", var.vpc_sub), ceil(log(length(var.az_zones), 2)), count.index) + availability_zone = var.az_zones[count.index] + + tags = merge( + var.public_subnet_tags, + { + Name = "${var.name}-Public-${var.az_zones[count.index]}-subnet" + Description = "Public Subnet for ${var.name}" + Created-By = "DevOps-Terraform" + Environment = var.deployment_env + } + ) +} + +/* Private Subnet */ +resource "aws_subnet" "private" { + count = length(var.az_zones) + vpc_id = aws_vpc.default.id + + cidr_block = cidrsubnet(format("%s.100.0/20", var.vpc_sub), ceil(log(length(var.az_zones), 2)), count.index) + availability_zone = var.az_zones[count.index] + + tags = merge( + var.private_subnet_tags, + { + Name = "${var.name}-Private-${var.az_zones[count.index]}-subnet" + Description = "Private Subnet for ${var.name}" + Created-By = "DevOps-Terraform" + Environment = var.deployment_env + } + ) +} + +/* Gateways Nat and Internet */ +resource "aws_eip" "nat" { + count = length(var.az_zones) + vpc = true + tags = { + Name = "${var.name}-${var.az_zones[count.index]}-eip" + Description = "Internet Gateway for NAT Gateway" + Created-By = "DevOps-Terraform" + Environment = var.deployment_env + } +} +resource "aws_nat_gateway" "default" { + count = length(var.az_zones) + allocation_id = element(aws_eip.nat.*.id, count.index) + subnet_id = element(aws_subnet.public.*.id, count.index) + depends_on = [aws_subnet.public] + + tags = { + Name = "${var.name}-${var.az_zones[count.index]}-natgw" + Created-By = "DevOps-Terraform" + Environment = var.deployment_env + } +} +resource "aws_internet_gateway" "default" { + vpc_id = aws_vpc.default.id + tags = { + Name = "${var.name}-internetgw" + Description = "Internet Gateway for Public Subnets for ${var.name}" + Created-By = "DevOps-Terraform" + Environment = var.deployment_env + } +} +/* route tables */ +resource "aws_route_table" "private" { + count = !var.remove_all_private_route_tables_v1 ? length(var.az_zones) : 0 + + vpc_id = aws_vpc.default.id + + route { + cidr_block = "0.0.0.0/0" + nat_gateway_id = element(aws_nat_gateway.default.*.id, count.index) + } + + dynamic "route" { + for_each = concat( + var.extra_private_routes, + try(var.extra_private_routes_per_az[var.az_zones[count.index]], []) + ) + + content { + cidr_block = route.value["cidr_block"] + vpc_peering_connection_id = route.value["vpc_peering_connection_id"] + network_interface_id = route.value["network_interface_id"] + } + } + + tags = { + Name = "${var.name}-Private-${var.az_zones[count.index]}-routetable" + Description = "Route table Target to Nat Gateway for ${var.name}" + Created-By = "DevOps-Terraform" + Environment = var.deployment_env + } + depends_on = [aws_nat_gateway.default] +} +resource "aws_route_table" "public" { + count = !var.remove_all_public_route_tables_v1 ? length(var.az_zones) : 0 + vpc_id = aws_vpc.default.id + + route { + cidr_block = "0.0.0.0/0" + gateway_id = aws_internet_gateway.default.id + } + + dynamic "route" { + for_each = var.extra_public_routes + + content { + cidr_block = route.value["cidr_block"] + vpc_peering_connection_id = route.value["vpc_peering_connection_id"] + network_interface_id = route.value["network_interface_id"] + } + } + + tags = { + Name = "${var.name}-Public-${var.az_zones[count.index]}-routetable" + Description = "Route table Target to Internet Gateway for ${var.name}" + Created-By = "DevOps-Terraform" + Environment = var.deployment_env + } + depends_on = [aws_internet_gateway.default] +} +/* Subnets Assciation for Public and Private */ +resource "aws_route_table_association" "private" { + count = length(var.az_zones) + + subnet_id = aws_subnet.private[count.index].id + + route_table_id = ( + count.index < var.associate_private_route_table_v2 + ? aws_route_table.private_v2[count.index].id + : aws_route_table.private[count.index].id + ) + + depends_on = [ + aws_subnet.private, + aws_route_table.private, + ] +} + +resource "aws_route_table_association" "public" { + count = length(var.az_zones) + + subnet_id = aws_subnet.public[count.index].id + + route_table_id = ( + count.index < var.associate_public_route_table_v2 + ? aws_route_table.public_v2[count.index].id + : aws_route_table.public[count.index].id + ) + + depends_on = [ + aws_subnet.public, + aws_route_table.public, + ] +} diff --git a/aws/network/outputs.tf b/aws/network/outputs.tf new file mode 100644 index 0000000..e3bc938 --- /dev/null +++ b/aws/network/outputs.tf @@ -0,0 +1,52 @@ +output "private_subnets" { + description = "List of IDs of private subnets" + value = aws_subnet.private.*.id +} + +output "public_subnets" { + description = "List of IDs of public subnets" + value = aws_subnet.public.*.id +} + +output "private_route_tables" { + description = "List of private route tables" + value = aws_route_table.private +} + +output "private_route_tables_v2" { + description = "List of private route tables v2" + value = aws_route_table.private_v2 +} + +output "private_routes_v2" { + value = concat(aws_route.private_nat_v2, values(aws_route.private_v2)) +} + +output "public_route_tables" { + description = "List of public route tables" + value = aws_route_table.public +} + +output "public_route_tables_v2" { + description = "List of public route tables v2" + value = aws_route_table.public_v2 +} + +output "public_routes_v2" { + value = concat(aws_route.public_gateway_v2, values(aws_route.public_v2)) +} + +output "vpc_id" { + description = "The ID of the VPC" + value = concat(aws_vpc.default.*.id, [""])[0] +} + +output "vpc" { + description = "The ID of the VPC" + value = aws_vpc.default +} + +output "nat_gateways" { + description = "List of nat gateways" + value = concat(aws_eip.nat.*) +} diff --git a/aws/network/route_table_v2.tf b/aws/network/route_table_v2.tf new file mode 100644 index 0000000..0714982 --- /dev/null +++ b/aws/network/route_table_v2.tf @@ -0,0 +1,73 @@ +resource "aws_route_table" "private_v2" { + count = var.create_route_table_v2 ? length(var.az_zones) : 0 + + vpc_id = aws_vpc.default.id + + tags = { + Name = "${var.name}-Private-${var.az_zones[count.index]}-routetable-v2" + Description = "Route table Target to Nat Gateway for ${var.name}" + Created-By = "DevOps-Terraform" + Environment = var.deployment_env + } + + depends_on = [aws_nat_gateway.default] +} + +resource "aws_route" "private_nat_v2" { + count = var.create_route_table_v2 ? length(var.az_zones) : 0 + + route_table_id = aws_route_table.private_v2[count.index].id + nat_gateway_id = aws_nat_gateway.default[count.index].id + destination_cidr_block = "0.0.0.0/0" +} + +resource "aws_route" "private_v2" { + for_each = var.create_route_table_v2 ? local.private_routes_v2 : {} + + route_table_id = aws_route_table.private_v2[index(var.az_zones, each.value.az)].id + destination_cidr_block = each.value.cidr_block + vpc_peering_connection_id = each.value.vpc_peering_connection_id +} + +resource "aws_route_table" "public_v2" { + count = var.create_route_table_v2 ? length(var.az_zones) : 0 + + vpc_id = aws_vpc.default.id + + tags = { + Name = "${var.name}-Public-${var.az_zones[count.index]}-routetable-v2" + Description = "Route table Target to Internet Gateway for ${var.name}" + Created-By = "DevOps-Terraform" + Environment = var.deployment_env + } + + depends_on = [aws_internet_gateway.default] +} + +resource "aws_route" "public_gateway_v2" { + count = var.create_route_table_v2 ? length(var.az_zones) : 0 + + route_table_id = aws_route_table.public_v2[count.index].id + gateway_id = aws_internet_gateway.default.id + destination_cidr_block = "0.0.0.0/0" +} + +resource "aws_route" "public_v2" { + for_each = var.create_route_table_v2 ? local.public_routes_v2 : {} + + route_table_id = aws_route_table.public_v2[index(var.az_zones, each.value.az)].id + destination_cidr_block = each.value.cidr_block + vpc_peering_connection_id = each.value.vpc_peering_connection_id +} + +locals { + private_routes_v2 = merge({ + for index, az_route in setproduct(var.az_zones, var.extra_private_routes) : + "${az_route[0]}/${az_route[1].cidr_block}" => merge(az_route[1], { az = az_route[0] }) + }) + + public_routes_v2 = { + for index, az_route in setproduct(var.az_zones, var.extra_public_routes) : + "${az_route[0]}/${az_route[1].cidr_block}" => merge(az_route[1], { az = az_route[0] }) + } +} diff --git a/aws/network/variables.tf b/aws/network/variables.tf new file mode 100644 index 0000000..b4de856 --- /dev/null +++ b/aws/network/variables.tf @@ -0,0 +1,96 @@ + +variable "region" { + type = string + description = "region of VPC" +} + +variable "name" { + type = string + description = "name of vpc" +} + +variable "vpc_sub" { + type = string + default = "10.0" + description = "first two octets of subnet vpc" +} + +variable "public_subnet_tags" { + type = map(string) + default = {} +} + +variable "private_subnet_tags" { + type = map(string) + default = {} +} + +variable "az_zones" { + type = list(string) + description = "List of available Zones" + default = ["us-west-1a", "us-west-1b"] +} + +variable "deployment_env" { + type = string + description = "Environment where the VPC resides" +} + +# Only vpc peering supported for now +variable "extra_public_routes" { + type = list(object({ + cidr_block = string + vpc_peering_connection_id = optional(string) + network_interface_id = optional(string) + })) + + default = [] + description = "List of route configs, see https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table#route-argument-reference" +} + +# Only vpc peering supported for now +variable "extra_private_routes" { + type = list(object({ + cidr_block = string + vpc_peering_connection_id = optional(string) + network_interface_id = optional(string) + })) + + default = [] + description = "List of route configs, see https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table#route-argument-reference" +} + +variable "extra_private_routes_per_az" { + type = map(list(object({ + cidr_block = string + vpc_peering_connection_id = optional(string) + network_interface_id = optional(string) + }))) + + default = {} +} + +variable "create_route_table_v2" { + type = bool + default = false +} + +variable "associate_public_route_table_v2" { + type = number + default = 0 +} + +variable "associate_private_route_table_v2" { + type = number + default = 0 +} + +variable "remove_all_public_route_tables_v1" { + type = bool + default = false +} + +variable "remove_all_private_route_tables_v1" { + type = bool + default = false +} diff --git a/aws/rds/README.md b/aws/rds/README.md new file mode 100644 index 0000000..35df4ac --- /dev/null +++ b/aws/rds/README.md @@ -0,0 +1,82 @@ +# aws/rds module + +Allows the provisioning of DB instances. + + +## Required variables + +- `name` - DB name +- `username` - DB user name +- `password` - DB user password +- `resources_prefix` - resources will be created with this prefix +- `vpc` - VPC object + - `id` - VPC id + - `private_subnets` - list of the VPC private subnets + - `cidr` - VPC ip range as cidr block notation + +## Optional variables + +- `allocated_storage` - Allocated DB storage in GiB. +- `instance_class` - DB instance class. See https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Concepts.DBInstanceClass.html +- `tags` - DB tags +- `skip_final_snapshot` - Whether to take a DB snapshot before deleting the instance +- `storage_type` - DB storage type +- `engine` - DB engine +- `engine_version` - DB engine version +- `backup_retention_period` - Number of days to keep DB backups +- `snapshot_identifier` - Specify a snapshot to create the DB instance from. Triggers recreation +- `final_snapshot_identifier` - If `skip_final_snapshot = false`, takes a snapshot with this name before deleting the DB instance. Only takes effect it `skip_final_snapshot` is set to `false` during DB creation +- `deletion_protection` - Whether to allow the DB instance to be deleted + +## Scope of this module + +`aws_db_subnet_group` + +`aws_db_instance` + +`aws_security_group` + +`aws_security_group_rule` + +## Examples + + +```terraform +data "aws_vpc" "default" { + default = true +} + +data "aws_subnet_ids" "default" { + vpc_id = data.aws_vpc.default.id +} + +module "db" { + source = "../.." + + resources_prefix = "test-db-instance" + name = "testdbinstance" + instance_class = "db.t2.micro" + storage_type = "gp2" + engine = "postgres" + engine_version = "11.6" + username = "testdbuser" + password = "testdbpassword" + allocated_storage = 10 + skip_final_snapshot = true + + tags = { + Name = "Test DB instance" + } + + vpc = { + id = data.aws_vpc.default.id + cidr = data.aws_vpc.default.cidr_block + subnets = data.aws_subnet_ids.default.ids + } +} +``` + +## Outputs + +- `this` - The `aws_db_instance` output for the db instance. See https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/db_instance#attributes-reference . +- `sg` - The `aws_security_group` output for the db security group. See https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group . diff --git a/aws/rds/examples/default/main.tf b/aws/rds/examples/default/main.tf new file mode 100644 index 0000000..2f3468e --- /dev/null +++ b/aws/rds/examples/default/main.tf @@ -0,0 +1,43 @@ +provider "aws" { + region = "us-west-2" +} + +data "aws_caller_identity" "current" {} + +data "aws_vpc" "default" { + default = true +} + +data "aws_subnets" "default" { + filter { + name = "vpc-id" + values = [data.aws_vpc.default.id] + } +} + +module "db" { + source = "../.." + + resources_prefix = "test-db-instance" + name = "testdb" + instance_class = "db.t3.micro" + storage_type = "gp2" + engine = "postgres" + engine_version = "14.7" + username = "testdbuser" + password = "testdbpassword" + allocated_storage = 10 + manage_master_user_password = null + final_snapshot_identifier = "test-db-instance-final-snapshot" + deletion_protection = false + + tags = { + Name = "Test DB instance" + } + + vpc = { + id = data.aws_vpc.default.id + cidr = data.aws_vpc.default.cidr_block + subnets = data.aws_subnets.default.ids + } +} diff --git a/aws/rds/main.tf b/aws/rds/main.tf new file mode 100644 index 0000000..7896b62 --- /dev/null +++ b/aws/rds/main.tf @@ -0,0 +1,73 @@ +locals { + db_identifier = "${var.resources_prefix}-db" + db_name = var.name + db_sg = "${var.resources_prefix}-db-sg" +} + +resource "aws_db_subnet_group" "this" { + description = "Subnet group for ${local.db_identifier} DB instance" + subnet_ids = var.vpc.subnets +} + + +resource "aws_db_instance" "this" { + identifier = local.db_identifier + db_name = local.db_name + allocated_storage = var.allocated_storage + instance_class = var.instance_class + engine_version = var.engine_version + tags = var.tags + + performance_insights_enabled = true + username = var.username + password = var.password + manage_master_user_password = var.manage_master_user_password + + # Safety good practices + # - A final snapshot is always taken + # - automated backups are always retained + final_snapshot_identifier = coalesce(var.final_snapshot_identifier, "${local.db_identifier}-final-snapshot") + delete_automated_backups = false + skip_final_snapshot = false + + snapshot_identifier = var.snapshot_identifier + storage_type = var.storage_type + engine = var.engine + backup_retention_period = var.backup_retention_period + deletion_protection = var.deletion_protection + publicly_accessible = var.publicly_accessible + apply_immediately = var.apply_immediately + parameter_group_name = var.parameter_group + multi_az = var.multi_az + enabled_cloudwatch_logs_exports = var.enabled_cloudwatch_logs_exports + + db_subnet_group_name = aws_db_subnet_group.this.id + + vpc_security_group_ids = [ + aws_security_group.this.id + ] + + lifecycle { + ignore_changes = [ + engine_version + ] + } +} + +resource "aws_security_group" "this" { + name = local.db_sg + description = "Allows ${local.db_identifier} DB instance access" + vpc_id = var.vpc.id +} + +resource "aws_security_group_rule" "access_from_vpc" { + security_group_id = aws_security_group.this.id + from_port = aws_db_instance.this.port + to_port = aws_db_instance.this.port + + type = "ingress" + description = "Access ${local.db_identifier} DB from within VPC" + protocol = "tcp" + + cidr_blocks = [var.vpc.cidr] +} diff --git a/aws/rds/outputs.tf b/aws/rds/outputs.tf new file mode 100644 index 0000000..4d6099a --- /dev/null +++ b/aws/rds/outputs.tf @@ -0,0 +1,7 @@ +output "this" { + value = aws_db_instance.this +} + +output "sg" { + value = aws_security_group.this +} diff --git a/aws/rds/variables.tf b/aws/rds/variables.tf new file mode 100644 index 0000000..d12d260 --- /dev/null +++ b/aws/rds/variables.tf @@ -0,0 +1,120 @@ +variable "name" { + description = "DB name." + type = string + default = null +} + +variable "username" { + description = "DB user name." + type = string +} + +variable "password" { + type = string + sensitive = true + nullable = true + default = null +} + +variable "resources_prefix" { + description = "Creates resources with this prefix." + type = string +} + +variable "vpc" { + type = object({ + id = string + cidr = string + subnets = list(string) + }) +} + +variable "allocated_storage" { + description = "Allocated DB storage in GiB." + type = number + default = 10 +} + +variable "instance_class" { + # See https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/Concepts.DBInstanceClass.html + description = "DB instance class." + type = string + default = "db.t2.micro" +} + +variable "tags" { + type = map(string) + default = {} +} + +variable "storage_type" { + type = string + default = "gp2" +} + +variable "engine" { + type = string + default = "postgres" +} + +variable "engine_version" { + type = string + default = "11.6" +} + +variable "backup_retention_period" { + description = "Backup retention period in days." + type = number + default = 30 +} + +variable "snapshot_identifier" { + description = "Specify a snapshot to create the DB instance from. Triggers recreation." + type = string + default = null +} + +variable "final_snapshot_identifier" { + # Only takes effect if skip_final_snapshot is set to false during creation. + description = "If skip_final_snapshot = false, takes a snapshot with this name before deleting the instance." + type = string + default = null +} + +variable "deletion_protection" { + description = "The database can't be deleted when this is set to true." + type = bool + default = false +} + +variable "apply_immediately" { + type = bool + default = false +} + +variable "publicly_accessible" { + type = bool + default = false +} + +variable "parameter_group" { + type = string + default = null +} + +variable "multi_az" { + type = bool + default = false +} + +variable "enabled_cloudwatch_logs_exports" { + type = list(string) + + default = [] +} + +# See https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/db_instance#managed-master-passwords-via-secrets-manager-default-kms-key +variable "manage_master_user_password" { + type = bool + default = false +} diff --git a/aws/redis/README.md b/aws/redis/README.md new file mode 100644 index 0000000..78ccd54 --- /dev/null +++ b/aws/redis/README.md @@ -0,0 +1,29 @@ +## Requirements + +| Name | Version | +|------|---------| +| terraform | >= 0.12 | + +## Providers + +| Name | Version | +|------|---------| +| aws | n/a | + +## Inputs + +| Name | Description | Type | Default | Required | +|------|-------------|------|---------|:--------:| +| name | Name of Redis Cluster | `string` | n/a | yes | +| nodes | number of nodes for redis cluster | `number` | n/a | yes | +| platform | Name of Platform or Brand | `string` | n/a | yes | +| port | port number for redis | `number` | n/a | yes | +| subnet | List of subnets ID For Redis subnet | `list(string)` | n/a | yes | +| vpc | VPC ID | `string` | n/a | yes | + +## Outputs + +| Name | Description | +|------|-------------| +| endpoint | n/a | +| security\_id | n/a | \ No newline at end of file diff --git a/aws/redis/main.tf b/aws/redis/main.tf new file mode 100644 index 0000000..0d18e5c --- /dev/null +++ b/aws/redis/main.tf @@ -0,0 +1,112 @@ +terraform { + required_version = ">= 1.0.0" + + required_providers { + aws = { + source = "hashicorp/aws" + } + } +} + +resource "aws_elasticache_subnet_group" "redis" { + name = "${var.name}-subnet" + subnet_ids = var.subnet +} + +resource "aws_security_group" "redis" { + vpc_id = var.vpc + name = "${var.name}-sg" + description = "Redis cache Security Group" + egress { + from_port = "0" + to_port = "0" + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } + tags = { + Name = "${var.name}" + } +} + +resource "aws_elasticache_replication_group" "redis" { + automatic_failover_enabled = true + availability_zones = local.az_zones + replication_group_id = var.name + description = "redis cluster for ${var.platform}" + node_type = "cache.${var.size}" + num_cache_clusters = local.num_cache_clusters + port = var.port + subnet_group_name = aws_elasticache_subnet_group.redis.name + security_group_ids = [aws_security_group.redis.id] + engine_version = var.engine_version + engine = "redis" + multi_az_enabled = var.multi_az_enabled + + parameter_group_name = ( + var.parameter_group_name == null + ? format(local.parameter_group_name_scheme, regex("^(\\d.\\w+)?", var.engine_version)[0]) + : var.parameter_group_name + ) + + num_node_groups = try(var.cluster_mode.num_node_groups, null) + replicas_per_node_group = try(var.cluster_mode.replicas_per_node_group, null) + + dynamic "log_delivery_configuration" { + for_each = local.log_delivery_configuration + + content { + destination = log_delivery_configuration.value.destination + destination_type = log_delivery_configuration.value.destination_type + log_format = log_delivery_configuration.value.log_format + log_type = log_delivery_configuration.value.log_type + } + } + + lifecycle { + ignore_changes = [num_cache_clusters] + } +} + +resource "aws_elasticache_cluster" "redis" { + count = var.cluster_mode == null ? 1 : 0 + + cluster_id = lower("${var.name}-cache") + replication_group_id = aws_elasticache_replication_group.redis.id +} + + +resource "aws_security_group_rule" "service-redis" { + type = "ingress" + from_port = 6379 + to_port = 6379 + protocol = "tcp" + source_security_group_id = var.security_group_id + security_group_id = aws_security_group.redis.id + description = "VPC access" +} + +locals { + num_cache_clusters = ( + var.cluster_mode != null + ? null + : length(var.az_zones) + ) + + parameter_group_name_scheme = ( + var.cluster_mode != null + ? "default.redis%s.cluster.on" + : "default.redis%s" + ) + + az_zones = ( + var.cluster_mode != null + ? null + : var.az_zones + ) + + log_delivery_configuration = ( + var.log_delivery_configuration != null + ? [var.log_delivery_configuration] + : [] + ) +} diff --git a/aws/redis/outputs.tf b/aws/redis/outputs.tf new file mode 100644 index 0000000..d6d38bb --- /dev/null +++ b/aws/redis/outputs.tf @@ -0,0 +1,11 @@ +output "sg-redis" { + value = aws_security_group.redis.id +} + +output "endpoint" { + value = ( + var.cluster_mode != null + ? aws_elasticache_replication_group.redis.configuration_endpoint_address + : aws_elasticache_replication_group.redis.primary_endpoint_address + ) +} diff --git a/aws/redis/refactor.tf b/aws/redis/refactor.tf new file mode 100644 index 0000000..41139e7 --- /dev/null +++ b/aws/redis/refactor.tf @@ -0,0 +1,4 @@ +moved { + from = aws_elasticache_cluster.redis + to = aws_elasticache_cluster.redis[0] +} diff --git a/aws/redis/variables.tf b/aws/redis/variables.tf new file mode 100644 index 0000000..e3ebfdc --- /dev/null +++ b/aws/redis/variables.tf @@ -0,0 +1,74 @@ +variable "subnet" { + type = list(string) + description = "List of subnets ID For Redis subnet" +} + +variable "name" { + type = string + description = "Name of Redis Cluster" +} + +variable "vpc" { + type = string + description = "VPC ID" +} + +variable "platform" { + type = string + description = "Name of Platform or Brand" +} + +variable "port" { + type = number + description = "port number for redis" +} + +variable "az_zones" { + type = list(string) + description = "List of available Zones" +} +variable "engine_version" { + type = string + description = "version number of redis" +} +variable "size" { + type = string + default = "t2.small" +} + +variable "security_group_id" { + type = string + description = "The id of the general security group" + default = null +} + +variable "cluster_mode" { + type = object({ + replicas_per_node_group = number + num_node_groups = number + }) + + default = null +} + +variable "multi_az_enabled" { + type = bool + default = false +} + +variable "parameter_group_name" { + type = string + default = null + nullable = true +} + +variable "log_delivery_configuration" { + type = object({ + destination = string + destination_type = string + log_format = string + log_type = string + }) + + default = null +}