Skip to content
This repository was archived by the owner on Jul 3, 2023. It is now read-only.

Added ASG template, explicit types in module arguments #81

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
2 changes: 2 additions & 0 deletions asg/files/instance-config.yml.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#instance-config
${custom_script}
292 changes: 292 additions & 0 deletions asg/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,292 @@
/**
*/

variable "name" {
description = "The cluster name, e.g cdn"
type = "string"
}

variable "environment" {
description = "Environment tag, e.g prod"
type = "string"
}

variable "vpc_id" {
description = "VPC ID"
type = "string"
}

variable "image_id" {
description = "AMI Image ID"
type = "string"
}

variable "subnet_ids" {
description = "list of subnet IDs"
type = "list"
}

variable "key_name" {
description = "SSH key name to use"
type = "string"
}

variable "ingress_cidr" {
description = "Comma separated list of ingress cidrs"
type = "string"
}

variable "iam_instance_profile" {
description = "Instance profile ARN to use in the launch configuration"
type = "string"
}

variable "region" {
description = "AWS Region"
type = "string"
}

variable "availability_zones" {
description = "list of AZs"
type = "list"
}

variable "instance_type" {
description = "The instance type to use, e.g t2.small"
type = "string"
}

variable "instance_ebs_optimized" {
description = "When set to true the instance will be launched with EBS optimized turned on"
default = true
}

variable "min_size" {
description = "Minimum instance count"
default = 3
}

variable "max_size" {
description = "Maxmimum instance count"
default = 100
}

variable "desired_capacity" {
description = "Desired instance count"
default = 3
}

variable "associate_public_ip_address" {
description = "Should created instances be publicly accessible (if the SG allows)"
default = false
}

variable "custom_script" {
description = "Custom instance bootupt script"
default = ""
type = "string"
}

variable "load_balancers" {
description = "ASG ELBs"
default = []
}

variable "health_check_grace_period" {
description = "Time (in seconds) after instance comes into service before checking health"
default = 300
}

variable "target_group_arns" {
description = "Application load balancer target group ARN(s) if any"
default = []
}

variable "termination_policies" {
description = "OldestInstance, NewestInstance, OldestLaunchConfiguration, ClosestToNextInstanceHour, Default"
default = ["OldestLaunchConfiguration", "Default"]
}

variable "wait_for_capacity_timeout" {
description = "A maximum duration that Terraform should wait for ASG instances to be healthy before timing out"
default = "10m"
}

resource "aws_security_group" "asg" {
name = "${var.name}-asg"
vpc_id = "${var.vpc_id}"
description = "Allows traffic from and to the EC2 instances of the ${var.name} ASG"

ingress {
from_port = 0
to_port = 0
protocol = -1
cidr_blocks = ["${split(",", var.ingress_cidr)}"]
}

egress {
from_port = 0
to_port = 0
protocol = -1
cidr_blocks = ["0.0.0.0/0"]
}

tags {
Name = "ASG (${var.name})"
Environment = "${var.environment}"
}

lifecycle {
create_before_destroy = true
}
}

data "template_file" "instance_config" {
template = "${file("${path.module}/files/instance-config.yml.tpl")}"

vars {
custom_script = "${var.custom_script}"
}
}

resource "aws_launch_configuration" "main" {
name_prefix = "${format("%s-", var.name)}"

image_id = "${var.image_id}"
instance_type = "${var.instance_type}"
ebs_optimized = "${var.instance_ebs_optimized}"
iam_instance_profile = "${var.iam_instance_profile}"
key_name = "${var.key_name}"
security_groups = ["${aws_security_group.asg.id}"]
user_data = "${data.template_file.instance_config.rendered}"
associate_public_ip_address = "${var.associate_public_ip_address}"

lifecycle {
create_before_destroy = true
}
}

