├── .gitignore ├── .pre-commit-config.yaml ├── LICENSE ├── README.md ├── cloudwatch.tf ├── main.tf ├── outputs.tf ├── security_groups.tf └── variables.tf /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled files 2 | *.tfstate 3 | *.tfstate.backup 4 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: git://github.com/antonbabenko/pre-commit-terraform 3 | rev: v1.30.0 4 | hooks: 5 | - id: terraform_fmt 6 | - id: terraform_docs 7 | - repo: git://github.com/pre-commit/pre-commit-hooks 8 | rev: v3.1.0 9 | hooks: 10 | - id: check-merge-conflict 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 FitnessKeeper, Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # A Terraform module to create a Redis ElastiCache cluster 2 | 3 | A terraform module providing a Redis ElastiCache cluster in AWS. 4 | 5 | This module 6 | 7 | - Creates Redis ElastiCache clusters 8 | - Creates, manages, and exports a security group 9 | 10 | ## Terraform versions 11 | 12 | Terraform 0.12. Pin module version to `~> v2.0`. Submit pull-requests to `master` branch. 13 | 14 | Terraform 0.11. Pin module version to `~> v1.0`. Submit pull-requests to `terraform011` branch. 15 | 16 | ## Usage 17 | 18 | ```hcl 19 | module "redis" { 20 | source = "github.com/terraform-community-modules/tf_aws_elasticache_redis.git?ref=v2.2.0" 21 | 22 | env = "dev" 23 | name = "thtest" 24 | redis_clusters = "2" 25 | redis_failover = "true" 26 | subnets = ["subnet-12345678", "subnet-11111111", "subnet-22222222"] 27 | vpc_id = "vpc-12345678" 28 | 29 | redis_parameters = [{ 30 | name = "min-slaves-max-lag" 31 | value = "5" 32 | },{ 33 | name = "min-slaves-to-write" 34 | value = "1" 35 | },{ 36 | name = "databases" 37 | value = "32" 38 | }] 39 | } 40 | ``` 41 | 42 | 43 | ## Requirements 44 | 45 | No requirements. 46 | 47 | ## Providers 48 | 49 | | Name | Version | 50 | |------|---------| 51 | | aws | n/a | 52 | | random | n/a | 53 | 54 | ## Inputs 55 | 56 | | Name | Description | Type | Default | Required | 57 | |------|-------------|------|---------|:--------:| 58 | | allowed\_cidr | A list CIDRs to allow access to. | `list(string)` |
[| no | 59 | | allowed\_security\_groups | A list of Security Group ID's to allow access to. | `list(string)` | `[]` | no | 60 | | apply\_immediately | Specifies whether any modifications are applied immediately, or during the next maintenance window. Default is false. | `bool` | `false` | no | 61 | | at\_rest\_encryption\_enabled | Whether to enable encryption at rest | `bool` | `false` | no | 62 | | auth\_token | The password used to access a password protected server. Can be specified only if transit\_encryption\_enabled = true. If specified must contain from 16 to 128 alphanumeric characters or symbols | `string` | `null` | no | 63 | | auto\_minor\_version\_upgrade | Specifies whether a minor engine upgrades will be applied automatically to the underlying Cache Cluster instances during the maintenance window | `bool` | `true` | no | 64 | | availability\_zones | A list of EC2 availability zones in which the replication group's cache clusters will be created. The order of the availability zones in the list is not important | `list(string)` | `[]` | no | 65 | | env | env to deploy into, should typically dev/staging/prod | `string` | n/a | yes | 66 | | kms\_key\_id | The ARN of the key that you wish to use if encrypting at rest. If not supplied, uses service managed encryption. Can be specified only if at\_rest\_encryption\_enabled = true | `string` | `""` | no | 67 | | name | Name for the Redis replication group i.e. UserObject | `string` | n/a | yes | 68 | | notification\_topic\_arn | An Amazon Resource Name (ARN) of an SNS topic to send ElastiCache notifications to. Example: arn:aws:sns:us-east-1:012345678999:my\_sns\_topic | `string` | `""` | no | 69 | | redis\_clusters | Number of Redis cache clusters (nodes) to create | `string` | n/a | yes | 70 | | redis\_failover | n/a | `bool` | `false` | no | 71 | | redis\_maintenance\_window | Specifies the weekly time range for when maintenance on the cache cluster is performed. The format is ddd:hh24:mi-ddd:hh24:mi (24H Clock UTC). The minimum maintenance window is a 60 minute period | `string` | `"fri:08:00-fri:09:00"` | no | 72 | | redis\_node\_type | Instance type to use for creating the Redis cache clusters | `string` | `"cache.m3.medium"` | no | 73 | | redis\_parameters | additional parameters modifyed in parameter group | `list(map(any))` | `[]` | no | 74 | | redis\_port | n/a | `number` | `6379` | no | 75 | | redis\_snapshot\_retention\_limit | The number of days for which ElastiCache will retain automatic cache cluster snapshots before deleting them. For example, if you set SnapshotRetentionLimit to 5, then a snapshot that was taken today will be retained for 5 days before being deleted. If the value of SnapshotRetentionLimit is set to zero (0), backups are turned off. Please note that setting a snapshot\_retention\_limit is not supported on cache.t1.micro or cache.t2.\* cache nodes | `number` | `0` | no | 76 | | redis\_snapshot\_window | The daily time range (in UTC) during which ElastiCache will begin taking a daily snapshot of your cache cluster. The minimum snapshot window is a 60 minute period | `string` | `"06:30-07:30"` | no | 77 | | redis\_version | Redis version to use, defaults to 3.2.10 | `string` | `"3.2.10"` | no | 78 | | security\_group\_names | A list of cache security group names to associate with this replication group | `list(string)` | `[]` | no | 79 | | snapshot\_arns | A single-element string list containing an Amazon Resource Name (ARN) of a Redis RDB snapshot file stored in Amazon S3. Example: arn:aws:s3:::my\_bucket/snapshot1.rdb | `list(string)` | `[]` | no | 80 | | snapshot\_name | The name of a snapshot from which to restore data into the new node group. Changing the snapshot\_name forces a new resource | `string` | `""` | no | 81 | | subnets | List of VPC Subnet IDs for the cache subnet group | `list(string)` | n/a | yes | 82 | | tags | Tags for redis nodes | `map(string)` | `{}` | no | 83 | | transit\_encryption\_enabled | Whether to enable encryption in transit. Requires 3.2.6 or >=4.0 redis\_version | `bool` | `false` | no | 84 | | vpc\_id | VPC ID | `string` | n/a | yes | 85 | 86 | ## Outputs 87 | 88 | | Name | Description | 89 | |------|-------------| 90 | | endpoint | n/a | 91 | | id | n/a | 92 | | parameter\_group | n/a | 93 | | port | n/a | 94 | | redis\_security\_group\_id | n/a | 95 | | redis\_subnet\_group\_name | n/a | 96 | 97 | 98 | 99 | ## Authors 100 | 101 | Created by [Tim Hartmann](https://github.com/tfhartmann). Maintained by [Anton Babenko](https://github.com/antonbabenko) and [these awesome contributors](https://github.com/terraform-community-modules/tf_aws_elasticache_redis/graphs/contributors). 102 | 103 | ## License 104 | 105 | [MIT License](LICENSE) 106 | -------------------------------------------------------------------------------- /cloudwatch.tf: -------------------------------------------------------------------------------- 1 | # Cloudwatch resources inspired by https://github.com/azavea/terraform-aws-redis-elasticache 2 | # Stubbing this out, we should have conversation about monitoring before we make this the default behavior 3 | # For this module 4 | /* 5 | 6 | resource "aws_cloudwatch_metric_alarm" "cache_cpu" { 7 | count = "${var.redis_clusters}" 8 | 9 | alarm_name = "alarm-${var.name}-${local.vpc_name}-CacheCluster00${count.index + 1}CPUUtilization" 10 | alarm_description = "Redis cluster CPU utilization" 11 | comparison_operator = "GreaterThanThreshold" 12 | evaluation_periods = "1" 13 | metric_name = "CPUUtilization" 14 | namespace = "AWS/ElastiCache" 15 | period = "300" 16 | statistic = "Average" 17 | 18 | threshold = "${var.alarm_cpu_threshold}" 19 | 20 | dimensions { 21 | CacheClusterId = "${aws_elasticache_replication_group.redis.id}-00${count.index + 1}" 22 | } 23 | 24 | alarm_actions = ["${var.alarm_actions}"] 25 | } 26 | 27 | resource "aws_cloudwatch_metric_alarm" "cache_memory" { 28 | count = "${var.redis_clusters}" 29 | 30 | alarm_name = "alarm-${var.name}-${local.vpc_name}-CacheCluster00${count.index + 1}FreeableMemory" 31 | alarm_description = "Redis cluster freeable memory" 32 | comparison_operator = "LessThanThreshold" 33 | evaluation_periods = "1" 34 | metric_name = "FreeableMemory" 35 | namespace = "AWS/ElastiCache" 36 | period = "60" 37 | statistic = "Average" 38 | 39 | threshold = "${var.alarm_memory_threshold}" 40 | 41 | dimensions { 42 | CacheClusterId = "${aws_elasticache_replication_group.redis.id}-00${count.index + 1}" 43 | } 44 | 45 | alarm_actions = ["${var.alarm_actions}"] 46 | } 47 | */ 48 | 49 | -------------------------------------------------------------------------------- /main.tf: -------------------------------------------------------------------------------- 1 | data "aws_vpc" "vpc" { 2 | id = var.vpc_id 3 | } 4 | 5 | locals { 6 | vpc_name = lookup(data.aws_vpc.vpc.tags, "Name", var.vpc_id) 7 | parameter_group_family = substr(var.redis_version, 0,1) < 6 ? "redis${replace(var.redis_version, "/\\.[\\d]+$/", "")}": "redis${replace(var.redis_version, "/\\.[\\d]+$/", "")}.x" 8 | } 9 | 10 | resource "random_id" "salt" { 11 | byte_length = 8 12 | keepers = { 13 | redis_version = var.redis_version 14 | } 15 | } 16 | 17 | resource "aws_elasticache_replication_group" "redis" { 18 | replication_group_id = format("%.20s", "${var.name}-${var.env}") 19 | replication_group_description = "Terraform-managed ElastiCache replication group for ${var.name}-${var.env}-${local.vpc_name}" 20 | number_cache_clusters = var.redis_clusters 21 | node_type = var.redis_node_type 22 | automatic_failover_enabled = var.redis_failover 23 | auto_minor_version_upgrade = var.auto_minor_version_upgrade 24 | availability_zones = var.availability_zones 25 | multi_az_enabled = var.multi_az_enabled 26 | engine = "redis" 27 | at_rest_encryption_enabled = var.at_rest_encryption_enabled 28 | kms_key_id = var.kms_key_id 29 | transit_encryption_enabled = var.transit_encryption_enabled 30 | auth_token = var.transit_encryption_enabled ? var.auth_token : null 31 | engine_version = var.redis_version 32 | port = var.redis_port 33 | parameter_group_name = aws_elasticache_parameter_group.redis_parameter_group.id 34 | subnet_group_name = aws_elasticache_subnet_group.redis_subnet_group.id 35 | security_group_names = var.security_group_names 36 | security_group_ids = [aws_security_group.redis_security_group.id] 37 | snapshot_arns = var.snapshot_arns 38 | snapshot_name = var.snapshot_name 39 | apply_immediately = var.apply_immediately 40 | maintenance_window = var.redis_maintenance_window 41 | notification_topic_arn = var.notification_topic_arn 42 | snapshot_window = var.redis_snapshot_window 43 | snapshot_retention_limit = var.redis_snapshot_retention_limit 44 | tags = merge(tomap({"Name" = format("tf-elasticache-%s-%s", var.name, local.vpc_name)}), var.tags) 45 | } 46 | 47 | resource "aws_elasticache_parameter_group" "redis_parameter_group" { 48 | name = replace(format("%.255s", lower(replace("tf-redis-${var.name}-${var.env}-${local.vpc_name}-${random_id.salt.hex}", "_", "-"))), "/\\s/", "-") 49 | 50 | description = "Terraform-managed ElastiCache parameter group for ${var.name}-${var.env}-${local.vpc_name}" 51 | 52 | # Strip the patch version from redis_version var 53 | family = local.parameter_group_family 54 | dynamic "parameter" { 55 | for_each = var.redis_parameters 56 | content { 57 | name = parameter.value.name 58 | value = parameter.value.value 59 | } 60 | } 61 | 62 | lifecycle { 63 | create_before_destroy = true 64 | } 65 | } 66 | 67 | resource "aws_elasticache_subnet_group" "redis_subnet_group" { 68 | name = replace(format("%.255s", lower(replace("tf-redis-${var.name}-${var.env}-${local.vpc_name}", "_", "-"))), "/\\s/", "-") 69 | subnet_ids = var.subnets 70 | } 71 | -------------------------------------------------------------------------------- /outputs.tf: -------------------------------------------------------------------------------- 1 | output "redis_security_group_id" { 2 | value = aws_security_group.redis_security_group.id 3 | } 4 | 5 | output "parameter_group" { 6 | value = aws_elasticache_parameter_group.redis_parameter_group.id 7 | } 8 | 9 | output "redis_subnet_group_name" { 10 | value = aws_elasticache_subnet_group.redis_subnet_group.name 11 | } 12 | 13 | output "id" { 14 | value = aws_elasticache_replication_group.redis.id 15 | } 16 | 17 | output "port" { 18 | value = var.redis_port 19 | } 20 | 21 | output "endpoint" { 22 | value = aws_elasticache_replication_group.redis.primary_endpoint_address 23 | } 24 | -------------------------------------------------------------------------------- /security_groups.tf: -------------------------------------------------------------------------------- 1 | resource "aws_security_group" "redis_security_group" { 2 | name = format("%.255s", "tf-sg-ec-${var.name}-${var.env}-${local.vpc_name}") 3 | description = "Terraform-managed ElastiCache security group for ${var.name}-${var.env}-${local.vpc_name}" 4 | vpc_id = data.aws_vpc.vpc.id 5 | 6 | tags = { 7 | Name = "tf-sg-ec-${var.name}-${var.env}-${local.vpc_name}" 8 | } 9 | } 10 | 11 | resource "aws_security_group_rule" "redis_ingress" { 12 | count = length(var.allowed_security_groups) 13 | type = "ingress" 14 | from_port = var.redis_port 15 | to_port = var.redis_port 16 | protocol = "tcp" 17 | source_security_group_id = element(var.allowed_security_groups, count.index) 18 | security_group_id = aws_security_group.redis_security_group.id 19 | } 20 | 21 | resource "aws_security_group_rule" "redis_networks_ingress" { 22 | type = "ingress" 23 | from_port = var.redis_port 24 | to_port = var.redis_port 25 | protocol = "tcp" 26 | cidr_blocks = var.allowed_cidr 27 | security_group_id = aws_security_group.redis_security_group.id 28 | } 29 | -------------------------------------------------------------------------------- /variables.tf: -------------------------------------------------------------------------------- 1 | /* 2 | # These vars would be used by cloudwatch.tf and should be uncommented if we decide to use them. 3 | variable "alarm_cpu_threshold" { 4 | default = "75" 5 | } 6 | 7 | variable "alarm_memory_threshold" { 8 | # 10MB 9 | default = "10000000" 10 | } 11 | 12 | variable "alarm_actions" { 13 | type = "list" 14 | } 15 | */ 16 | 17 | variable "apply_immediately" { 18 | description = "Specifies whether any modifications are applied immediately, or during the next maintenance window. Default is false." 19 | type = bool 20 | default = false 21 | } 22 | 23 | variable "allowed_cidr" { 24 | description = "A list of Security Group ID's to allow access to." 25 | type = list(string) 26 | default = ["127.0.0.1/32"] 27 | } 28 | 29 | variable "allowed_security_groups" { 30 | description = "A list of Security Group ID's to allow access to." 31 | type = list(string) 32 | default = [] 33 | } 34 | 35 | variable "env" { 36 | description = "env to deploy into, should typically dev/staging/prod" 37 | type = string 38 | } 39 | 40 | variable "name" { 41 | description = "Name for the Redis replication group i.e. UserObject" 42 | type = string 43 | } 44 | 45 | variable "redis_clusters" { 46 | description = "Number of Redis cache clusters (nodes) to create" 47 | type = string 48 | } 49 | 50 | variable "redis_failover" { 51 | type = bool 52 | default = false 53 | } 54 | 55 | variable "multi_az_enabled" { 56 | type = bool 57 | default = false 58 | } 59 | 60 | variable "redis_node_type" { 61 | description = "Instance type to use for creating the Redis cache clusters" 62 | type = string 63 | default = "cache.m3.medium" 64 | } 65 | 66 | variable "redis_port" { 67 | type = number 68 | default = 6379 69 | } 70 | 71 | variable "subnets" { 72 | type = list(string) 73 | description = "List of VPC Subnet IDs for the cache subnet group" 74 | } 75 | 76 | # might want a map 77 | variable "redis_version" { 78 | description = "Redis version to use, defaults to 3.2.10" 79 | type = string 80 | default = "3.2.10" 81 | } 82 | 83 | variable "vpc_id" { 84 | description = "VPC ID" 85 | type = string 86 | } 87 | 88 | variable "redis_parameters" { 89 | description = "additional parameters modifyed in parameter group" 90 | type = list(map(any)) 91 | default = [] 92 | } 93 | 94 | variable "redis_maintenance_window" { 95 | description = "Specifies the weekly time range for when maintenance on the cache cluster is performed. The format is ddd:hh24:mi-ddd:hh24:mi (24H Clock UTC). The minimum maintenance window is a 60 minute period" 96 | type = string 97 | default = "fri:08:00-fri:09:00" 98 | } 99 | 100 | variable "redis_snapshot_window" { 101 | description = "The daily time range (in UTC) during which ElastiCache will begin taking a daily snapshot of your cache cluster. The minimum snapshot window is a 60 minute period" 102 | type = string 103 | default = "06:30-07:30" 104 | } 105 | 106 | variable "redis_snapshot_retention_limit" { 107 | description = "The number of days for which ElastiCache will retain automatic cache cluster snapshots before deleting them. For example, if you set SnapshotRetentionLimit to 5, then a snapshot that was taken today will be retained for 5 days before being deleted. If the value of SnapshotRetentionLimit is set to zero (0), backups are turned off. Please note that setting a snapshot_retention_limit is not supported on cache.t1.micro or cache.t2.* cache nodes" 108 | type = number 109 | default = 0 110 | } 111 | 112 | variable "tags" { 113 | description = "Tags for redis nodes" 114 | type = map(string) 115 | default = {} 116 | } 117 | 118 | variable "auto_minor_version_upgrade" { 119 | description = "Specifies whether a minor engine upgrades will be applied automatically to the underlying Cache Cluster instances during the maintenance window" 120 | type = bool 121 | default = true 122 | } 123 | 124 | variable "availability_zones" { 125 | description = "A list of EC2 availability zones in which the replication group's cache clusters will be created. The order of the availability zones in the list is not important" 126 | type = list(string) 127 | default = [] 128 | } 129 | 130 | variable "at_rest_encryption_enabled" { 131 | description = "Whether to enable encryption at rest" 132 | type = bool 133 | default = false 134 | } 135 | 136 | variable "kms_key_id" { 137 | description = "The ARN of the key that you wish to use if encrypting at rest. If not supplied, uses service managed encryption. Can be specified only if at_rest_encryption_enabled = true" 138 | type = string 139 | default = "" 140 | } 141 | 142 | variable "transit_encryption_enabled" { 143 | description = "Whether to enable encryption in transit. Requires 3.2.6 or >=4.0 redis_version" 144 | type = bool 145 | default = false 146 | } 147 | 148 | variable "auth_token" { 149 | description = "The password used to access a password protected server. Can be specified only if transit_encryption_enabled = true. If specified must contain from 16 to 128 alphanumeric characters or symbols" 150 | type = string 151 | default = null 152 | } 153 | 154 | variable "security_group_names" { 155 | description = "A list of cache security group names to associate with this replication group" 156 | type = list(string) 157 | default = [] 158 | } 159 | 160 | variable "snapshot_arns" { 161 | description = "A single-element string list containing an Amazon Resource Name (ARN) of a Redis RDB snapshot file stored in Amazon S3. Example: arn:aws:s3:::my_bucket/snapshot1.rdb" 162 | type = list(string) 163 | default = [] 164 | } 165 | 166 | variable "snapshot_name" { 167 | description = " The name of a snapshot from which to restore data into the new node group. Changing the snapshot_name forces a new resource" 168 | type = string 169 | default = "" 170 | } 171 | 172 | variable "notification_topic_arn" { 173 | description = "An Amazon Resource Name (ARN) of an SNS topic to send ElastiCache notifications to. Example: arn:aws:sns:us-east-1:012345678999:my_sns_topic" 174 | type = string 175 | default = "" 176 | } 177 | --------------------------------------------------------------------------------
"127.0.0.1/32"
]