From ef235242d76648bb7e177d35e4a6220559228d3a Mon Sep 17 00:00:00 2001 From: James Johnson Date: Fri, 24 Aug 2018 00:25:45 -0400 Subject: [PATCH 1/9] First pass at using launch_template as an alternative to launch_configuration so that we can apply tags to instance volumes Syntax, typos --- modules/vault-cluster/main.tf | 67 +++++++++++++++++++++++++++++- modules/vault-cluster/outputs.tf | 8 +++- modules/vault-cluster/variables.tf | 21 ++++++++++ 3 files changed, 92 insertions(+), 4 deletions(-) diff --git a/modules/vault-cluster/main.tf b/modules/vault-cluster/main.tf index 762b7832..53cbba5a 100644 --- a/modules/vault-cluster/main.tf +++ b/modules/vault-cluster/main.tf @@ -13,7 +13,8 @@ terraform { resource "aws_autoscaling_group" "autoscaling_group" { name_prefix = "${var.cluster_name}" - launch_configuration = "${aws_launch_configuration.launch_configuration.name}" + launch_configuration = "${var.use_launch_template ? 0 : aws_launch_configuration.launch_configuration.*.name[0]}" + launch_template = "${var.use_launch_template ? aws_launch_template.launch_template.*.name[0] : 0}" availability_zones = ["${var.availability_zones}"] vpc_zone_identifier = ["${var.subnet_ids}"] @@ -41,6 +42,7 @@ resource "aws_autoscaling_group" "autoscaling_group" { # --------------------------------------------------------------------------------------------------------------------- resource "aws_launch_configuration" "launch_configuration" { + count = "${var.use_launch_template ? 0 : 1}" name_prefix = "${var.cluster_name}-" image_id = "${var.ami_id}" instance_type = "${var.instance_type}" @@ -72,6 +74,66 @@ resource "aws_launch_configuration" "launch_configuration" { } } +data "aws_ami" "ami" { + filter { + name = "image-id" + values = ["${var.ami_id}"] + } +} + +resource "aws_launch_template" "launch_template" { + count = "${var.use_launch_template ? 1 : 0}" + name_prefix = "${var.cluster_name}-" + image_id = "${var.ami_id}" + instance_type = "${var.instance_type}" + user_data = "${var.user_data}" + + iam_instance_profile { + name = "${aws_iam_instance_profile.instance_profile.name}" + } + + key_name = "${var.ssh_key_name}" + vpc_security_group_ids = ["${concat(list(aws_security_group.lc_security_group.id), var.additional_security_group_ids)}"] + + placement { + tenancy = "${var.tenancy}" + } + + network_interfaces { + associate_public_ip_address = "${var.associate_public_ip_address}" + } + + ebs_optimized = "${var.root_volume_ebs_optimized}" + + block_device { + device_name = "${data.aws_ami.ami.root_device_name}" + volume_type = "${var.root_volume_type}" + volume_size = "${var.root_volume_size}" + delete_on_termination = "${var.root_volume_delete_on_termination}" + } + + tag_specifications { + # Instanc tags are already handled by the autoscaling group + resource_type = "volume" + + tags = "${merge( + map("key", var.cluster_tag_key, "value", var.cluster_name), + var.volume_extra_tags) + }" + } + + # Important note: whenever using a launch configuration with an auto scaling group, you must set + # create_before_destroy = true. However, as soon as you set create_before_destroy = true in one resource, you must + # also set it in every resource that it depends on, or you'll get an error about cyclic dependencies (especially when + # removing resources). For more info, see: + # + # https://www.terraform.io/docs/providers/aws/r/launch_configuration.html + # https://terraform.io/docs/configuration/resources.html + lifecycle { + create_before_destroy = true + } +} + # --------------------------------------------------------------------------------------------------------------------- # CREATE A SECURITY GROUP TO CONTROL WHAT REQUESTS CAN GO IN AND OUT OF EACH EC2 INSTANCE # --------------------------------------------------------------------------------------------------------------------- @@ -201,7 +263,8 @@ resource "aws_iam_role_policy" "vault_s3" { } data "aws_iam_policy_document" "vault_s3" { - count = "${var.enable_s3_backend ? 1 : 0}" + count = "${var.enable_s3_backend ? 1 : 0}" + statement { effect = "Allow" actions = ["s3:*"] diff --git a/modules/vault-cluster/outputs.tf b/modules/vault-cluster/outputs.tf index 1acf4b26..d5926c3b 100644 --- a/modules/vault-cluster/outputs.tf +++ b/modules/vault-cluster/outputs.tf @@ -15,7 +15,11 @@ output "cluster_size" { } output "launch_config_name" { - value = "${aws_launch_configuration.launch_configuration.name}" + value = "${var.use_launch_template ? "" : aws_launch_configuration.launch_configuration.*.name[0]}" +} + +output "launch_template_name" { + value = "${var.use_launch_template ? aws_launch_template.launch_template.*.name[0] : ""}" } output "iam_role_arn" { @@ -32,4 +36,4 @@ output "security_group_id" { output "s3_bucket_arn" { value = "${join(",", aws_s3_bucket.vault_storage.*.arn)}" -} \ No newline at end of file +} diff --git a/modules/vault-cluster/variables.tf b/modules/vault-cluster/variables.tf index 03039be7..01ad3acc 100644 --- a/modules/vault-cluster/variables.tf +++ b/modules/vault-cluster/variables.tf @@ -5,40 +5,49 @@ variable "cluster_name" { description = "The name of the Vault cluster (e.g. vault-stage). This variable is used to namespace all resources created by this module." + default = "fred" } variable "ami_id" { description = "The ID of the AMI to run in this cluster. Should be an AMI that had Vault installed and configured by the install-vault module." + default = "123" } variable "instance_type" { description = "The type of EC2 Instances to run for each node in the cluster (e.g. t2.micro)." + default = "t2.micro" } variable "vpc_id" { description = "The ID of the VPC in which to deploy the cluster" + default = "123" } variable "allowed_inbound_cidr_blocks" { description = "A list of CIDR-formatted IP address ranges from which the EC2 Instances will allow connections to Vault" type = "list" + default = [] } variable "allowed_inbound_security_group_ids" { description = "A list of security group IDs that will be allowed to connect to Vault" type = "list" + default = [] } variable "allowed_inbound_security_group_count" { description = "The number of entries in var.allowed_inbound_security_group_ids. Ideally, this value could be computed dynamically, but we pass this variable to a Terraform resource's 'count' property and Terraform requires that 'count' be computed with literals or data sources only." + default = 0 } variable "user_data" { description = "A User Data script to execute while the server is booting. We recommend passing in a bash script that executes the run-vault script, which should have been installed in the AMI by the install-vault module." + default = "#!/bin/bash" } variable "cluster_size" { description = "The number of nodes to have in the cluster. We strongly recommend setting this to 3 or 5." + default = 1 } # --------------------------------------------------------------------------------------------------------------------- @@ -197,3 +206,15 @@ variable "force_destroy_s3_bucket" { description = "If 'configure_s3_backend' is enabled and you set this to true, when you run terraform destroy, this tells Terraform to delete all the objects in the S3 bucket used for backend storage. You should NOT set this to true in production or you risk losing all your data! This property is only here so automated tests of this module can clean up after themselves. Only used if 'enable_s3_backend' is set to true." default = false } + +variable "use_launch_template" { + description = "Use aws_launch_template resource instead of aws_launch_configuration. Enables volume_extra_tags." + default = false +} + +variable "volume_extra_tags" { + description = "A list of additional tags to add to each Instance's volumes in the ASG. Only applicable when use_launch_template is true." + type = "map" + default = {} +} + From 72aee0343fc697b282f70aecca5a512fa040542d Mon Sep 17 00:00:00 2001 From: James Johnson Date: Fri, 24 Aug 2018 10:45:08 -0400 Subject: [PATCH 2/9] WIP experiment but failed due to: https://github.com/terraform-providers/terraform-provider-aws/issues/4553 --- modules/vault-cluster/main.tf | 50 +++++++++++++++--------------- modules/vault-cluster/outputs.tf | 6 +--- modules/vault-cluster/variables.tf | 20 +++++------- 3 files changed, 34 insertions(+), 42 deletions(-) diff --git a/modules/vault-cluster/main.tf b/modules/vault-cluster/main.tf index 53cbba5a..c30aab2c 100644 --- a/modules/vault-cluster/main.tf +++ b/modules/vault-cluster/main.tf @@ -13,22 +13,21 @@ terraform { resource "aws_autoscaling_group" "autoscaling_group" { name_prefix = "${var.cluster_name}" - launch_configuration = "${var.use_launch_template ? 0 : aws_launch_configuration.launch_configuration.*.name[0]}" - launch_template = "${var.use_launch_template ? aws_launch_template.launch_template.*.name[0] : 0}" + # launch_configuration = "${aws_launch_configuration.launch_configuration.name}" + launch_template { + id = "${aws_launch_template.launch_template.id}" + } availability_zones = ["${var.availability_zones}"] vpc_zone_identifier = ["${var.subnet_ids}"] - # Use a fixed-size cluster - min_size = "${var.cluster_size}" - max_size = "${var.cluster_size}" - desired_capacity = "${var.cluster_size}" - termination_policies = ["${var.termination_policies}"] - + min_size = "${var.cluster_size}" + max_size = "${var.cluster_size}" + desired_capacity = "${var.cluster_size}" + termination_policies = ["${var.termination_policies}"] health_check_type = "${var.health_check_type}" health_check_grace_period = "${var.health_check_grace_period}" wait_for_capacity_timeout = "${var.wait_for_capacity_timeout}" - tags = ["${concat( list( map("key", var.cluster_tag_key, "value", var.cluster_name, "propagate_at_launch", true) @@ -38,11 +37,10 @@ resource "aws_autoscaling_group" "autoscaling_group" { } # --------------------------------------------------------------------------------------------------------------------- -# CREATE LAUNCH CONFIGURATION TO DEFINE WHAT RUNS ON EACH INSTANCE IN THE ASG +# CREATE LAUNCH TEMPLATE TO DEFINE WHAT RUNS ON EACH INSTANCE IN THE ASG # --------------------------------------------------------------------------------------------------------------------- resource "aws_launch_configuration" "launch_configuration" { - count = "${var.use_launch_template ? 0 : 1}" name_prefix = "${var.cluster_name}-" image_id = "${var.ami_id}" instance_type = "${var.instance_type}" @@ -82,11 +80,10 @@ data "aws_ami" "ami" { } resource "aws_launch_template" "launch_template" { - count = "${var.use_launch_template ? 1 : 0}" name_prefix = "${var.cluster_name}-" image_id = "${var.ami_id}" instance_type = "${var.instance_type}" - user_data = "${var.user_data}" + user_data = "${base64encode(var.user_data)}" iam_instance_profile { name = "${aws_iam_instance_profile.instance_profile.name}" @@ -99,21 +96,25 @@ resource "aws_launch_template" "launch_template" { tenancy = "${var.tenancy}" } - network_interfaces { - associate_public_ip_address = "${var.associate_public_ip_address}" - } + # network_interfaces { + # associate_public_ip_address = "${var.associate_public_ip_address}" + # security_groups = ["${concat(list(aws_security_group.lc_security_group.id), var.additional_security_group_ids)}"] + # } ebs_optimized = "${var.root_volume_ebs_optimized}" - - block_device { - device_name = "${data.aws_ami.ami.root_device_name}" - volume_type = "${var.root_volume_type}" - volume_size = "${var.root_volume_size}" - delete_on_termination = "${var.root_volume_delete_on_termination}" + block_device_mappings { + device_name = "${data.aws_ami.ami.root_device_name}" + + ebs { + encrypted = "${var.ebs_encryption}" + volume_type = "${var.root_volume_type}" + volume_size = "${var.root_volume_size}" + delete_on_termination = "${var.root_volume_delete_on_termination}" + } } - + tags = "${var.launch_template_tags}" tag_specifications { - # Instanc tags are already handled by the autoscaling group + # Instance tags are already handled by the autoscaling group resource_type = "volume" tags = "${merge( @@ -121,7 +122,6 @@ resource "aws_launch_template" "launch_template" { var.volume_extra_tags) }" } - # Important note: whenever using a launch configuration with an auto scaling group, you must set # create_before_destroy = true. However, as soon as you set create_before_destroy = true in one resource, you must # also set it in every resource that it depends on, or you'll get an error about cyclic dependencies (especially when diff --git a/modules/vault-cluster/outputs.tf b/modules/vault-cluster/outputs.tf index d5926c3b..2ec6d6ed 100644 --- a/modules/vault-cluster/outputs.tf +++ b/modules/vault-cluster/outputs.tf @@ -14,12 +14,8 @@ output "cluster_size" { value = "${aws_autoscaling_group.autoscaling_group.desired_capacity}" } -output "launch_config_name" { - value = "${var.use_launch_template ? "" : aws_launch_configuration.launch_configuration.*.name[0]}" -} - output "launch_template_name" { - value = "${var.use_launch_template ? aws_launch_template.launch_template.*.name[0] : ""}" + value = "${aws_launch_template.launch_template.name}" } output "iam_role_arn" { diff --git a/modules/vault-cluster/variables.tf b/modules/vault-cluster/variables.tf index 01ad3acc..e8fd69fc 100644 --- a/modules/vault-cluster/variables.tf +++ b/modules/vault-cluster/variables.tf @@ -5,49 +5,40 @@ variable "cluster_name" { description = "The name of the Vault cluster (e.g. vault-stage). This variable is used to namespace all resources created by this module." - default = "fred" } variable "ami_id" { description = "The ID of the AMI to run in this cluster. Should be an AMI that had Vault installed and configured by the install-vault module." - default = "123" } variable "instance_type" { description = "The type of EC2 Instances to run for each node in the cluster (e.g. t2.micro)." - default = "t2.micro" } variable "vpc_id" { description = "The ID of the VPC in which to deploy the cluster" - default = "123" } variable "allowed_inbound_cidr_blocks" { description = "A list of CIDR-formatted IP address ranges from which the EC2 Instances will allow connections to Vault" type = "list" - default = [] } variable "allowed_inbound_security_group_ids" { description = "A list of security group IDs that will be allowed to connect to Vault" type = "list" - default = [] } variable "allowed_inbound_security_group_count" { description = "The number of entries in var.allowed_inbound_security_group_ids. Ideally, this value could be computed dynamically, but we pass this variable to a Terraform resource's 'count' property and Terraform requires that 'count' be computed with literals or data sources only." - default = 0 } variable "user_data" { description = "A User Data script to execute while the server is booting. We recommend passing in a bash script that executes the run-vault script, which should have been installed in the AMI by the install-vault module." - default = "#!/bin/bash" } variable "cluster_size" { description = "The number of nodes to have in the cluster. We strongly recommend setting this to 3 or 5." - default = 1 } # --------------------------------------------------------------------------------------------------------------------- @@ -207,9 +198,10 @@ variable "force_destroy_s3_bucket" { default = false } -variable "use_launch_template" { - description = "Use aws_launch_template resource instead of aws_launch_configuration. Enables volume_extra_tags." - default = false +variable "launch_template_tags" { + description = "A list of tags to add to the launch template." + type = "map" + default = {} } variable "volume_extra_tags" { @@ -218,3 +210,7 @@ variable "volume_extra_tags" { default = {} } +variable "ebs_encryption" { + description = "Value of 'encrypted' attribute on the launch template's block device definition." + default = false +} From 0ee25b9eae40925dc8532fe749bc9904fe5c9387 Mon Sep 17 00:00:00 2001 From: James Johnson Date: Mon, 27 Aug 2018 21:11:29 -0400 Subject: [PATCH 3/9] Set the cluster name tag (etc) after cluster_extra_tags (etc) so that cluster_extra_tags can't overwrite it. --- modules/vault-cluster/main.tf | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/modules/vault-cluster/main.tf b/modules/vault-cluster/main.tf index c30aab2c..ea02315f 100644 --- a/modules/vault-cluster/main.tf +++ b/modules/vault-cluster/main.tf @@ -29,10 +29,11 @@ resource "aws_autoscaling_group" "autoscaling_group" { health_check_grace_period = "${var.health_check_grace_period}" wait_for_capacity_timeout = "${var.wait_for_capacity_timeout}" tags = ["${concat( + var.cluster_extra_tags, list( map("key", var.cluster_tag_key, "value", var.cluster_name, "propagate_at_launch", true) - ), - var.cluster_extra_tags) + ) + ) }"] } @@ -118,8 +119,9 @@ resource "aws_launch_template" "launch_template" { resource_type = "volume" tags = "${merge( - map("key", var.cluster_tag_key, "value", var.cluster_name), - var.volume_extra_tags) + var.volume_extra_tags, + map("key", var.cluster_tag_key, "value", var.cluster_name) + ) }" } # Important note: whenever using a launch configuration with an auto scaling group, you must set @@ -150,7 +152,7 @@ resource "aws_security_group" "lc_security_group" { create_before_destroy = true } - tags = "${merge(map("Name", var.cluster_name), var.security_group_tags)}" + tags = "${merge(var.security_group_tags, map("Name", var.cluster_name))}" } resource "aws_security_group_rule" "allow_ssh_inbound_from_cidr_blocks" { From 055132e52782b5527866a94eb2a705803234e1ba Mon Sep 17 00:00:00 2001 From: James Johnson Date: Mon, 27 Aug 2018 21:16:18 -0400 Subject: [PATCH 4/9] It's not pretty but it works. Though I think we should wait for https://github.com/terraform-providers/terraform-provider-aws/issues/4553 to be fixed & then do a cleaner implementation. To make this work, I have to do: terraform apply -target aws_iam_instance_profile.instance_profile -var-file inputs modules/vault-cluster/ terraform apply -var-file inputs modules/vault-cluster/ --- modules/vault-cluster/main.tf | 46 ++++++++++++++++++++++++++--------- 1 file changed, 35 insertions(+), 11 deletions(-) diff --git a/modules/vault-cluster/main.tf b/modules/vault-cluster/main.tf index ea02315f..a45d30d9 100644 --- a/modules/vault-cluster/main.tf +++ b/modules/vault-cluster/main.tf @@ -15,8 +15,10 @@ resource "aws_autoscaling_group" "autoscaling_group" { # launch_configuration = "${aws_launch_configuration.launch_configuration.name}" + depends_on = ["aws_iam_instance_profile.instance_profile", "aws_launch_template.launch_template"] launch_template { - id = "${aws_launch_template.launch_template.id}" + id = "${aws_launch_template.launch_template.id}" + version = "$$Latest" } availability_zones = ["${var.availability_zones}"] vpc_zone_identifier = ["${var.subnet_ids}"] @@ -86,22 +88,26 @@ resource "aws_launch_template" "launch_template" { instance_type = "${var.instance_type}" user_data = "${base64encode(var.user_data)}" + depends_on = ["aws_iam_instance_profile.instance_profile"] + iam_instance_profile { name = "${aws_iam_instance_profile.instance_profile.name}" } - key_name = "${var.ssh_key_name}" - vpc_security_group_ids = ["${concat(list(aws_security_group.lc_security_group.id), var.additional_security_group_ids)}"] + key_name = "${var.ssh_key_name}" + + # Don't use vpc_security_group_ids when network_interfaces + # includes security_groups. + # vpc_security_group_ids = ["${concat(list(aws_security_group.lc_security_group.id), var.additional_security_group_ids)}"] placement { tenancy = "${var.tenancy}" } - - # network_interfaces { - # associate_public_ip_address = "${var.associate_public_ip_address}" - # security_groups = ["${concat(list(aws_security_group.lc_security_group.id), var.additional_security_group_ids)}"] - # } - + network_interfaces { + associate_public_ip_address = "${var.associate_public_ip_address}" + delete_on_termination = true + security_groups = ["${concat(list(aws_security_group.lc_security_group.id), var.additional_security_group_ids)}"] + } ebs_optimized = "${var.root_volume_ebs_optimized}" block_device_mappings { device_name = "${data.aws_ami.ami.root_device_name}" @@ -136,6 +142,23 @@ resource "aws_launch_template" "launch_template" { } } +resource "null_resource" "update_launch_template" { + # + # Any time the launch configuration changes we need to use the CLI to create a + # new version of the template without the encryption method. I have only tested + # this where var.ebs_encryption is false. + # Got the idea & code from: + # https://github.com/terraform-providers/terraform-provider-aws/issues/4553#issuecomment-414716171 + # + triggers { + launch_template_version = "${aws_launch_template.launch_template.latest_version}" + } + + provisioner "local-exec" { + command = "${var.ebs_encryption} || (sleep 5; aws ec2 create-launch-template-version --launch-template-id ${aws_launch_template.launch_template.id} --version-description turnOffEncryption --source-version '$$Latest' --launch-template-data '{\"BlockDeviceMappings\": [{\"DeviceName\": \"${data.aws_ami.ami.root_device_name}\", \"Ebs\": { \"VolumeSize\": ${var.root_volume_size}, \"VolumeType\": \"${var.root_volume_type}\" }}]}')" + } +} + # --------------------------------------------------------------------------------------------------------------------- # CREATE A SECURITY GROUP TO CONTROL WHAT REQUESTS CAN GO IN AND OUT OF EACH EC2 INSTANCE # --------------------------------------------------------------------------------------------------------------------- @@ -252,8 +275,9 @@ resource "aws_s3_bucket" "vault_storage" { force_destroy = "${var.force_destroy_s3_bucket}" tags = "${merge( - map("Description", "Used for secret storage with Vault. DO NOT DELETE this Bucket unless you know what you are doing."), - var.s3_bucket_tags) + var.s3_bucket_tags, + map("Description", "Used for secret storage with Vault. DO NOT DELETE this Bucket unless you know what you are doing.") + ) }" } From af10a1fa4959c8348a891a6d65860958d02795e8 Mon Sep 17 00:00:00 2001 From: James Johnson Date: Mon, 1 Oct 2018 13:45:52 -0400 Subject: [PATCH 5/9] Working launch_template without any hacks. Tested with AWS provider 1.38.0 and root_volume_ebs_encryption="" Does not work for *my* usecase with any other value for root_volume_ebs_encryption --- modules/vault-cluster/main.tf | 77 +++++++++++++++++++----------- modules/vault-cluster/outputs.tf | 12 ++--- modules/vault-cluster/variables.tf | 22 +++++++-- 3 files changed, 73 insertions(+), 38 deletions(-) diff --git a/modules/vault-cluster/main.tf b/modules/vault-cluster/main.tf index a45d30d9..bb03cc2a 100644 --- a/modules/vault-cluster/main.tf +++ b/modules/vault-cluster/main.tf @@ -11,25 +11,60 @@ terraform { # --------------------------------------------------------------------------------------------------------------------- resource "aws_autoscaling_group" "autoscaling_group" { + count = "${var.asg_launch_mechanism == "launch_configuration" ? 1 : 0}" name_prefix = "${var.cluster_name}" - # launch_configuration = "${aws_launch_configuration.launch_configuration.name}" + launch_configuration = "${aws_launch_configuration.launch_configuration.name}" depends_on = ["aws_iam_instance_profile.instance_profile", "aws_launch_template.launch_template"] + + availability_zones = ["${var.availability_zones}"] + vpc_zone_identifier = ["${var.subnet_ids}"] + + # Use a fixed-size cluster + min_size = "${var.cluster_size}" + max_size = "${var.cluster_size}" + desired_capacity = "${var.cluster_size}" + termination_policies = ["${var.termination_policies}"] + + health_check_type = "${var.health_check_type}" + health_check_grace_period = "${var.health_check_grace_period}" + wait_for_capacity_timeout = "${var.wait_for_capacity_timeout}" + + tags = ["${concat( + var.cluster_extra_tags, + list( + map("key", var.cluster_tag_key, "value", var.cluster_name, "propagate_at_launch", true) + ) + ) + }"] +} + +# An alternate autoscaling group that uses a launch_template +resource "aws_autoscaling_group" "lt_autoscaling_group" { + count = "${var.asg_launch_mechanism == "launch_template" ? 1 : 0}" + name_prefix = "${var.cluster_name}" + launch_template { id = "${aws_launch_template.launch_template.id}" - version = "$$Latest" + version = "${var.launch_template_version}" } + + depends_on = ["aws_iam_instance_profile.instance_profile", "aws_launch_template.launch_template"] + availability_zones = ["${var.availability_zones}"] vpc_zone_identifier = ["${var.subnet_ids}"] + # Use a fixed-size cluster - min_size = "${var.cluster_size}" - max_size = "${var.cluster_size}" - desired_capacity = "${var.cluster_size}" - termination_policies = ["${var.termination_policies}"] + min_size = "${var.cluster_size}" + max_size = "${var.cluster_size}" + desired_capacity = "${var.cluster_size}" + termination_policies = ["${var.termination_policies}"] + health_check_type = "${var.health_check_type}" health_check_grace_period = "${var.health_check_grace_period}" wait_for_capacity_timeout = "${var.wait_for_capacity_timeout}" + tags = ["${concat( var.cluster_extra_tags, list( @@ -40,10 +75,11 @@ resource "aws_autoscaling_group" "autoscaling_group" { } # --------------------------------------------------------------------------------------------------------------------- -# CREATE LAUNCH TEMPLATE TO DEFINE WHAT RUNS ON EACH INSTANCE IN THE ASG +# CREATE LAUNCH CONFIGURATION TO DEFINE WHAT RUNS ON EACH INSTANCE IN THE ASG # --------------------------------------------------------------------------------------------------------------------- resource "aws_launch_configuration" "launch_configuration" { + count = "${var.asg_launch_mechanism == "launch_configuration" ? 1 : 0}" name_prefix = "${var.cluster_name}-" image_id = "${var.ami_id}" instance_type = "${var.instance_type}" @@ -75,6 +111,10 @@ resource "aws_launch_configuration" "launch_configuration" { } } +# --------------------------------------------------------------------------------------------------------------------- +# CREATE LAUNCH TEMPLATE TO DEFINE WHAT RUNS ON EACH INSTANCE IN THE ASG +# --------------------------------------------------------------------------------------------------------------------- + data "aws_ami" "ami" { filter { name = "image-id" @@ -83,6 +123,7 @@ data "aws_ami" "ami" { } resource "aws_launch_template" "launch_template" { + count = "${var.asg_launch_mechanism == "launch_template" ? 1 : 0}" name_prefix = "${var.cluster_name}-" image_id = "${var.ami_id}" instance_type = "${var.instance_type}" @@ -96,8 +137,7 @@ resource "aws_launch_template" "launch_template" { key_name = "${var.ssh_key_name}" - # Don't use vpc_security_group_ids when network_interfaces - # includes security_groups. + # Don't use vpc_security_group_ids when network_interfaces includes security_groups. # vpc_security_group_ids = ["${concat(list(aws_security_group.lc_security_group.id), var.additional_security_group_ids)}"] placement { @@ -113,7 +153,7 @@ resource "aws_launch_template" "launch_template" { device_name = "${data.aws_ami.ami.root_device_name}" ebs { - encrypted = "${var.ebs_encryption}" + encrypted = "${var.root_volume_ebs_encryption}" volume_type = "${var.root_volume_type}" volume_size = "${var.root_volume_size}" delete_on_termination = "${var.root_volume_delete_on_termination}" @@ -142,23 +182,6 @@ resource "aws_launch_template" "launch_template" { } } -resource "null_resource" "update_launch_template" { - # - # Any time the launch configuration changes we need to use the CLI to create a - # new version of the template without the encryption method. I have only tested - # this where var.ebs_encryption is false. - # Got the idea & code from: - # https://github.com/terraform-providers/terraform-provider-aws/issues/4553#issuecomment-414716171 - # - triggers { - launch_template_version = "${aws_launch_template.launch_template.latest_version}" - } - - provisioner "local-exec" { - command = "${var.ebs_encryption} || (sleep 5; aws ec2 create-launch-template-version --launch-template-id ${aws_launch_template.launch_template.id} --version-description turnOffEncryption --source-version '$$Latest' --launch-template-data '{\"BlockDeviceMappings\": [{\"DeviceName\": \"${data.aws_ami.ami.root_device_name}\", \"Ebs\": { \"VolumeSize\": ${var.root_volume_size}, \"VolumeType\": \"${var.root_volume_type}\" }}]}')" - } -} - # --------------------------------------------------------------------------------------------------------------------- # CREATE A SECURITY GROUP TO CONTROL WHAT REQUESTS CAN GO IN AND OUT OF EACH EC2 INSTANCE # --------------------------------------------------------------------------------------------------------------------- diff --git a/modules/vault-cluster/outputs.tf b/modules/vault-cluster/outputs.tf index 2ec6d6ed..ceb0f8a0 100644 --- a/modules/vault-cluster/outputs.tf +++ b/modules/vault-cluster/outputs.tf @@ -1,5 +1,7 @@ output "asg_name" { - value = "${aws_autoscaling_group.autoscaling_group.name}" + # This is safe because asg_launch_mechanism will only allow one of aws_autoscaling_group.autoscaling_group.* + # or aws_autoscaling_group.lt_autoscaling_group.* to be non-empty. + value = "${join("",concat(aws_autoscaling_group.autoscaling_group.*.name,aws_autoscaling_group.lt_autoscaling_group.*.name))}" } output "cluster_tag_key" { @@ -11,11 +13,9 @@ output "cluster_tag_value" { } output "cluster_size" { - value = "${aws_autoscaling_group.autoscaling_group.desired_capacity}" -} - -output "launch_template_name" { - value = "${aws_launch_template.launch_template.name}" + # This is safe because asg_launch_mechanism will only allow one of aws_autoscaling_group.autoscaling_group.* + # or aws_autoscaling_group.lt_autoscaling_group.* to be non-empty. + value = "${join("",concat(aws_autoscaling_group.autoscaling_group.*.desired_capacity,aws_autoscaling_group.lt_autoscaling_group.*.desired_capacity))}" } output "iam_role_arn" { diff --git a/modules/vault-cluster/variables.tf b/modules/vault-cluster/variables.tf index e8fd69fc..7b72d512 100644 --- a/modules/vault-cluster/variables.tf +++ b/modules/vault-cluster/variables.tf @@ -198,19 +198,31 @@ variable "force_destroy_s3_bucket" { default = false } +# Launch Template Extensions + +variable "asg_launch_mechanism" { + description = "Select between launch_config-driven or launch_template-driven autoscaling group." + default = "launch_config" +} + variable "launch_template_tags" { description = "A list of tags to add to the launch template." type = "map" default = {} } +variable "root_volume_ebs_encryption" { + description = "If true, the launched EC2 instance's root volume will be encrypted." + default = "" +} + +variable "launch_template_version" { + default = "Launch template verison to be used by the autoscaling group." + default = "$Latest" +} + variable "volume_extra_tags" { description = "A list of additional tags to add to each Instance's volumes in the ASG. Only applicable when use_launch_template is true." type = "map" default = {} } - -variable "ebs_encryption" { - description = "Value of 'encrypted' attribute on the launch template's block device definition." - default = false -} From cbd44e21a4dba3323f5e51ecd1f52732622ade8f Mon Sep 17 00:00:00 2001 From: James Johnson Date: Thu, 4 Oct 2018 15:22:41 -0400 Subject: [PATCH 6/9] Fix default vaule and explain the choices --- modules/vault-cluster/variables.tf | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/modules/vault-cluster/variables.tf b/modules/vault-cluster/variables.tf index 7b72d512..f039b937 100644 --- a/modules/vault-cluster/variables.tf +++ b/modules/vault-cluster/variables.tf @@ -201,8 +201,13 @@ variable "force_destroy_s3_bucket" { # Launch Template Extensions variable "asg_launch_mechanism" { + # Choices are launch_configuration and launch_template. + # launch_template gives you the opportunithy to declare volume encryption and + # set tags on instance volumes. + # description = "Select between launch_config-driven or launch_template-driven autoscaling group." - default = "launch_config" + + default = "launch_configuration" } variable "launch_template_tags" { From ed5cebec86eeb6055d40b30be1233141b2017085 Mon Sep 17 00:00:00 2001 From: jcej Date: Sat, 6 Oct 2018 14:22:43 -0400 Subject: [PATCH 7/9] Wrong dependency for launch_configuration based autoscaling group --- modules/vault-cluster/main.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/vault-cluster/main.tf b/modules/vault-cluster/main.tf index bb03cc2a..1c9fc85b 100644 --- a/modules/vault-cluster/main.tf +++ b/modules/vault-cluster/main.tf @@ -16,7 +16,7 @@ resource "aws_autoscaling_group" "autoscaling_group" { launch_configuration = "${aws_launch_configuration.launch_configuration.name}" - depends_on = ["aws_iam_instance_profile.instance_profile", "aws_launch_template.launch_template"] + depends_on = ["aws_iam_instance_profile.instance_profile", "aws_launch_configuration.launch_configuration"] availability_zones = ["${var.availability_zones}"] vpc_zone_identifier = ["${var.subnet_ids}"] From bb7a7a6f71408f644b0fcb1967502f767e01ba9b Mon Sep 17 00:00:00 2001 From: jcej Date: Sat, 6 Oct 2018 14:41:19 -0400 Subject: [PATCH 8/9] Cleaner approach for setting the cluster_size output value --- modules/vault-cluster/outputs.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/vault-cluster/outputs.tf b/modules/vault-cluster/outputs.tf index ceb0f8a0..efa92f3a 100644 --- a/modules/vault-cluster/outputs.tf +++ b/modules/vault-cluster/outputs.tf @@ -15,7 +15,7 @@ output "cluster_tag_value" { output "cluster_size" { # This is safe because asg_launch_mechanism will only allow one of aws_autoscaling_group.autoscaling_group.* # or aws_autoscaling_group.lt_autoscaling_group.* to be non-empty. - value = "${join("",concat(aws_autoscaling_group.autoscaling_group.*.desired_capacity,aws_autoscaling_group.lt_autoscaling_group.*.desired_capacity))}" + value = "${element(concat(aws_autoscaling_group.autoscaling_group.*.desired_capacity, aws_autoscaling_group.lt_autoscaling_group.*.desired_capacity), 0)}" } output "iam_role_arn" { From 234f63ba0050e7830057b7f8b3bf20bb4147f046 Mon Sep 17 00:00:00 2001 From: jcej Date: Sat, 6 Oct 2018 14:44:20 -0400 Subject: [PATCH 9/9] launch_configuration can also request volume encryption --- modules/vault-cluster/variables.tf | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/modules/vault-cluster/variables.tf b/modules/vault-cluster/variables.tf index f039b937..8d193bd4 100644 --- a/modules/vault-cluster/variables.tf +++ b/modules/vault-cluster/variables.tf @@ -202,8 +202,7 @@ variable "force_destroy_s3_bucket" { variable "asg_launch_mechanism" { # Choices are launch_configuration and launch_template. - # launch_template gives you the opportunithy to declare volume encryption and - # set tags on instance volumes. + # launch_template gives you the opportunithy to set tags on instance volumes. # description = "Select between launch_config-driven or launch_template-driven autoscaling group."