resource "aws_autoscaling_group" "main" {
name = "${var.name}"

availability_zones = ["${var.availability_zones}"]
vpc_zone_identifier = ["${var.subnet_ids}"]
launch_configuration = "${aws_launch_configuration.main.id}"
min_size = "${var.min_size}"
max_size = "${var.max_size}"
desired_capacity = "${var.desired_capacity}"
health_check_grace_period = "${var.health_check_grace_period}"
health_check_type = "ELB"
load_balancers = ["${var.load_balancers}"]
target_group_arns = ["${var.target_group_arns}"]
termination_policies = "${var.termination_policies}"
wait_for_capacity_timeout = "${var.wait_for_capacity_timeout}"

tag {
key = "Name"
value = "${var.name}"
propagate_at_launch = true
}

tag {
key = "Cluster"
value = "${var.name}"
propagate_at_launch = true
}

tag {
key = "Environment"
value = "${var.environment}"
propagate_at_launch = true
}

lifecycle {
create_before_destroy = true
}
}

resource "aws_autoscaling_policy" "scale_up" {
name = "${var.name}-scaleup"
scaling_adjustment = 1
adjustment_type = "ChangeInCapacity"
cooldown = 300
autoscaling_group_name = "${aws_autoscaling_group.main.name}"

lifecycle {
create_before_destroy = true
}
}

resource "aws_autoscaling_policy" "scale_down" {
name = "${var.name}-scaledown"
scaling_adjustment = -1
adjustment_type = "ChangeInCapacity"
cooldown = 300
autoscaling_group_name = "${aws_autoscaling_group.main.name}"

lifecycle {
create_before_destroy = true
}
}

resource "aws_cloudwatch_metric_alarm" "cpu_high" {
alarm_name = "${var.name}-cpureservation-high"
comparison_operator = "GreaterThanOrEqualToThreshold"
evaluation_periods = "2"
metric_name = "CPUUtilization"
namespace = "AWS/EC2"
period = "300"
statistic = "Maximum"
threshold = "60"

dimensions {
AutoScalingGroupName = "${aws_autoscaling_group.main.name}"
}

alarm_description = "Scale up if the cpu reservation is above 60% for 10 minutes"
alarm_actions = ["${aws_autoscaling_policy.scale_up.arn}"]

lifecycle {
create_before_destroy = true
}

# This is required to make cloudwatch alarms creation sequential, AWS doesn't
# support modifying alarms concurrently.
depends_on = ["aws_autoscaling_group.main"]
}

resource "aws_cloudwatch_metric_alarm" "cpu_low" {
alarm_name = "${var.name}-cpureservation-low"
comparison_operator = "LessThanOrEqualToThreshold"
evaluation_periods = "2"
metric_name = "CPUUtilization"
namespace = "AWS/EC2"
period = "300"
statistic = "Maximum"
threshold = "10"

dimensions {
AutoScalingGroupName = "${aws_autoscaling_group.main.name}"
}

alarm_description = "Scale down if the cpu reservation is below 10% for 10 minutes"
alarm_actions = ["${aws_autoscaling_policy.scale_down.arn}"]

lifecycle {
create_before_destroy = true
}

# This is required to make cloudwatch alarms creation sequential, AWS doesn't
# support modifying alarms concurrently.
depends_on = ["aws_cloudwatch_metric_alarm.cpu_high"]
}

// The asg name, e.g cdn
output "name" {
value = "${var.name}"
}

// The asg security group ID.
output "security_group_id" {
value = "${aws_security_group.asg.id}"
}
7 changes: 5 additions & 2 deletions bastion/main.tf
Original file line number Diff line number Diff line change
@@ -24,14 +24,17 @@
variable "instance_type" {
default = "t2.micro"
description = "Instance type, see a list at: https://aws.amazon.com/ec2/instance-types/"
type = "string"
}

variable "region" {
description = "AWS Region, e.g us-west-2"
type = "string"
}

variable "security_groups" {
description = "a comma separated lists of security group IDs"
description = "List of security group IDs"
type = "list"
}

