Skip to content
77 changes: 52 additions & 25 deletions README.md

Large diffs are not rendered by default.

39 changes: 28 additions & 11 deletions README.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -53,34 +53,45 @@ usage: |2-
region = var.region
}

module "vpc" {
source = "git::https://github.com/cloudposse/terraform-aws-vpc.git?ref=tags/0.8.1"
module "this" {
source = "cloudposse/label/null"
# Cloud Posse recommends pinning every module to a specific version
# version = "x.x.x"
namespace = var.namespace
stage = var.stage
name = var.name
}

module "vpc" {
source = "cloudposse/vpc/aws"
# Cloud Posse recommends pinning every module to a specific version
# version = "x.x.x"

cidr_block = "172.16.0.0/16"

context = module.this.context
}

module "subnets" {
source = "git::https://github.com/cloudposse/terraform-aws-dynamic-subnets.git?ref=tags/0.18.1"
source = "cloudposse/dynamic-subnets/aws"
# Cloud Posse recommends pinning every module to a specific version
# version = "x.x.x"

availability_zones = var.availability_zones
namespace = var.namespace
stage = var.stage
name = var.name
vpc_id = module.vpc.vpc_id
igw_id = module.vpc.igw_id
cidr_block = module.vpc.vpc_cidr_block
nat_gateway_enabled = false
nat_gateway_enabled = true
nat_instance_enabled = false

context = module.this.context
}

module "memcached" {
source = "cloudposse/elasticache-memcached/aws"
# Cloud Posse recommends pinning every module to a specific version
# version = "x.x.x"
namespace = var.namespace
stage = var.stage
name = var.name

availability_zones = var.availability_zones
vpc_id = module.vpc.vpc_id
allowed_security_groups = [module.vpc.vpc_default_security_group_id]
Expand All @@ -90,10 +101,14 @@ usage: |2-
engine_version = var.engine_version
apply_immediately = true
zone_id = var.zone_id

elasticache_parameter_group_family = var.elasticache_parameter_group_family

context = module.this.context
}
```
examples: |-
Review the [complete example](examples/simple) to see how to use this module.
Review the [complete example](examples/complete) to see how to use this module.
include:
- "docs/targets.md"
- "docs/terraform.md"
Expand All @@ -105,3 +120,5 @@ contributors:
github: "aknysh"
- name: "Erik Osterman"
github: "osterman"
- name: "Dan Meyers"
github: "danjbh"
34 changes: 22 additions & 12 deletions docs/terraform.md

Large diffs are not rendered by default.

12 changes: 8 additions & 4 deletions examples/complete/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,18 @@ provider "aws" {
}

module "vpc" {
source = "cloudposse/vpc/aws"
version = "0.18.1"
source = "cloudposse/vpc/aws"
version = "0.28.0"

cidr_block = "172.16.0.0/16"

context = module.this.context
}

module "subnets" {
source = "cloudposse/dynamic-subnets/aws"
version = "0.33.0"
source = "cloudposse/dynamic-subnets/aws"
version = "0.39.7"

availability_zones = var.availability_zones
vpc_id = module.vpc.vpc_id
igw_id = module.vpc.igw_id
Expand All @@ -36,5 +38,7 @@ module "memcached" {
apply_immediately = true
zone_id = var.zone_id

elasticache_parameter_group_family = var.elasticache_parameter_group_family

context = module.this.context
}
119 changes: 67 additions & 52 deletions main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -22,45 +22,56 @@ resource "null_resource" "cluster_urls" {
#
# Security Group Resources
#
locals {
legacy_cidr_ingress_rule = length(var.allowed_cidr_blocks) == 0 ? null : {
key = "legacy-cidr-ingress"
type = "ingress"
from_port = var.port
to_port = var.port
protocol = "tcp"
cidr_blocks = var.allowed_cidr_blocks
description = "Allow inbound traffic from CIDR blocks"
}

resource "aws_security_group" "default" {
count = local.enabled && var.use_existing_security_groups == false ? 1 : 0
vpc_id = var.vpc_id
name = module.this.id
tags = module.this.tags
sg_rules = {
legacy = merge(local.legacy_cidr_ingress_rule, {})
extra = var.additional_security_group_rules
}
}

resource "aws_security_group_rule" "egress" {
count = local.enabled && var.use_existing_security_groups == false ? 1 : 0
description = "Allow all egress traffic"
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
security_group_id = join("", aws_security_group.default.*.id)
type = "egress"
}
module "aws_security_group" {
source = "cloudposse/security-group/aws"
version = "0.4.3"

enabled = local.create_security_group

allow_all_egress = var.allow_all_egress
security_group_name = var.security_group_name
rules_map = local.sg_rules
rule_matrix = [{
key = "in"
source_security_group_ids = local.allowed_security_group_ids
cidr_blocks = var.allowed_cidr_blocks
rules = [{
key = "in"
type = "ingress"
from_port = var.port
to_port = var.port
protocol = "tcp"
description = "Selectively allow inbound traffic"
}]
}]

resource "aws_security_group_rule" "ingress_security_groups" {
count = local.enabled && var.use_existing_security_groups == false ? length(var.allowed_security_groups) : 0
description = "Allow inbound traffic from existing Security Groups"
from_port = var.port
to_port = var.port
protocol = "tcp"
source_security_group_id = var.allowed_security_groups[count.index]
security_group_id = join("", aws_security_group.default.*.id)
type = "ingress"
}
vpc_id = var.vpc_id

security_group_description = local.security_group_description

resource "aws_security_group_rule" "ingress_cidr_blocks" {
count = local.enabled && var.use_existing_security_groups == false && length(var.allowed_cidr_blocks) > 0 ? 1 : 0
description = "Allow inbound traffic from CIDR blocks"
from_port = var.port
to_port = var.port
protocol = "tcp"
cidr_blocks = var.allowed_cidr_blocks
security_group_id = join("", aws_security_group.default.*.id)
type = "ingress"
create_before_destroy = var.security_group_create_before_destroy

security_group_create_timeout = var.security_group_create_timeout
security_group_delete_timeout = var.security_group_delete_timeout

context = module.this.context
}

#
Expand All @@ -84,16 +95,19 @@ resource "aws_elasticache_parameter_group" "default" {
}

resource "aws_elasticache_cluster" "default" {
count = local.enabled ? 1 : 0
apply_immediately = var.apply_immediately
cluster_id = module.this.id
engine = "memcached"
engine_version = var.engine_version
node_type = var.instance_type
num_cache_nodes = var.cluster_size
parameter_group_name = join("", aws_elasticache_parameter_group.default.*.name)
subnet_group_name = local.elasticache_subnet_group_name
security_group_ids = var.use_existing_security_groups ? var.existing_security_groups : [join("", aws_security_group.default.*.id)]
count = local.enabled ? 1 : 0
apply_immediately = var.apply_immediately
cluster_id = module.this.id
engine = "memcached"
engine_version = var.engine_version
node_type = var.instance_type
num_cache_nodes = var.cluster_size
parameter_group_name = join("", aws_elasticache_parameter_group.default.*.name)
subnet_group_name = local.elasticache_subnet_group_name
# It would be nice to remove null or duplicate security group IDs, if there are any, using `compact`,
# but that causes problems, and having duplicates does not seem to cause problems.
# See https://github.com/hashicorp/terraform/issues/29799
security_group_ids = local.create_security_group ? concat(local.associated_security_group_ids, [module.aws_security_group.id]) : local.associated_security_group_ids
maintenance_window = var.maintenance_window
notification_topic_arn = var.notification_topic_arn
port = var.port
Expand All @@ -107,7 +121,7 @@ resource "aws_elasticache_cluster" "default" {
# CloudWatch Resources
#
resource "aws_cloudwatch_metric_alarm" "cache_cpu" {
count = local.enabled ? 1 : 0
count = local.enabled && var.cloudwatch_metric_alarms_enabled ? 1 : 0
alarm_name = "${module.this.id}-cpu-utilization"
alarm_description = "Memcached cluster CPU utilization"
comparison_operator = "GreaterThanThreshold"
Expand All @@ -128,7 +142,7 @@ resource "aws_cloudwatch_metric_alarm" "cache_cpu" {
}

resource "aws_cloudwatch_metric_alarm" "cache_memory" {
count = local.enabled ? 1 : 0
count = local.enabled && var.cloudwatch_metric_alarms_enabled ? 1 : 0
alarm_name = "${module.this.id}-freeable-memory"
alarm_description = "Memcached cluster freeable memory"
comparison_operator = "LessThanThreshold"
Expand All @@ -149,12 +163,13 @@ resource "aws_cloudwatch_metric_alarm" "cache_memory" {
}

module "dns" {
source = "cloudposse/route53-cluster-hostname/aws"
version = "0.12.0"
enabled = local.enabled && var.zone_id != "" ? true : false
ttl = 60
zone_id = var.zone_id
records = [join("", aws_elasticache_cluster.default.*.cluster_address)]
source = "cloudposse/route53-cluster-hostname/aws"
version = "0.12.0"
enabled = module.this.enabled && length(var.zone_id) > 0 ? true : false
dns_name = var.dns_subdomain != "" ? var.dns_subdomain : module.this.id
ttl = 60
zone_id = var.zone_id
records = [join("", aws_elasticache_cluster.default.*.cluster_address)]

context = module.this.context
}
9 changes: 7 additions & 2 deletions outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,13 @@ output "cluster_id" {
}

output "security_group_id" {
value = join("", aws_security_group.default.*.id)
description = "Security Group ID"
value = module.aws_security_group.id
description = "The ID of the created security group"
}

output "security_group_name" {
value = module.aws_security_group.name
description = "The name of the created security group"
}

output "cluster_address" {
Expand Down
111 changes: 111 additions & 0 deletions security-group-inputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
# security_group_inputs Version: 1
##


variable "create_security_group" {
type = bool
default = true
description = "Set `true` to create and configure a new security group. If false, `associated_security_group_ids` must be provided."
}

locals {
create_security_group = local.enabled && (var.use_existing_security_groups == null ? var.create_security_group : !var.use_existing_security_groups)
}

variable "associated_security_group_ids" {
type = list(string)
default = []
description = <<-EOT
A list of IDs of Security Groups to associate the created resource with, in addition to the created security group.
These security groups will not be modified and, if `create_security_group` is `false`, must provide all the required access.
EOT
}

locals {
associated_security_group_ids = concat(var.existing_security_groups, var.associated_security_group_ids)
}

variable "allowed_security_group_ids" {
type = list(string)
default = []
description = <<-EOT
A list of IDs of Security Groups to allow access to the security group created by this module.
EOT
}

locals {
allowed_security_group_ids = concat(var.allowed_security_groups, var.allowed_security_group_ids)
}


variable "security_group_name" {
type = list(string)
default = []
description = <<-EOT
The name to assign to the created security group. Must be unique within the VPC.
If not provided, will be derived from the `null-label.context` passed in.
If `create_before_destroy` is true, will be used as a name prefix.
EOT
}

variable "security_group_description" {
type = string
default = "Security group for Elasticache Memcached"
description = <<-EOT
The description to assign to the created Security Group.
Warning: Changing the description causes the security group to be replaced.
Set this to `null` to maintain parity with releases <= `0.34.0`.
EOT
}

locals {
security_group_description = var.security_group_description == null ? "Managed by Terraform" : var.security_group_description
}

variable "security_group_create_before_destroy" {
type = bool
default = true
description = <<-EOT
Set `true` to enable Terraform `create_before_destroy` behavior on the created security group.
We only recommend setting this `false` if you are upgrading this module and need to keep
the existing security group from being replaced.
Note that changing this value will always cause the security group to be replaced.
EOT
}

variable "security_group_create_timeout" {
type = string
default = "10m"
description = "How long to wait for the security group to be created."
}

variable "security_group_delete_timeout" {
type = string
default = "15m"
description = <<-EOT
How long to retry on `DependencyViolation` errors during security group deletion.
EOT
}


variable "allow_all_egress" {
type = bool
default = true
description = <<-EOT
If `true`, the created security group will allow egress on all ports and protocols to all IP address.
If this is false and no egress rules are otherwise specified, then no egress will be allowed.
EOT
}

variable "additional_security_group_rules" {
type = list(any)
default = []
description = <<-EOT
A list of Security Group rule objects to add to the created security group, in addition to the ones
this module normally creates. (To suppress the module's rules, set `create_security_group` to false
and supply your own security group via `associated_security_group_ids`.)
The keys and values of the objects are fully compatible with the `aws_security_group_rule` resource, except
for `security_group_id` which will be ignored, and the optional "key" which, if provided, must be unique and known at "plan" time.
To get more info see https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group_rule .
EOT
}
Loading