From 96e464ecbfd3a5bdee37ae5272eaea41a7672f2a Mon Sep 17 00:00:00 2001 From: Lachlan Donald Date: Tue, 11 Sep 2018 11:36:22 +1000 Subject: [PATCH 1/4] Ditch the aws module which uses cloudformation --- terraform/example.tf | 4 --- terraform/modules/example/main.tf | 59 +++++++++++++++++++++---------- 2 files changed, 40 insertions(+), 23 deletions(-) diff --git a/terraform/example.tf b/terraform/example.tf index 9c50490..e499030 100644 --- a/terraform/example.tf +++ b/terraform/example.tf @@ -2,10 +2,6 @@ terraform { required_version = "0.11.8" } -provider "aws" { - version = "1.34.0" -} - # Use the default VPC and subnets data "aws_vpc" "main" { default = true diff --git a/terraform/modules/example/main.tf b/terraform/modules/example/main.tf index 6517f4e..8b815eb 100644 --- a/terraform/modules/example/main.tf +++ b/terraform/modules/example/main.tf @@ -36,30 +36,46 @@ data "template_file" "main" { } } -# The autoscaling group -module "asg" { - source = "telia-oss/asg/aws" - version = "0.2.0" - - name_prefix = "${var.name_prefix}" - user_data = "${data.template_file.main.rendered}" - vpc_id = "${var.vpc_id}" - subnet_ids = "${var.subnet_ids}" - await_signal = "true" - pause_time = "PT5M" - health_check_type = "EC2" - instance_policy = "${data.aws_iam_policy_document.permissions.json}" - min_size = "${var.instance_count}" - instance_type = "${var.instance_type}" - instance_ami = "${var.instance_ami}" - instance_key = "${var.instance_key}" +resource "aws_launch_configuration" "main" { + name_prefix = "${var.name_prefix}" + image_id = "${var.instance_ami}" + instance_type = "${var.instance_type}" + key_name = "${var.instance_key}" + iam_instance_profile = "${aws_iam_instance_profile.lifecycle.name}" + security_groups = ["${aws_security_group.main.id}"] + + user_data = "${data.template_file.main.rendered}" + + lifecycle { + create_before_destroy = true + } +} + +resource "aws_autoscaling_group" "main" { + name = "${var.name_prefix}-${aws_launch_configuration.main.name}" + launch_configuration = "${aws_launch_configuration.main.id}" + vpc_zone_identifier = ["${var.subnet_ids}"] + + min_size = "0" + desired_capacity = "${var.instance_count}" + max_size = "1" tags = "${var.tags}" + + lifecycle { + create_before_destroy = true + } +} + +resource "aws_security_group" "main" { + name = "${var.name_prefix}-sg" + description = "Allow access to lifecycled instances" + vpc_id = "${var.vpc_id}" } # Allow SSH ingress if a EC2 key pair is specified. resource "aws_security_group_rule" "ssh_ingress" { count = "${var.instance_key != "" ? 1 : 0}" - security_group_id = "${module.asg.security_group_id}" + security_group_id = "${aws_security_group.main.id}" type = "ingress" protocol = "tcp" from_port = 22 @@ -155,7 +171,7 @@ resource "aws_sns_topic" "main" { # Lifecycle hook resource "aws_autoscaling_lifecycle_hook" "main" { name = "${var.name_prefix}-lifecycle" - autoscaling_group_name = "${module.asg.id}" + autoscaling_group_name = "${aws_autoscaling_group.main.id}" lifecycle_transition = "autoscaling:EC2_INSTANCE_TERMINATING" default_result = "CONTINUE" heartbeat_timeout = "60" @@ -163,6 +179,11 @@ resource "aws_autoscaling_lifecycle_hook" "main" { role_arn = "${aws_iam_role.lifecycle.arn}" } +resource "aws_iam_instance_profile" "lifecycle" { + name = "${var.name_prefix}-lifecycle-instance-profile" + role = "${aws_iam_role.lifecycle.name}" +} + # Execution role and policies for the lifecycle hook resource "aws_iam_role" "lifecycle" { name = "${var.name_prefix}-lifecycle-role" From 1401fd9a96a72e766180d80205b1a7f140f88e0a Mon Sep 17 00:00:00 2001 From: Lachlan Donald Date: Tue, 11 Sep 2018 14:52:37 +1000 Subject: [PATCH 2/4] Tags must be a list --- terraform/modules/example/main.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/terraform/modules/example/main.tf b/terraform/modules/example/main.tf index 8b815eb..f7645cf 100644 --- a/terraform/modules/example/main.tf +++ b/terraform/modules/example/main.tf @@ -59,7 +59,7 @@ resource "aws_autoscaling_group" "main" { min_size = "0" desired_capacity = "${var.instance_count}" max_size = "1" - tags = "${var.tags}" + tags = ["${var.tags}"] lifecycle { create_before_destroy = true From 10563c65a44935901727e93f413e4000eaa95e59 Mon Sep 17 00:00:00 2001 From: Lachlan Donald Date: Thu, 4 Oct 2018 15:36:04 +1000 Subject: [PATCH 3/4] Changes from PR for terraform example --- terraform/example.tf | 6 +++- terraform/modules/example/cloud-config.yml | 25 +--------------- terraform/modules/example/main.tf | 34 +++++++++++++++------- 3 files changed, 29 insertions(+), 36 deletions(-) diff --git a/terraform/example.tf b/terraform/example.tf index e499030..eb5d092 100644 --- a/terraform/example.tf +++ b/terraform/example.tf @@ -2,6 +2,10 @@ terraform { required_version = "0.11.8" } +provider "aws" { + version = "1.34.0" +} + # Use the default VPC and subnets data "aws_vpc" "main" { default = true @@ -39,7 +43,7 @@ data "aws_ami" "linux2" { variable "instance_key" { description = "Name of EC2 Keypair" - default = "lifecycled-example" + default = "lifecycled-example" } module "example" { diff --git a/terraform/modules/example/cloud-config.yml b/terraform/modules/example/cloud-config.yml index 3064cf2..67fd326 100644 --- a/terraform/modules/example/cloud-config.yml +++ b/terraform/modules/example/cloud-config.yml @@ -1,7 +1,4 @@ #cloud-config -package_update: true -packages: - - aws-cfn-bootstrap write_files: - path: "/etc/systemd/system/lifecycled.service" permissions: "0644" @@ -23,23 +20,6 @@ write_files: [Install] WantedBy=multi-user.target - - path: "/usr/local/scripts/cloudformation-signal.sh" - permissions: "0744" - owner: "root" - content: | - #! /usr/bin/bash - - set -euo pipefail - - function await_unit() { - echo -n "Waiting for $1..." - while ! systemctl is-active $1 > /dev/null; do - sleep 1 - done - echo "Done!" - } - - await_unit lifecycled.service - path: "/usr/local/scripts/lifecycle-handler.sh" permissions: "0744" owner: "root" @@ -52,13 +32,10 @@ write_files: sleep 120 echo "goodbye from the handler" runcmd: - - | + - | aws s3 cp s3://${artifact_bucket}/${artifact_key} /usr/local/bin/lifecycled chmod +x /usr/local/bin/lifecycled chown root:root /usr/local/bin/lifecycled echo "lifecycled ${artifact_etag} installed" - | systemctl enable lifecycled.service --now - - | - /usr/local/scripts/cloudformation-signal.sh - /opt/aws/bin/cfn-signal -e $? --stack ${stack_name} --resource AutoScalingGroup --region ${region} diff --git a/terraform/modules/example/main.tf b/terraform/modules/example/main.tf index f7645cf..b26d56b 100644 --- a/terraform/modules/example/main.tf +++ b/terraform/modules/example/main.tf @@ -37,12 +37,12 @@ data "template_file" "main" { } resource "aws_launch_configuration" "main" { - name_prefix = "${var.name_prefix}" - image_id = "${var.instance_ami}" - instance_type = "${var.instance_type}" - key_name = "${var.instance_key}" - iam_instance_profile = "${aws_iam_instance_profile.lifecycle.name}" - security_groups = ["${aws_security_group.main.id}"] + name_prefix = "${var.name_prefix}" + image_id = "${var.instance_ami}" + instance_type = "${var.instance_type}" + key_name = "${var.instance_key}" + iam_instance_profile = "${aws_iam_instance_profile.lifecycle.name}" + security_groups = ["${aws_security_group.main.id}"] user_data = "${data.template_file.main.rendered}" @@ -59,7 +59,6 @@ resource "aws_autoscaling_group" "main" { min_size = "0" desired_capacity = "${var.instance_count}" max_size = "1" - tags = ["${var.tags}"] lifecycle { create_before_destroy = true @@ -70,6 +69,13 @@ resource "aws_security_group" "main" { name = "${var.name_prefix}-sg" description = "Allow access to lifecycled instances" vpc_id = "${var.vpc_id}" + + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + } } # Allow SSH ingress if a EC2 key pair is specified. @@ -187,23 +193,29 @@ resource "aws_iam_instance_profile" "lifecycle" { # Execution role and policies for the lifecycle hook resource "aws_iam_role" "lifecycle" { name = "${var.name_prefix}-lifecycle-role" - assume_role_policy = "${data.aws_iam_policy_document.asg_assume.json}" + assume_role_policy = "${data.aws_iam_policy_document.assume.json}" +} + +resource "aws_iam_role_policy" "lifecycle-asg" { + name = "${var.name_prefix}-lifecycle-asg-permissions" + role = "${aws_iam_role.lifecycle.id}" + policy = "${data.aws_iam_policy_document.asg_permissions.json}" } resource "aws_iam_role_policy" "lifecycle" { name = "${var.name_prefix}-lifecycle-permissions" role = "${aws_iam_role.lifecycle.id}" - policy = "${data.aws_iam_policy_document.asg_permissions.json}" + policy = "${data.aws_iam_policy_document.permissions.json}" } -data "aws_iam_policy_document" "asg_assume" { +data "aws_iam_policy_document" "assume" { statement { effect = "Allow" actions = ["sts:AssumeRole"] principals { type = "Service" - identifiers = ["autoscaling.amazonaws.com"] + identifiers = ["ec2.amazonaws.com", "autoscaling.amazonaws.com"] } } } From 0632869de1b21951bd9eda70e3f4c2568dfae8d2 Mon Sep 17 00:00:00 2001 From: Lachlan Donald Date: Fri, 5 Oct 2018 16:00:24 +1000 Subject: [PATCH 4/4] Split roles for lifecycle hook and ec2 instance --- terraform/modules/example/main.tf | 71 +++++++++++++++++++------------ 1 file changed, 43 insertions(+), 28 deletions(-) diff --git a/terraform/modules/example/main.tf b/terraform/modules/example/main.tf index b26d56b..8b23789 100644 --- a/terraform/modules/example/main.tf +++ b/terraform/modules/example/main.tf @@ -41,7 +41,7 @@ resource "aws_launch_configuration" "main" { image_id = "${var.instance_ami}" instance_type = "${var.instance_type}" key_name = "${var.instance_key}" - iam_instance_profile = "${aws_iam_instance_profile.lifecycle.name}" + iam_instance_profile = "${aws_iam_instance_profile.ec2.name}" security_groups = ["${aws_security_group.main.id}"] user_data = "${data.template_file.main.rendered}" @@ -63,6 +63,15 @@ resource "aws_autoscaling_group" "main" { lifecycle { create_before_destroy = true } + + initial_lifecycle_hook { + name = "${var.name_prefix}-lifecycle" + default_result = "CONTINUE" + heartbeat_timeout = 60 + lifecycle_transition = "autoscaling:EC2_INSTANCE_TERMINATING" + notification_target_arn = "${aws_sns_topic.main.arn}" + role_arn = "${aws_iam_role.lifecycle_hook.arn}" + } } resource "aws_security_group" "main" { @@ -169,53 +178,59 @@ data "aws_iam_policy_document" "permissions" { } } -# SNS topic for the lifecycle hook -resource "aws_sns_topic" "main" { - name = "${var.name_prefix}-lifecycle" +resource "aws_iam_instance_profile" "ec2" { + name = "${var.name_prefix}-ec2-instance-profile" + role = "${aws_iam_role.ec2.name}" +} + +resource "aws_iam_role" "ec2" { + name = "${var.name_prefix}-ec2-role" + assume_role_policy = "${data.aws_iam_policy_document.ec2_assume.json}" +} + +resource "aws_iam_role_policy" "ec2" { + name = "${var.name_prefix}-ec2-permissions" + role = "${aws_iam_role.ec2.id}" + policy = "${data.aws_iam_policy_document.permissions.json}" } -# Lifecycle hook -resource "aws_autoscaling_lifecycle_hook" "main" { - name = "${var.name_prefix}-lifecycle" - autoscaling_group_name = "${aws_autoscaling_group.main.id}" - lifecycle_transition = "autoscaling:EC2_INSTANCE_TERMINATING" - default_result = "CONTINUE" - heartbeat_timeout = "60" - notification_target_arn = "${aws_sns_topic.main.arn}" - role_arn = "${aws_iam_role.lifecycle.arn}" +data "aws_iam_policy_document" "ec2_assume" { + statement { + effect = "Allow" + actions = ["sts:AssumeRole"] + + principals { + type = "Service" + identifiers = ["ec2.amazonaws.com"] + } + } } -resource "aws_iam_instance_profile" "lifecycle" { - name = "${var.name_prefix}-lifecycle-instance-profile" - role = "${aws_iam_role.lifecycle.name}" +# SNS topic for the lifecycle hook +resource "aws_sns_topic" "main" { + name = "${var.name_prefix}-lifecycle" } # Execution role and policies for the lifecycle hook -resource "aws_iam_role" "lifecycle" { +resource "aws_iam_role" "lifecycle_hook" { name = "${var.name_prefix}-lifecycle-role" - assume_role_policy = "${data.aws_iam_policy_document.assume.json}" + assume_role_policy = "${data.aws_iam_policy_document.asg_assume.json}" } -resource "aws_iam_role_policy" "lifecycle-asg" { +resource "aws_iam_role_policy" "lifecycle_hook" { name = "${var.name_prefix}-lifecycle-asg-permissions" - role = "${aws_iam_role.lifecycle.id}" + role = "${aws_iam_role.lifecycle_hook.id}" policy = "${data.aws_iam_policy_document.asg_permissions.json}" } -resource "aws_iam_role_policy" "lifecycle" { - name = "${var.name_prefix}-lifecycle-permissions" - role = "${aws_iam_role.lifecycle.id}" - policy = "${data.aws_iam_policy_document.permissions.json}" -} - -data "aws_iam_policy_document" "assume" { +data "aws_iam_policy_document" "asg_assume" { statement { effect = "Allow" actions = ["sts:AssumeRole"] principals { type = "Service" - identifiers = ["ec2.amazonaws.com", "autoscaling.amazonaws.com"] + identifiers = ["autoscaling.amazonaws.com"] } } }