variable "vpc_id" {
@@ -63,7 +66,7 @@ resource "aws_instance" "bastion" {
instance_type = "${var.instance_type}"
subnet_id = "${var.subnet_id}"
key_name = "${var.key_name}"
vpc_security_group_ids = ["${split(",",var.security_groups)}"]
vpc_security_group_ids = ["${var.security_groups}"]
monitoring = true
user_data = "${file(format("%s/user_data.sh", path.module))}"

2 changes: 1 addition & 1 deletion dns/main.tf
Original file line number Diff line number Diff line change
@@ -40,5 +40,5 @@ output "zone_id" {

// A comma separated list of the zone name servers.
output "name_servers" {
value = "${join(",",aws_route53_zone.main.name_servers)}"
value = ["${aws_route53_zone.main.name_servers}"]
}
5 changes: 3 additions & 2 deletions ecs-cluster/main.tf
Original file line number Diff line number Diff line change
@@ -51,7 +51,8 @@ variable "key_name" {
}

variable "security_groups" {
description = "Comma separated list of security groups"
description = "List of security groups"
type = "list"
}

variable "iam_instance_profile" {
@@ -135,7 +136,7 @@ resource "aws_security_group" "cluster" {
from_port = 0
to_port = 0
protocol = -1
security_groups = ["${split(",", var.security_groups)}"]
security_groups = ["${var.security_groups}"]
}

egress {
62 changes: 52 additions & 10 deletions elb/main.tf
Original file line number Diff line number Diff line change
@@ -6,42 +6,78 @@

variable "name" {
description = "ELB name, e.g cdn"
type = "string"
}

variable "subnet_ids" {
description = "Comma separated list of subnet IDs"
description = "List of subnet IDs"
type = "list"
}

variable "environment" {
description = "Environment tag, e.g prod"
type = "string"
}

variable "port" {
description = "Instance port"
type = "string"
}

variable "security_groups" {
description = "Comma separated list of security group IDs"
description = "List of security group IDs"
type = "list"
}

variable "dns_name" {
description = "Route53 record name"
type = "string"
}

variable "healthcheck" {
description = "Healthcheck path"
type = "string"
}

variable "healthcheck_healthy_threshold" {
description = "Number of consecutive health check successes before declaring an EC2 instance healthy."
default = 2
}

variable "healthcheck_unhealthy_threshold" {
description = "Number of consecutive health check failures before declaring an EC2 instance unhealthy."
default = 2
}

variable "healthcheck_timeout" {
description = "Time to wait when receiving a response from the health check (2 sec 60 sec)."
default = 5
}

variable "healthcheck_interval" {
description = "Amount of time between health checks (5 sec 300 sec)"
default = 30
}

variable "protocol" {
description = "Protocol to use, HTTP or TCP"
type = "string"
}

variable "zone_id" {
description = "Route53 zone ID to use for dns_name"
type = "string"
}

variable "log_bucket" {
description = "S3 bucket name to write ELB logs into"
type = "string"
}

# https://docs.aws.amazon.com/elasticloadbalancing/latest/classic/config-idle-timeout.html?icmpid=docs_elb_console
variable "idle_timeout" {
description = "ELB idle connection timeout"
default = 30
}

/**
@@ -53,26 +89,26 @@ resource "aws_elb" "main" {

internal = true
cross_zone_load_balancing = true
subnets = ["${split(",", var.subnet_ids)}"]
security_groups = ["${split(",",var.security_groups)}"]
subnets = ["${var.subnet_ids}"]
security_groups = ["${var.security_groups}"]

idle_timeout = 30
idle_timeout = "${var.idle_timeout}"
connection_draining = true
connection_draining_timeout = 15

listener {
lb_port = 80
lb_port = "${var.port}"
lb_protocol = "${var.protocol}"
instance_port = "${var.port}"
instance_protocol = "${var.protocol}"
}

health_check {
healthy_threshold = 2
unhealthy_threshold = 2
timeout = 5
healthy_threshold = "${var.healthcheck_healthy_threshold}"
unhealthy_threshold = "${var.healthcheck_unhealthy_threshold}"
timeout = "${var.healthcheck_timeout}"
target = "${var.protocol}:${var.port}${var.healthcheck}"
interval = 30
interval = "${var.healthcheck_interval}"
}

access_logs {
@@ -102,6 +138,11 @@ resource "aws_route53_record" "main" {
* Outputs.
*/

// Instance port
output "port" {
value = "${var.port}"
}

// The ELB name.
output "name" {
value = "${aws_elb.main.name}"
@@ -126,3 +167,4 @@ output "fqdn" {
output "zone_id" {
value = "${aws_elb.main.zone_id}"
}

72 changes: 42 additions & 30 deletions iam-role/main.tf
Original file line number Diff line number Diff line change
@@ -6,30 +6,46 @@ variable "environment" {
description = "The name of the environment for this stack"
}

resource "aws_iam_role" "default_ecs_role" {
name = "ecs-role-${var.name}-${var.environment}"
variable "ecs_role_services" {
description = ""
default = "\"ec2.amazonaws.com\""
}

variable "aws_iam_role_policy_allow" {
description = ""
default = "\"autoscaling:*\",\"cloudwatch:*\""
}

assume_role_policy = <<EOF
data "template_file" "aws_iam_role" {
template = <<EOF
{
"Version": "2008-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Principal": {
"Service": [
"ecs.amazonaws.com",
"ec2.amazonaws.com"
$${ecs_role_services}
]
},
"Effect": "Allow"
}
]
}
EOF

vars {
ecs_role_services = "${var.ecs_role_services}"
}
}

resource "aws_iam_role" "default_ecs_role" {
name = "ecsrole-${var.name}-${var.environment}"
assume_role_policy = "${data.template_file.aws_iam_role.rendered}"
}

resource "aws_iam_role_policy" "default_ecs_service_role_policy" {
name = "ecs-service-role-policy-${var.name}-${var.environment}"
name = "ecs-servicerole-policy-${var.name}-${var.environment}"
role = "${aws_iam_role.default_ecs_role.id}"

policy = <<EOF
@@ -41,9 +57,11 @@ resource "aws_iam_role_policy" "default_ecs_service_role_policy" {
"Action": [
"ec2:AuthorizeSecurityGroupIngress",
"ec2:Describe*",
"s3:*",
"elasticloadbalancing:DeregisterInstancesFromLoadBalancer",
"elasticloadbalancing:Describe*",
"elasticloadbalancing:RegisterInstancesWithLoadBalancer"
"elasticloadbalancing:RegisterInstancesWithLoadBalancer",
"cloudwatch:*"
],
"Resource": "*"
}
@@ -52,30 +70,15 @@ resource "aws_iam_role_policy" "default_ecs_service_role_policy" {
EOF
}

resource "aws_iam_role_policy" "default_ecs_instance_role_policy" {
name = "ecs-instance-role-policy-${var.name}-${var.environment}"
role = "${aws_iam_role.default_ecs_role.id}"

policy = <<EOF
data "template_file" "aws_iam_role_policy" {
template = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ecs:CreateCluster",
"ecs:DeregisterContainerInstance",
"ecs:DiscoverPollEndpoint",
"ecs:Poll",
"ecs:RegisterContainerInstance",
"ecs:StartTelemetrySession",
"ecs:Submit*",
"ecr:GetAuthorizationToken",
"ecr:BatchCheckLayerAvailability",
"ecr:GetDownloadUrlForLayer",
"ecr:BatchGetImage",
"ecs:StartTask",
"autoscaling:*"
$${allow_actions}
],
"Resource": "*"
},
@@ -85,13 +88,25 @@ resource "aws_iam_role_policy" "default_ecs_instance_role_policy" {
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents",
"logs:DescribeLogStreams"
"logs:DescribeLogStreams",
"cloudwatch:*"
],
"Resource": "arn:aws:logs:*:*:*"
}
]
}
EOF

vars {
allow_actions = "${var.aws_iam_role_policy_allow}"
}
}

resource "aws_iam_role_policy" "default_ecs_instance_role_policy" {
name = "ecs-instancerole-policy-${var.name}-${var.environment}"
role = "${aws_iam_role.default_ecs_role.id}"

policy = "${data.template_file.aws_iam_role_policy.rendered}"
}

resource "aws_iam_instance_profile" "default_ecs" {
@@ -100,14 +115,11 @@ resource "aws_iam_instance_profile" "default_ecs" {
roles = ["${aws_iam_role.default_ecs_role.name}"]
}

output "default_ecs_role_id" {
value = "${aws_iam_role.default_ecs_role.id}"
}

output "arn" {
value = "${aws_iam_role.default_ecs_role.arn}"
}

output "profile" {
value = "${aws_iam_instance_profile.default_ecs.id}"
}

15 changes: 0 additions & 15 deletions main.tf
Original file line number Diff line number Diff line change
@@ -265,11 +265,6 @@ output "iam_role" {
value = "${module.iam_role.arn}"
}

// Default ECS role ID. Useful if you want to add a new policy to that role.
output "iam_role_default_ecs_role_id" {
value = "${module.iam_role.default_ecs_role_id}"
}

// S3 bucket ID for ELB logs.
output "log_bucket_id" {
value = "${module.s3_logs.id}"
@@ -309,13 +304,3 @@ output "vpc_id" {
output "ecs_cluster_security_group_id" {
value = "${module.ecs_cluster.security_group_id}"
}

// Comma separated list of internal route table IDs.
output "internal_route_tables" {
value = "${module.vpc.internal_rtb_id}"
}

// The external route table ID.
output "external_route_tables" {
value = "${module.vpc.external_rtb_id}"
}
12 changes: 10 additions & 2 deletions service/main.tf
Original file line number Diff line number Diff line change
@@ -36,11 +36,13 @@ variable "version" {
}

variable "subnet_ids" {
description = "Comma separated list of subnet IDs that will be passed to the ELB module"
description = "List of subnet IDs that will be passed to the ELB module"
type = "list"
}

variable "security_groups" {
description = "Comma separated list of security group IDs that will be passed to the ELB module"
description = "List of security group IDs that will be passed to the ELB module"
type = "list"
}

variable "port" {
@@ -98,6 +100,11 @@ variable "cpu" {
default = 512
}

variable "mount_points" {
description = "The raw json on the mount points"
default = "[]"
}

variable "protocol" {
description = "The ELB protocol, HTTP or TCP"
default = "HTTP"
@@ -155,6 +162,7 @@ module "task" {
env_vars = "${var.env_vars}"
memory = "${var.memory}"
cpu = "${var.cpu}"
mount_points = "${mount_points}"

ports = <<EOF
[
7 changes: 6 additions & 1 deletion task/main.tf
Original file line number Diff line number Diff line change
@@ -62,6 +62,11 @@ variable "memory" {
default = 512
}

variable "mount_points" {
description = "The raw json on the mount points"
default = "[]"
}

/**
* Resources.
*/
@@ -88,7 +93,7 @@ resource "aws_ecs_task_definition" "main" {
"name": "${var.name}",
"portMappings": ${var.ports},
"entryPoint": ${var.entry_point},
"mountPoints": [],
"mountPoints": ${var.mount_points},
"logConfiguration": {
"logDriver": "journald",
"options": {
69 changes: 25 additions & 44 deletions vpc/main.tf
Original file line number Diff line number Diff line change
@@ -1,29 +1,32 @@
variable "cidr" {
description = "The CIDR block for the VPC."
type = "string"
}

variable "external_subnets" {
description = "List of external subnets"
type = "list"
description = "List of subnets"
type = "list"
}

variable "internal_subnets" {
description = "List of internal subnets"
type = "list"
}

variable "environment" {
description = "Environment tag, e.g prod"
description = "List of subnets"
type = "list"
}

variable "availability_zones" {
description = "List of availability zones"
type = "list"
type = "list"
}

variable "environment" {
description = "Environment tag, e.g prod"
type = "string"
}

variable "name" {
description = "Name tag, e.g stack"
default = "stack"
type = "string"
}

/**
@@ -55,14 +58,14 @@ resource "aws_internet_gateway" "main" {
}

resource "aws_nat_gateway" "main" {
count = "${length(var.internal_subnets)}"
count = "${length(compact(var.internal_subnets))}"
allocation_id = "${element(aws_eip.nat.*.id, count.index)}"
subnet_id = "${element(aws_subnet.external.*.id, count.index)}"
depends_on = ["aws_internet_gateway.main"]
}

resource "aws_eip" "nat" {
count = "${length(var.internal_subnets)}"
count = "${length(compact(var.internal_subnets))}"
vpc = true
}

@@ -74,7 +77,7 @@ resource "aws_subnet" "internal" {
vpc_id = "${aws_vpc.main.id}"
cidr_block = "${element(var.internal_subnets, count.index)}"
availability_zone = "${element(var.availability_zones, count.index)}"
count = "${length(var.internal_subnets)}"
count = "${length(compact(var.internal_subnets))}"

tags {
Name = "${var.name}-${format("internal-%03d", count.index+1)}"
@@ -85,7 +88,7 @@ resource "aws_subnet" "external" {
vpc_id = "${aws_vpc.main.id}"
cidr_block = "${element(var.external_subnets, count.index)}"
availability_zone = "${element(var.availability_zones, count.index)}"
count = "${length(var.external_subnets)}"
count = "${length(compact(var.external_subnets))}"
map_public_ip_on_launch = true

tags {
@@ -100,45 +103,37 @@ resource "aws_subnet" "external" {
resource "aws_route_table" "external" {
vpc_id = "${aws_vpc.main.id}"

route {
cidr_block = "0.0.0.0/0"
gateway_id = "${aws_internet_gateway.main.id}"
}

tags {
Name = "${var.name}-external-001"
}
}

resource "aws_route" "external" {
route_table_id = "${aws_route_table.external.id}"
destination_cidr_block = "0.0.0.0/0"
gateway_id = "${aws_internet_gateway.main.id}"
}

resource "aws_route_table" "internal" {
count = "${length(var.internal_subnets)}"
count = "${length(compact(var.internal_subnets))}"
vpc_id = "${aws_vpc.main.id}"

tags {
Name = "${var.name}-${format("internal-%03d", count.index+1)}"
}
}

resource "aws_route" "internal" {
count = "${length(compact(var.internal_subnets))}"
route_table_id = "${element(aws_route_table.internal.*.id, count.index)}"
destination_cidr_block = "0.0.0.0/0"
nat_gateway_id = "${element(aws_nat_gateway.main.*.id, count.index)}"
}

/**
* Route associations
*/

resource "aws_route_table_association" "internal" {
count = "${length(var.internal_subnets)}"
count = "${length(compact(var.internal_subnets))}"
subnet_id = "${element(aws_subnet.internal.*.id, count.index)}"
route_table_id = "${element(aws_route_table.internal.*.id, count.index)}"
}

resource "aws_route_table_association" "external" {
count = "${length(var.external_subnets)}"
count = "${length(compact(var.external_subnets))}"
subnet_id = "${element(aws_subnet.external.*.id, count.index)}"
route_table_id = "${aws_route_table.external.id}"
}
@@ -157,7 +152,7 @@ output "external_subnets" {
value = ["${aws_subnet.external.*.id}"]
}

// A list of subnet IDs.
// A comma-separated list of subnet IDs.
output "internal_subnets" {
value = ["${aws_subnet.internal.*.id}"]
}
@@ -172,17 +167,3 @@ output "availability_zones" {
value = ["${aws_subnet.external.*.availability_zone}"]
}

// The internal route table ID.
output "internal_rtb_id" {
value = "${join(",", aws_route_table.internal.*.id)}"
}

// The external route table ID.
output "external_rtb_id" {
value = "${aws_route_table.external.id}"
}

// The list of EIPs associated with the internal subnets.
output "internal_nat_ips" {
value = ["${aws_eip.nat.*.public_ip}"]
}
6 changes: 4 additions & 2 deletions web-service/main.tf
Original file line number Diff line number Diff line change
@@ -36,11 +36,13 @@ variable "version" {
}

variable "subnet_ids" {
description = "Comma separated list of subnet IDs that will be passed to the ELB module"
description = "List of subnet IDs that will be passed to the ELB module"
type = "list"
}

variable "security_groups" {
description = "Comma separated list of security group IDs that will be passed to the ELB module"
description = "List of security group IDs that will be passed to the ELB module"
type = "list"
}

variable "port" {