initial commit of replacement infrastructure automation
authorJustin Wind <j.wind@partner.samsung.com>
Mon, 11 Sep 2017 22:30:37 +0000 (15:30 -0700)
committerJustin Wind <j.wind@partner.samsung.com>
Mon, 11 Sep 2017 22:30:37 +0000 (15:30 -0700)
47 files changed:
infrastructure/BOOTSTRAP.md [new file with mode: 0644]
infrastructure/generate-backend-configs.sh [new file with mode: 0755]
infrastructure/management-stack/data_vpc.tf [new file with mode: 0644]
infrastructure/management-stack/main.tf [new file with mode: 0644]
infrastructure/management-stack/outputs.tf [new file with mode: 0644]
infrastructure/management-stack/terraform.tfvars [new symlink]
infrastructure/management-stack/variables.tf [new file with mode: 0644]
infrastructure/modules/management-stack/README.md [new file with mode: 0644]
infrastructure/modules/management-stack/iam.tf [new file with mode: 0644]
infrastructure/modules/management-stack/management.tf [new file with mode: 0644]
infrastructure/modules/management-stack/outputs.tf [new file with mode: 0644]
infrastructure/modules/management-stack/queues.tf [new file with mode: 0644]
infrastructure/modules/management-stack/user-data.tpl [new file with mode: 0644]
infrastructure/modules/management-stack/variables.tf [new file with mode: 0644]
infrastructure/modules/management-stack/version.tf [new file with mode: 0644]
infrastructure/modules/terraform-infrastructure/main.tf [new file with mode: 0644]
infrastructure/modules/terraform-infrastructure/outputs.tf [new file with mode: 0644]
infrastructure/modules/terraform-infrastructure/variables.tf [new file with mode: 0644]
infrastructure/modules/tf_aws_asg_stack/README.md [new file with mode: 0644]
infrastructure/modules/tf_aws_asg_stack/iam.tf [new file with mode: 0644]
infrastructure/modules/tf_aws_asg_stack/main.tf [new file with mode: 0644]
infrastructure/modules/tf_aws_asg_stack/outputs.tf [new file with mode: 0644]
infrastructure/modules/tf_aws_asg_stack/user-data.tpl [new file with mode: 0644]
infrastructure/modules/tf_aws_asg_stack/variables.tf [new file with mode: 0644]
infrastructure/modules/tf_aws_asg_stack/version.tf [new file with mode: 0644]
infrastructure/modules/tf_aws_vpc/README.md [new file with mode: 0644]
infrastructure/modules/tf_aws_vpc/main.tf [new file with mode: 0644]
infrastructure/modules/tf_aws_vpc/outputs.tf [new file with mode: 0644]
infrastructure/modules/tf_aws_vpc/variables.tf [new file with mode: 0644]
infrastructure/modules/tf_aws_vpc/version.tf [new file with mode: 0644]
infrastructure/modules/vpcaccess-stack/main.tf [new file with mode: 0644]
infrastructure/modules/vpcaccess-stack/outputs.tf [new file with mode: 0644]
infrastructure/modules/vpcaccess-stack/variables.tf [new file with mode: 0644]
infrastructure/terraform-infrastructure/main.tf [new file with mode: 0644]
infrastructure/terraform-infrastructure/outputs.tf [new file with mode: 0644]
infrastructure/terraform-infrastructure/terraform.tfvars [new symlink]
infrastructure/terraform-infrastructure/variables.tf [new file with mode: 0644]
infrastructure/terraform.tfvars [new file with mode: 0644]
infrastructure/vpc/main.tf [new file with mode: 0644]
infrastructure/vpc/outputs.tf [new file with mode: 0644]
infrastructure/vpc/terraform.tfvars [new symlink]
infrastructure/vpc/variables.tf [new file with mode: 0644]
infrastructure/vpcaccess-stack/data_management-stack.tf [new file with mode: 0644]
infrastructure/vpcaccess-stack/data_vpc.tf [new file with mode: 0644]
infrastructure/vpcaccess-stack/main.tf [new file with mode: 0644]
infrastructure/vpcaccess-stack/outputs.tf [new file with mode: 0644]
infrastructure/vpcaccess-stack/variables.tf [new file with mode: 0644]

diff --git a/infrastructure/BOOTSTRAP.md b/infrastructure/BOOTSTRAP.md
new file mode 100644 (file)
index 0000000..b9bae27
--- /dev/null
@@ -0,0 +1,44 @@
+# AWSible Infrastructure via Terraform
+
+Ensure the correct profile will be used:
+
+       export AWS_PROFILE=profile
+
+Initialize the shared infrastructure needed by terraform:
+
+       pushd terraform-infrastructure
+       terraform init
+       terraform apply
+       ../generate-backend-configs.sh > backend.tf
+       echo yes | terraform init
+       popd
+
+Create the VPC:
+
+       pushd vpc
+       ../generate-backend-configs.sh > backend.tf
+       terraform init
+       terraform apply
+       popd
+
+Create the management stack:
+
+       pushd management-stack
+       ../generate-backend-configs.sh > backend.tf
+       terraform init
+       terraform apply
+       popd
+
+Create the vpcaccess stack:
+
+       pushd vpcaccess-stack
+       ../generate-backend-configs.sh > backend.tf
+       terraform init
+       terraform apply
+       popd
+
+Run Ansible by hand to configure the vpcaccess server, then connect to the VPN.
+Populate the management EFS.
+Run Ansible by hand to configure a management server, then scale up the management ASG.
+
+Create and deploy any other stacks.
diff --git a/infrastructure/generate-backend-configs.sh b/infrastructure/generate-backend-configs.sh
new file mode 100755 (executable)
index 0000000..f44ef5d
--- /dev/null
@@ -0,0 +1,21 @@
+#!/bin/bash
+# this is a rough hack at the moment, it needs to be better
+
+set -e
+set -o pipefail
+
+tf_infra=$(pushd ../terraform-infrastructure >/dev/null && terraform output -json && popd >/dev/null)
+function infra_value(){
+       jq -er ".${1}.value"<<<"${tf_infra}"
+}
+
+cat<<EOF
+terraform {
+       backend "s3" {
+               region = "$(infra_value region)"
+               bucket = "$(infra_value remote_state_bucket)"
+               dynamodb_table = "$(infra_value remote_state_table)"
+               key = "$(infra_value environment)/$(basename $(pwd)).tfstate"
+       }
+}
+EOF
diff --git a/infrastructure/management-stack/data_vpc.tf b/infrastructure/management-stack/data_vpc.tf
new file mode 100644 (file)
index 0000000..12f8be7
--- /dev/null
@@ -0,0 +1,9 @@
+data "terraform_remote_state" "vpc" {
+       backend = "s3"
+       config {
+               bucket = "${var.remote_state_bucket}"
+               region = "${var.region}"
+               key = "${var.environment}/vpc.tfstate"
+               dynamodb_table = "${var.remote_state_table}"
+       }
+}
diff --git a/infrastructure/management-stack/main.tf b/infrastructure/management-stack/main.tf
new file mode 100644 (file)
index 0000000..6446c01
--- /dev/null
@@ -0,0 +1,15 @@
+provider "aws" {
+       region = "${var.region}"
+}
+
+module "management-stack" {
+       source = "../modules/management-stack"
+       vpc_id = "${data.terraform_remote_state.vpc.vpc_id}"
+       acct_name = "${var.acct_name}"
+       key_name = "${var.key_name}"
+       phase = "${var.environment}"
+       management_subnet_ids = ["${data.terraform_remote_state.vpc.private_subnets}"]
+       security_group_ids = ["${data.terraform_remote_state.vpc.general_access_sg_id}"]
+       policy_arns = ["${data.terraform_remote_state.vpc.base_policy_arn}"]
+       management_service_name = "${var.project}-management"
+}
diff --git a/infrastructure/management-stack/outputs.tf b/infrastructure/management-stack/outputs.tf
new file mode 100644 (file)
index 0000000..c8ee8dc
--- /dev/null
@@ -0,0 +1,4 @@
+output "alerts_topic_arn" { value = "${module.management-stack.alerts_topic_arn}" }
+output "events_topic_arn" { value = "${module.management-stack.events_topic_arn}" }
+output "events_queue_name" { value = "${module.management-stack.events_queue_name}" }
+output "management_data_efs_id" { value = "${module.management-stack.management_data_efs_id}" }
diff --git a/infrastructure/management-stack/terraform.tfvars b/infrastructure/management-stack/terraform.tfvars
new file mode 120000 (symlink)
index 0000000..ac9c2a0
--- /dev/null
@@ -0,0 +1 @@
+../terraform.tfvars
\ No newline at end of file
diff --git a/infrastructure/management-stack/variables.tf b/infrastructure/management-stack/variables.tf
new file mode 100644 (file)
index 0000000..d1a1889
--- /dev/null
@@ -0,0 +1,7 @@
+variable "region" {}
+variable "remote_state_bucket" {}
+variable "remote_state_table" {}
+variable "acct_name" {}
+variable "project" {}
+variable "environment" {}
+variable "key_name" {}
diff --git a/infrastructure/modules/management-stack/README.md b/infrastructure/modules/management-stack/README.md
new file mode 100644 (file)
index 0000000..30ad1e4
--- /dev/null
@@ -0,0 +1,5 @@
+# AWSible Management Stack
+
+Creates the infrastructure for an automated Ansible management system within a VPC, with all the quirks to support a certain style of app deployment.
+
+In summary, this creates an ASG of small instances.  Each shares an EFS mount which shall contain all the Ansible playbooks and data needed to configure an environment.  Each listens to an SQS queue for messages sent from ASG events, and invokes the appropriate playbook when a message is received.
diff --git a/infrastructure/modules/management-stack/iam.tf b/infrastructure/modules/management-stack/iam.tf
new file mode 100644 (file)
index 0000000..3f85134
--- /dev/null
@@ -0,0 +1,66 @@
+data "aws_iam_policy_document" "instance_trust" {
+       statement {
+               effect = "Allow"
+               actions = [
+                       "sts:AssumeRole"
+               ]
+               principals {
+                       type = "Service"
+                       identifiers = [
+                               "ec2.amazonaws.com"
+                       ]
+               }
+       }
+}
+
+resource "aws_iam_role" "management" {
+       name = "${var.management_service_name}-role"
+       assume_role_policy = "${data.aws_iam_policy_document.instance_trust.json}"
+}
+
+data "aws_iam_policy_document" "management" {
+       statement {
+               sid = "AWSControl"
+               actions = [
+                       "autoscaling:*",
+                       "ec2:*",
+                       "elasticloadbalancing:*",
+                       "iam:PassRole",
+                       "iam:GetServerCertificate"
+               ]
+               resources = [
+                       "*"
+               ]
+       }
+       statement {
+               sid = "EventQueue"
+               actions = [
+                       "sqs:*"
+               ]
+               resources = [ "${aws_sqs_queue.management-events-queue.arn}" ]
+       }
+       statement {
+               sid = "AlertTopic"
+               actions = [
+                       "sns:*"
+               ]
+               resources = [ "${aws_sns_topic.management-events.arn}" ]
+       }
+}
+
+resource "aws_iam_policy" "management" {
+       name = "${var.management_service_name}"
+       description = "${var.management_service_name}"
+       path = "/"
+       policy = "${data.aws_iam_policy_document.management.json}"
+}
+
+resource "aws_iam_role_policy_attachment" "management" {
+       role = "${aws_iam_role.management.id}"
+       policy_arn = "${aws_iam_policy.management.arn}"
+}
+
+resource "aws_iam_instance_profile" "management" {
+       name = "${var.management_service_name}-instance-profile"
+       role = "${aws_iam_role.management.name}"
+}
diff --git a/infrastructure/modules/management-stack/management.tf b/infrastructure/modules/management-stack/management.tf
new file mode 100644 (file)
index 0000000..6efa19c
--- /dev/null
@@ -0,0 +1,185 @@
+resource "aws_security_group" "management-elb" {
+       count = "${var.management_elb > 0 ? 1 : 0}"
+       vpc_id = "${var.vpc_id}"
+       name = "${var.management_service_name}-elb"
+       description = "${var.management_service_name} internal ELB"
+}
+resource "aws_security_group_rule" "management-elb-out-all" {
+       count = "${var.management_elb > 0 ? 1 : 0}"
+       security_group_id = "${aws_security_group.management-elb.id}"
+       type = "egress"
+       from_port = 0
+       to_port = 0
+       protocol = "all"
+       cidr_blocks = [ "0.0.0.0/0" ]
+}
+resource "aws_security_group_rule" "management-elb-in-ssh" {
+       count = "${var.management_elb > 0 ? 1 : 0}"
+       security_group_id = "${aws_security_group.management-elb.id}"
+       type = "ingress"
+       from_port = 22
+       to_port = 22
+       protocol = "tcp"
+       cidr_blocks = [ "0.0.0.0/0" ]
+}
+
+resource "aws_security_group" "management" {
+       vpc_id = "${var.vpc_id}"
+       name = "${var.management_service_name}"
+       description = "${var.management_service_name} service"
+}
+resource "aws_security_group_rule" "management-out-all" {
+       security_group_id = "${aws_security_group.management.id}"
+       type = "egress"
+       from_port = 0
+       to_port = 0
+       protocol = "all"
+       cidr_blocks = [ "0.0.0.0/0" ]
+}
+resource "aws_security_group_rule" "management-in-self" {
+       security_group_id = "${aws_security_group.management.id}"
+       type = "ingress"
+       from_port = 0
+       to_port = 0
+       protocol = "all"
+       self = true
+}
+resource "aws_security_group_rule" "management-in-elb" {
+       security_group_id = "${aws_security_group.management.id}"
+       type = "ingress"
+       from_port = 0
+       to_port = 0
+       protocol = "all"
+       source_security_group_id = "${aws_security_group.management-elb.id}"
+}
+
+resource "aws_elb" "management" {
+       count = "${var.management_elb > 0 ? 1 : 0}"
+       name = "${var.management_service_name}-int-elb"
+       security_groups = ["${aws_security_group.management-elb.id}"]
+       internal = true
+       listener {
+               instance_port = 22
+               instance_protocol = "TCP"
+               lb_port = 22
+               lb_protocol = "TCP"
+       }
+       health_check {
+               healthy_threshold = 3
+               unhealthy_threshold = 2
+               target = "TCP:22"
+               interval = 30
+               timeout = 10
+       }
+       idle_timeout = 600
+       subnets = ["${var.management_subnet_ids}"]
+}
+
+data "aws_ami" "amazon_linux" {
+       count = "${length(var.ami) > 0 ? 0 : 1}"
+       most_recent = true
+       owners = ["amazon"]
+       filter {
+               name = "name"
+               values = ["amzn-ami-hvm-*-gp2"]
+       }
+       filter {
+               name = "root-device-type"
+               values = ["ebs"]
+       }
+}
+
+data "aws_region" "current" {
+       current = true
+}
+data "template_file" "user_data" {
+       template = "${file("${path.module}/user-data.tpl")}"
+       vars {
+               region = "${data.aws_region.current.name}"
+               app_name = "${var.management_service_name}"
+               stack = ""
+               phase = "${var.phase}"
+               country = ""
+               cluster = "${var.management_service_name}-d0${var.phase}"
+               acct_name = "${var.acct_name}"
+       }
+}
+
+resource "aws_launch_configuration" "management" {
+       name_prefix = "${var.management_service_name}"
+       image_id = "${length(var.ami) > 0 ? var.ami : data.aws_ami.amazon_linux.image_id}"
+       instance_type = "${var.instance_type}"
+       iam_instance_profile = "${aws_iam_instance_profile.management.name}"
+       key_name = "${var.key_name}"
+       security_groups = ["${concat(var.security_group_ids, list(aws_security_group.management.id))}"]
+       associate_public_ip_address = false
+       user_data = "${data.template_file.user_data.rendered}"
+       lifecycle {
+               create_before_destroy = true
+       }
+}
+
+resource "aws_autoscaling_group" "management" {
+       name = "${var.management_service_name}"
+       launch_configuration = "${aws_launch_configuration.management.name}"
+       vpc_zone_identifier = ["${var.management_subnet_ids}"]
+       min_size = 0
+       max_size = "${length(var.management_subnet_ids)}"
+       default_cooldown = 10
+       health_check_type = "EC2"
+       load_balancers = ["${var.management_elb > 0 ? aws_elb.management.name : ""}"]
+       lifecycle {
+               create_before_destroy = true
+       }
+       tag {
+               propagate_at_launch = true
+               key = "module"
+               value = "${var.management_service_name}"
+       }
+       tag {
+               propagate_at_launch = true
+               key = "phase"
+               value = "${var.phase}"
+       }
+}
+
+resource "aws_autoscaling_notification" "management" {
+       group_names = ["${aws_autoscaling_group.management.name}"]
+       topic_arn = "${aws_sns_topic.management-events.arn}"
+       notifications = [
+               "autoscaling:EC2_INSTANCE_LAUNCH",
+               "autoscaling:EC2_INSTANCE_LAUNCH_ERROR",
+               "autoscaling:EC2_INSTANCE_TERMINATE",
+               "autoscaling:EC2_INSTANCE_TERMINATE_ERROR"
+       ]
+}
+
+data "aws_subnet" "management" {
+       count = "${length(var.management_subnet_ids)}"
+       id = "${element(var.management_subnet_ids, count.index)}"
+}
+
+resource "aws_ebs_volume" "management-data" {
+       count = "${length(var.management_subnet_ids) * var.management_data_efs}"
+       availability_zone = "${element(data.aws_subnet.management.*.availability_zone, count.index)}"
+       size = "${var.management_data_volume_size}"
+       type = "gp2"
+       tags {
+               module = "${var.management_service_name}"
+       }
+}
+
+resource "aws_efs_file_system" "management-data" {
+       count = "${var.management_data_efs}"
+       creation_token = "${var.management_service_name}-data"
+       tags {
+               Name = "${var.management_service_name}-data"
+       }
+}
+
+resource "aws_efs_mount_target" "management-data" {
+       count = "${length(var.management_subnet_ids) * var.management_data_efs}"
+       file_system_id = "${aws_efs_file_system.management-data.id}"
+       subnet_id = "${element(var.management_subnet_ids, count.index)}"
+       security_groups = ["${aws_security_group.management.id}"]
+}
diff --git a/infrastructure/modules/management-stack/outputs.tf b/infrastructure/modules/management-stack/outputs.tf
new file mode 100644 (file)
index 0000000..e03c6eb
--- /dev/null
@@ -0,0 +1,4 @@
+output "alerts_topic_arn" { value = "${aws_sns_topic.management-alerts.arn}" }
+output "events_topic_arn" { value = "${aws_sns_topic.management-events.arn}" }
+output "events_queue_name" { value = "${aws_sqs_queue.management-events-queue.name}" }
+output "management_data_efs_id" { value = "${var.management_data_efs > 0 ? aws_efs_file_system.management-data.id : ""}" }
diff --git a/infrastructure/modules/management-stack/queues.tf b/infrastructure/modules/management-stack/queues.tf
new file mode 100644 (file)
index 0000000..b44f69f
--- /dev/null
@@ -0,0 +1,48 @@
+resource "aws_sqs_queue" "management-events-dlq" {
+       name = "${length(var.sqs_events_name) > 0 ? var.sqs_events_name : var.management_service_name}${length(var.sqs_events_name) > 0 ? "" : "-events"}-failed"
+       visibility_timeout_seconds = 30
+       message_retention_seconds = 1209600
+       max_message_size = 262144
+       receive_wait_time_seconds = 0
+}
+resource "aws_sqs_queue" "management-events-queue" {
+       name = "${length(var.sqs_events_name) > 0 ? var.sqs_events_name : var.management_service_name}${length(var.sqs_events_name) > 0 ? "" : "-events"}"
+       visibility_timeout_seconds = 60
+       message_retention_seconds = 1209600
+       max_message_size = 262144
+       receive_wait_time_seconds = 20
+       redrive_policy = "{\"deadLetterTargetArn\":\"${aws_sqs_queue.management-events-dlq.arn}\",\"maxReceiveCount\":5}"
+}
+resource "aws_sns_topic" "management-events" {
+       name = "${length(var.sns_events_name) > 0 ? var.sns_events_name : var.management_service_name}${length(var.sns_events_name) > 0 ? "" : "-events"}"
+}
+data "aws_iam_policy_document" "management-queue" {
+       statement {
+               effect = "Allow"
+               sid = "TopicPublish"
+               actions = ["SQS:SendMessage"]
+               resources = ["${aws_sqs_queue.management-events-queue.arn}"]
+               condition {
+                       test = "ForAnyValue:ArnEquals"
+                       variable = "aws:SourceArn"
+                       values = ["${aws_sns_topic.management-events.arn}"]
+               }
+               principals {
+                       type = "AWS"
+                       identifiers = ["*"]
+               }
+       }
+}
+resource "aws_sqs_queue_policy" "management-events" {
+       queue_url = "${aws_sqs_queue.management-events-queue.id}"
+       policy = "${data.aws_iam_policy_document.management-queue.json}"
+}
+resource "aws_sns_topic_subscription" "management-events-subscription" {
+       topic_arn = "${aws_sns_topic.management-events.arn}"
+       endpoint = "${aws_sqs_queue.management-events-queue.arn}"
+       protocol = "sqs"
+}
+
+resource "aws_sns_topic" "management-alerts" {
+       name = "${length(var.sns_alerts_name) > 0 ? var.sns_alerts_name : var.management_service_name}${length(var.sns_alerts_name) > 0 ? "" : "-alerts"}"
+}
diff --git a/infrastructure/modules/management-stack/user-data.tpl b/infrastructure/modules/management-stack/user-data.tpl
new file mode 100644 (file)
index 0000000..72caca9
--- /dev/null
@@ -0,0 +1,8 @@
+#!/bin/bash
+export EC2_REGION="${region}"
+export CLOUD_APP="${app_name}"
+export CLOUD_STACK="${stack}"
+export CLOUD_DEV_PHASE="${phase}"
+export CLOUD_COUNTRIES="${country}"
+export CLOUD_ENVIRONMENT="${acct_name}"
+export CLOUD_CLUSTER="${cluster}"
diff --git a/infrastructure/modules/management-stack/variables.tf b/infrastructure/modules/management-stack/variables.tf
new file mode 100644 (file)
index 0000000..c47e8b6
--- /dev/null
@@ -0,0 +1,74 @@
+variable "vpc_id" {
+       description = "Which VPC to build this in."
+}
+
+variable "acct_name" {
+       description = "Name of AWS account."
+}
+
+variable "instance_type" {
+       default = "t2.small"
+}
+
+variable "key_name" {}
+
+variable "management_subnet_ids" {
+       type = "list"
+       description = "Which subnets the management servers will be in. (Typically private.)"
+}
+
+variable "phase" {
+       description = "Release phase of this environment. (Such as dev, stage, or prod.)"
+       default = "dev"
+}
+
+variable "ami" {
+       description = "Specify an AMI to use; if empty, use most recent amazon linux."
+       default = ""
+}
+
+variable "security_group_ids" {
+       type = "list"
+       description = "Additional security groups the management servers will belong to. (Typically the general-access SG.)"
+       default = []
+}
+
+variable "policy_arns" {
+       type = "list"
+       description = "Additional policy arns the management role will have. (Typically the base policy.)"
+       default = []
+}
+
+variable "management_elb" {
+       default = false
+       description = "Whether to place management servers behind an ELB."
+}
+
+variable "management_data_efs" {
+       default = true
+       description = "Management instances share a common EFS filesystem.  If false, each has its own EBS volume."
+}
+
+variable "management_data_volume_size" {
+       default = 20
+       description = "Size of individual data volumes, if used."
+}
+
+variable "management_service_name" {
+       default = "management"
+}
+
+variable "sns_events_name" {
+       default = ""
+       description = "Name of the SNS topic to which ASGs send notifications.  Defaults to {management_service_name}-events."
+}
+
+variable "sqs_events_name" {
+       default = ""
+       description = "Name of the SQS queue the events topic feeds, and the management system listens to.  Defaults to {management_service_name}-events."
+}
+
+variable "sns_alerts_name" {
+       default = ""
+       description = "Name of the SNS topic to which informational messages are sent, to be mailed to interested meat-based parties.  Defaults to {management_service_name}-alerts."
+}
diff --git a/infrastructure/modules/management-stack/version.tf b/infrastructure/modules/management-stack/version.tf
new file mode 100644 (file)
index 0000000..353643f
--- /dev/null
@@ -0,0 +1,3 @@
+terraform {
+       required_version = ">= 0.10.2"
+}
diff --git a/infrastructure/modules/terraform-infrastructure/main.tf b/infrastructure/modules/terraform-infrastructure/main.tf
new file mode 100644 (file)
index 0000000..1da303d
--- /dev/null
@@ -0,0 +1,19 @@
+resource "aws_s3_bucket" "tf_state" {
+       bucket = "${var.remote_state_bucket}"
+       region = "${var.region}"
+       acl = "private"
+       versioning {
+               enabled = true
+       }
+}
+
+resource "aws_dynamodb_table" "tf_lock" {
+       name = "${var.remote_state_table}"
+       read_capacity = 1
+       write_capacity = 1
+       hash_key = "LockID"
+       attribute {
+               name = "LockID"
+               type = "S"
+       }
+}
diff --git a/infrastructure/modules/terraform-infrastructure/outputs.tf b/infrastructure/modules/terraform-infrastructure/outputs.tf
new file mode 100644 (file)
index 0000000..54b2cf9
--- /dev/null
@@ -0,0 +1,3 @@
+output "region" { value = "${var.region}" }
+output "remote_state_bucket" { value = "${var.remote_state_bucket}" }
+output "remote_state_table" { value = "${var.remote_state_table}" }
diff --git a/infrastructure/modules/terraform-infrastructure/variables.tf b/infrastructure/modules/terraform-infrastructure/variables.tf
new file mode 100644 (file)
index 0000000..b1df2ff
--- /dev/null
@@ -0,0 +1,3 @@
+variable "region" {}
+variable "remote_state_bucket" {}
+variable "remote_state_table" {}
diff --git a/infrastructure/modules/tf_aws_asg_stack/README.md b/infrastructure/modules/tf_aws_asg_stack/README.md
new file mode 100644 (file)
index 0000000..bfe033b
--- /dev/null
@@ -0,0 +1,3 @@
+# AutoScalingGroup Stack
+
+Creates an ASG, LC, self-allowing SG, and an IAM role for a certain style of application stack.
diff --git a/infrastructure/modules/tf_aws_asg_stack/iam.tf b/infrastructure/modules/tf_aws_asg_stack/iam.tf
new file mode 100644 (file)
index 0000000..1c257c4
--- /dev/null
@@ -0,0 +1,49 @@
+data "aws_iam_policy_document" "instance_trust" {
+       statement {
+               effect = "Allow"
+               actions = [
+                       "sts:AssumeRole"
+               ]
+               principals {
+                       type = "Service"
+                       identifiers = [
+                               "ec2.amazonaws.com"
+                       ]
+               }
+       }
+}
+
+resource "aws_iam_role" "default" {
+       name = "${var.module}${length(var.stack) > 0 ? "-" : ""}${var.stack}-role"
+       assume_role_policy = "${data.aws_iam_policy_document.instance_trust.json}"
+}
+
+data "aws_iam_policy_document" "default" {
+       statement {
+               effect = "Allow"
+               actions = ["${var.iam_allow_actions}"]
+               resources = ["*"]
+       }
+}
+
+resource "aws_iam_policy" "default" {
+       name = "${var.module}${length(var.stack) > 0 ? "-" : ""}${var.stack}"
+       description = "specific policy for ${var.module}${length(var.stack) > 0 ? "-" : ""}${var.stack}"
+       policy = "${data.aws_iam_policy_document.default.json}"
+}
+
+resource "aws_iam_role_policy_attachment" "default" {
+       role = "${aws_iam_role.default.id}"
+       policy_arn = "${aws_iam_policy.default.arn}"
+}
+
+resource "aws_iam_role_policy_attachment" "extra" {
+       count = "${length(var.iam_policy_arns)}"
+       role = "${aws_iam_role.default.id}"
+       policy_arn = "${element(var.iam_policy_arns, count.index)}"
+}
+
+resource "aws_iam_instance_profile" "default" {
+       name = "${var.module}${length(var.stack) > 0 ? "-" : ""}${var.stack}-instance-profile"
+       role = "${aws_iam_role.default.name}"
+}
diff --git a/infrastructure/modules/tf_aws_asg_stack/main.tf b/infrastructure/modules/tf_aws_asg_stack/main.tf
new file mode 100644 (file)
index 0000000..6a50ea3
--- /dev/null
@@ -0,0 +1,125 @@
+resource "aws_security_group" "default" {
+       vpc_id = "${var.vpc_id}"
+       name = "${var.module}${length(var.stack) > 0 ? "-" : ""}${var.stack}-self"
+       description = "${var.module}${length(var.stack) > 0 ? "-" : ""}${var.stack} self-access"
+}
+resource "aws_security_group_rule" "default-out-all" {
+       security_group_id = "${aws_security_group.default.id}"
+       type = "egress"
+       from_port = 0
+       to_port = 0
+       protocol = "all"
+       cidr_blocks = [ "0.0.0.0/0" ]
+}
+resource "aws_security_group_rule" "default-in-self" {
+       security_group_id = "${aws_security_group.default.id}"
+       type = "ingress"
+       from_port = 0
+       to_port = 0
+       protocol = "all"
+       self = true
+}
+resource "aws_security_group_rule" "default-in-elb" {
+       count = "${length(var.elb_sg_ids)}"
+       security_group_id = "${aws_security_group.default.id}"
+       type = "ingress"
+       from_port = 0
+       to_port = 0
+       protocol = "all"
+       source_security_group_id = "${element(var.elb_sg_ids, count.index)}"
+}
+
+data "aws_ami" "amazon_linux" {
+       count = "${length(var.ami) > 0 ? 0 : 1}"
+       most_recent = true
+       owners = ["amazon"]
+       filter {
+               name = "name"
+               values = ["amzn-ami-hvm-*-gp2"]
+       }
+       filter {
+               name = "root-device-type"
+               values = ["ebs"]
+       }
+}
+
+data "aws_region" "current" {
+       current = true
+}
+data "template_file" "user_data" {
+       template = "${file("${path.module}/user-data.tpl")}"
+       vars {
+               region = "${data.aws_region.current.name}"
+               app_name = "${var.module}"
+               stack = "${var.stack}"
+               phase = "${var.phase}"
+               country = "${var.country}"
+               cluster = "${var.module}${length(var.stack) > 0 ? "-" : ""}${var.stack}${length(var.country) > 0 ? "-c0" : ""}${var.country}${length(var.phase) > 0 ? "-d0" : ""}${var.phase}${length(var.suffix) > 0 ? "-" : ""}${var.suffix}"
+               acct_name = "${var.acct_name}"
+       }
+}
+
+resource "aws_launch_configuration" "default" {
+       name_prefix = "${var.module}${length(var.stack) > 0 ? "-" : ""}${var.stack}${length(var.country) > 0 ? "-c0" : ""}${var.country}${length(var.phase) > 0 ? "-d0" : ""}${var.phase}${length(var.suffix) > 0 ? "-" : ""}${var.suffix}-"
+       image_id = "${length(var.ami) > 0 ? var.ami : data.aws_ami.amazon_linux.image_id}"
+       instance_type = "${var.instance_type}"
+       iam_instance_profile = "${aws_iam_instance_profile.default.name}"
+       key_name = "${var.key_name}"
+       security_groups = ["${concat(var.security_group_ids, list(aws_security_group.default.id))}"]
+       associate_public_ip_address = "${var.public_ips}"
+       user_data = "${data.template_file.user_data.rendered}"
+       ephemeral_block_device {
+               virtual_name = "ephemeral0"
+               device_name = "/dev/sdb"
+       }
+       lifecycle {
+               create_before_destroy = true
+       }
+}
+
+resource "aws_autoscaling_group" "default" {
+       name = "${var.module}${length(var.stack) > 0 ? "-" : ""}${var.stack}${length(var.country) > 0 ? "-c0" : ""}${var.country}${length(var.phase) > 0 ? "-d0" : ""}${var.phase}${length(var.suffix) > 0 ? "-" : ""}${var.suffix}"
+       launch_configuration = "${aws_launch_configuration.default.name}"
+       vpc_zone_identifier = ["${var.subnet_ids}"]
+       min_size = "${var.min_size}"
+       max_size = "${var.max_size > 0 ? var.max_size : length(var.subnet_ids)}"
+       default_cooldown = 10
+       health_check_type = "EC2"
+       health_check_grace_period = "${var.health_check_grace_period}"
+       load_balancers = ["${var.elbs}"]
+       lifecycle {
+               create_before_destroy = true
+       }
+       tag {
+               propagate_at_launch = true
+               key = "module"
+               value = "${var.module}"
+       }
+       tag {
+               propagate_at_launch = true
+               key = "stack"
+               value = "${var.stack}"
+       }
+       tag {
+               propagate_at_launch = true
+               key = "country"
+               value = "${var.country}"
+       }
+       tag {
+               propagate_at_launch = true
+               key = "phase"
+               value = "${var.phase}"
+       }
+}
+
+resource "aws_autoscaling_notification" "default" {
+       count = "${length(var.notification_arns)}"
+       group_names = ["${aws_autoscaling_group.default.name}"]
+       topic_arn = "${element(var.notification_arn, count.index)}"
+       notifications = [
+               "autoscaling:EC2_INSTANCE_LAUNCH",
+               "autoscaling:EC2_INSTANCE_LAUNCH_ERROR",
+               "autoscaling:EC2_INSTANCE_TERMINATE",
+               "autoscaling:EC2_INSTANCE_TERMINATE_ERROR"
+       ]
+}
diff --git a/infrastructure/modules/tf_aws_asg_stack/outputs.tf b/infrastructure/modules/tf_aws_asg_stack/outputs.tf
new file mode 100644 (file)
index 0000000..fa65ab8
--- /dev/null
@@ -0,0 +1,4 @@
+output "sg_id" { value = "${aws_security_group.default.id}" }
+output "asg_id" { value = "${aws_autoscaling_group.default.id}" }
+output "iam_role_id" { value = "${aws_iam_role.default.id}" }
+output "iam_role_name" { value = "${aws_iam_role.default.name}" }
diff --git a/infrastructure/modules/tf_aws_asg_stack/user-data.tpl b/infrastructure/modules/tf_aws_asg_stack/user-data.tpl
new file mode 100644 (file)
index 0000000..72caca9
--- /dev/null
@@ -0,0 +1,8 @@
+#!/bin/bash
+export EC2_REGION="${region}"
+export CLOUD_APP="${app_name}"
+export CLOUD_STACK="${stack}"
+export CLOUD_DEV_PHASE="${phase}"
+export CLOUD_COUNTRIES="${country}"
+export CLOUD_ENVIRONMENT="${acct_name}"
+export CLOUD_CLUSTER="${cluster}"
diff --git a/infrastructure/modules/tf_aws_asg_stack/variables.tf b/infrastructure/modules/tf_aws_asg_stack/variables.tf
new file mode 100644 (file)
index 0000000..e8a8b0d
--- /dev/null
@@ -0,0 +1,97 @@
+variable "vpc_id" {
+       description = "Which VPC to build this in."
+}
+
+variable "acct_name" {
+       description = "Name of AWS account."
+}
+
+variable "notification_arns" {
+       type = "list"
+       description = "ARNs of SNS topics to send ASG event notifications to."
+       default = ""
+}
+
+variable "module" {
+       description = "Name of this application."
+}
+
+variable "stack" {
+       description = "Subtype of module. (Such as 'master' or 'data'.)"
+       default = ""
+}
+
+variable "country" {
+       description = "'Country' code, which actually represents a specific AZ for us."
+       default = ""
+}
+
+variable "phase" {
+       description = "Release phase of this environment. (Such as dev, stage, or prod.)"
+       default = "dev"
+}
+
+variable "suffix" {
+       description = "Extra stuff tacked on to end of name."
+       default = ""
+}
+
+variable "instance_type" {}
+
+variable "key_name" {}
+
+variable "public_ips" {
+       default = false
+}
+
+variable "subnet_ids" {
+       type = "list"
+       description = "Which subnets the servers will be in."
+}
+
+variable "iam_allow_actions" {
+       type = "list"
+       default = []
+       description = "Allowed actions to associate with the IAM role."
+}
+
+variable "iam_policy_arns" {
+       type = "list"
+       default = []
+       description = "Additional policies to attach to IAM role."
+}
+
+variable "max_size" {
+       description = "Defaults to 1 instance per subnet. (Cannot be zero.)"
+       default = 0
+}
+
+variable "min_size" {
+       default = 0
+}
+
+variable "health_check_grace_period" {
+       default = 600
+}
+
+variable "ami" {
+       description = "Specify an AMI to use; if empty, use most recent amazon linux."
+       default = ""
+}
+
+variable "elb_sg_ids" {
+       type = "list"
+       description = "ID of elb security group, to allow access from."
+       default = []
+}
+
+variable "elbs" {
+       type = "list"
+       default = []
+}
+
+variable "security_group_ids" {
+       type = "list"
+       description = "Additional security groups the servers will belong to."
+       default = []
+}
diff --git a/infrastructure/modules/tf_aws_asg_stack/version.tf b/infrastructure/modules/tf_aws_asg_stack/version.tf
new file mode 100644 (file)
index 0000000..a56eb0c
--- /dev/null
@@ -0,0 +1,4 @@
+terraform {
+  required_version = ">= 0.10.2"
+}
+
diff --git a/infrastructure/modules/tf_aws_vpc/README.md b/infrastructure/modules/tf_aws_vpc/README.md
new file mode 100644 (file)
index 0000000..8b31cad
--- /dev/null
@@ -0,0 +1,10 @@
+Creates a basic AWS VPC environment, with a public and private subnet per AZ, NAT gateways, and routing tables, as well as a base iam role and security group.
+
+Required variables:
+
+       region
+       project
+       environment
+       cidr
+       public_azs
+       private_azs
diff --git a/infrastructure/modules/tf_aws_vpc/main.tf b/infrastructure/modules/tf_aws_vpc/main.tf
new file mode 100644 (file)
index 0000000..4b36310
--- /dev/null
@@ -0,0 +1,239 @@
+resource "aws_vpc_dhcp_options" "default" {
+       count = "${var.enable_domain_name}"
+       domain_name = "ec2.internal ${var.r53_domain_name}"
+       domain_name_servers = ["AmazonProvidedDNS"]
+       tags {
+               Name = "${var.project}-${var.environment}-dhcp_options_set"
+               service = "${var.project}-${var.environment}-dhcp_options_set"
+               project = "${var.project}"
+               environment = "${var.environment}"
+               role = "dhcp_options_set"
+       }
+}
+
+resource "aws_vpc_dhcp_options_association" "default" {
+       count = "${var.enable_domain_name}"
+       vpc_id = "${aws_vpc.default.id}"
+       dhcp_options_id = "${aws_vpc_dhcp_options.default.id}"
+}
+
+resource "aws_vpc" "default" {
+       cidr_block = "${var.cidr}"
+       enable_dns_hostnames = "${var.enable_dns_hostnames}"
+       enable_dns_support = "${var.enable_dns_support}"
+       instance_tenancy = "default"
+       tags {
+               Name = "${var.project}-${var.environment}-vpc"
+               service = "${var.project}-${var.environment}-vpc"
+               project = "${var.project}"
+               environment = "${var.environment}"
+               role = "vpc"
+       }
+}
+
+resource "aws_internet_gateway" "default" {
+       vpc_id = "${aws_vpc.default.id}"
+       tags {
+               Name = "${var.project}-${var.environment}-igw"
+               service = "${var.project}-${var.environment}-igw"
+               project = "${var.project}"
+               environment = "${var.environment}"
+               role = "igw"
+       }
+}
+
+data "aws_vpc_peering_connection" "peer" {
+       count = "${length(var.peering_connection_ids)}"
+       id = "${element(var.peering_connection_ids, count.index)}"
+}
+
+resource "aws_default_route_table" "default" {
+       default_route_table_id = "${aws_vpc.default.default_route_table_id}"
+}
+
+resource "aws_route" "default_gateway" {
+       route_table_id = "${aws_default_route_table.default.id}"
+       destination_cidr_block = "0.0.0.0/0"
+       gateway_id = "${aws_internet_gateway.default.id}"
+}
+
+resource "aws_route" "default_peer" {
+       count = "${length(var.peering_connection_ids)}"
+       route_table_id = "${aws_default_route_table.default.id}"
+       destination_cidr_block = "${element(data.aws_vpc_peering_connection.peer.*.cidr_block, count.index)}"
+       vpc_peering_connection_id = "${element(data.aws_vpc_peering_connection.peer.*.id, count.index)}"
+}
+
+resource "aws_route_table" "public" {
+       vpc_id = "${aws_vpc.default.id}"
+       tags {
+               Name = "${var.project}-${var.environment}-public"
+               service = "${var.project}-${var.environment}-route-table"
+               project = "${var.project}"
+               environment = "${var.environment}"
+               role = "route-table"
+       }
+}
+
+resource "aws_route" "public_gateway" {
+       route_table_id = "${aws_route_table.public.id}"
+       destination_cidr_block = "0.0.0.0/0"
+       gateway_id = "${aws_internet_gateway.default.id}"
+}
+
+resource "aws_route" "public_peer" {
+       count = "${length(var.peering_connection_ids)}"
+       route_table_id = "${aws_route_table.public.id}"
+       destination_cidr_block = "${element(data.aws_vpc_peering_connection.peer.*.cidr_block, count.index)}"
+       vpc_peering_connection_id = "${element(data.aws_vpc_peering_connection.peer.*.id, count.index)}"
+}
+
+resource "aws_subnet" "public" {
+       count = "${length(var.public_azs)}"
+       vpc_id = "${aws_vpc.default.id}"
+       cidr_block = "${cidrsubnet(var.cidr, 8, count.index + var.subnets_offset_public)}"
+       availability_zone = "${element(var.public_azs, count.index)}"
+       tags {
+               Name = "${var.project}-${var.environment}-public-${element(var.public_azs, count.index)}"
+               project = "${var.project}"
+               environment = "${var.environment}"
+               service = "${var.project}-${var.environment}-subnet-public"
+               role = "subnet"
+               zone = "pub"
+       }
+       map_public_ip_on_launch = true
+}
+
+resource "aws_route_table_association" "public" {
+       count = "${length(var.public_azs)}"
+       subnet_id = "${element(aws_subnet.public.*.id, count.index)}"
+       route_table_id =  "${element(aws_route_table.public.*.id, count.index)}"
+}
+
+resource "aws_subnet" "private" {
+       count = "${length(var.private_azs)}"
+       vpc_id = "${aws_vpc.default.id}"
+       cidr_block = "${cidrsubnet(var.cidr, 8, count.index + var.subnets_offset_private)}"
+       availability_zone = "${element(var.private_azs, count.index)}"
+       tags {
+               Name = "${var.project}-${var.environment}-private-${element(var.private_azs, count.index)}"
+               project = "${var.project}"
+               environment = "${var.environment}"
+               service = "${var.project}-${var.environment}-subnet-private"
+               role = "subnet"
+               zone = "priv"
+       }
+       map_public_ip_on_launch = false
+}
+
+resource "aws_route_table_association" "private" {
+       count = "${length(var.private_azs)}"
+       subnet_id = "${element(aws_subnet.private.*.id, count.index)}"
+       route_table_id = "${element(aws_route_table.private.*.id, count.index)}"
+}
+
+resource "aws_route_table" "private" {
+       count = "${length(var.private_azs)}"
+       vpc_id = "${aws_vpc.default.id}"
+       tags {
+               Name = "${var.project}-${var.environment}-private${format("%02d", count.index + 1)}"
+               project = "${var.project}"
+               environment = "${var.environment}"
+               service = "${var.project}-${var.environment}-route-table-private"
+               role = "route-table"
+       }
+}
+
+resource "aws_route" "private_gateway" {
+       count = "${length(var.private_azs)}"
+       route_table_id = "${element(aws_route_table.private.*.id, count.index)}"
+       destination_cidr_block = "0.0.0.0/0"
+       nat_gateway_id = "${element(aws_nat_gateway.default.*.id, count.index)}"
+}
+
+resource "aws_route" "private_peer" {
+       count = "${length(var.peering_connection_ids) * length(var.private_azs)}"
+       route_table_id = "${element(aws_route_table.private.*.id, count.index / length(var.private_azs))}"
+       destination_cidr_block = "${element(data.aws_vpc_peering_connection.peer.*.cidr_block, count.index % length(var.private_azs))}"
+       vpc_peering_connection_id = "${element(data.aws_vpc_peering_connection.peer.*.id, count.index % length(var.private_azs))}"
+}
+
+resource "aws_eip" "nat" {
+       count = "${length(var.private_azs)}"
+       vpc = true
+}
+
+resource "aws_nat_gateway" "default" {
+       count = "${length(var.private_azs)}"
+       allocation_id = "${element(aws_eip.nat.*.id, count.index)}"
+       subnet_id = "${element(aws_subnet.public.*.id, count.index)}"
+}
+
+data "aws_iam_policy_document" "base" {
+       statement {
+               sid = "aws-read"
+               resources = ["*"]
+               actions = [
+                       "autoscaling:Describe*",
+                       "cloudwatch:ListMetrics",
+                       "cloudwatch:GetMetricsStatistics",
+                       "cloudwatch:Describe*",
+                       "ec2:Describe*",
+                       "elasticloadbalancing:Describe*",
+                       "logs:CreateLogGroup",
+                       "logs:CreateLogStream",
+                       "logs:Describe*",
+                       "logs:PutLogEvents",
+                       "logs:PutMetricFilter"
+               ]
+       }
+}
+
+resource "aws_iam_policy" "base" {
+       name = "base-policy"
+       path = "/"
+       description = "base-policy"
+       policy = "${data.aws_iam_policy_document.base.json}"
+}
+
+resource "aws_security_group" "general-access" {
+       name = "general-access"
+       description = "Allow all ICMP and intra-vpc SSH traffic"
+       vpc_id = "${aws_vpc.default.id}"
+}
+
+resource "aws_security_group_rule" "ga_out_all" {
+       security_group_id = "${aws_security_group.general-access.id}"
+       type = "egress"
+       from_port = 0
+       to_port = 0
+       protocol = "all"
+       cidr_blocks = ["0.0.0.0/0"]
+       lifecycle {
+               create_before_destroy = true
+       }
+}
+
+resource "aws_security_group_rule" "ga_in_icmp" {
+       security_group_id = "${aws_security_group.general-access.id}"
+       type = "ingress"
+       from_port = -1
+       to_port = -1
+       protocol = "icmp"
+       cidr_blocks = ["0.0.0.0/0"]
+       lifecycle {
+               create_before_destroy = true
+       }
+}
+
+resource "aws_security_group_rule" "ga_in_ssh" {
+       security_group_id = "${aws_security_group.general-access.id}"
+       type = "ingress"
+       from_port = 22
+       to_port = 22
+       protocol = "tcp"
+       cidr_blocks = ["${concat(list(var.cidr), var.ssh_allowed_cidr)}"]
+       lifecycle {
+               create_before_destroy = true
+       }
+}
diff --git a/infrastructure/modules/tf_aws_vpc/outputs.tf b/infrastructure/modules/tf_aws_vpc/outputs.tf
new file mode 100644 (file)
index 0000000..ca68bbc
--- /dev/null
@@ -0,0 +1,35 @@
+output "vpc_id" {
+       value = "${aws_vpc.default.id}"
+}
+
+output "vpc_name" {
+       value = "${var.project}-${var.environment}-vpc"
+}
+
+output "public_subnets" {
+       value = "${aws_subnet.public.*.id}"
+}
+
+output "private_subnets" {
+       value = "${aws_subnet.private.*.id}"
+}
+
+output "nat_gateway_ips" {
+       value = "${aws_eip.nat.*.public_ip}"
+}
+
+output "private_route_table_ids" {
+       value =  "${aws_route_table.private.*.id}"
+}
+
+output "public_route_table_id" {
+       value = "${aws_route_table.public.id}"
+}
+
+output "base_policy_arn" {
+  value = "${aws_iam_policy.base.arn}"
+}
+
+output "general_access_sg_id" {
+  value = "${aws_security_group.general-access.id}"
+}
diff --git a/infrastructure/modules/tf_aws_vpc/variables.tf b/infrastructure/modules/tf_aws_vpc/variables.tf
new file mode 100644 (file)
index 0000000..0b30d3e
--- /dev/null
@@ -0,0 +1,66 @@
+variable "project" {
+    description = "topmost classification name"
+}
+
+variable "environment" {
+    description = "deployment environment of this vpc, e.g. prod, stage, dev"
+    default = "dev"
+}
+
+variable "cidr" {
+    description = "cidr block for this vpc"
+}
+
+variable "public_azs" {
+    type = "list"
+    description = "list of azs to use for public subnets in this vpc (full specification, such as us-east-1a)"
+    default = []
+}
+
+variable "private_azs" {
+    type = "list"
+    description = "list of azs to use for private subnets in this vpc (full specification, such as us-east-1a)"
+    default = []
+}
+
+variable "r53_domain_name" {
+    description = "domain name for everything in this vpc"
+    default = ""
+}
+
+variable "enable_dns_hostnames" {
+    description = "should be true if you want to use private DNS within the VPC"
+    default = true
+}
+
+variable "enable_dns_support" {
+    description = "should be true if you want to use private DNS within the VPC"
+    default = true
+}
+
+variable "enable_domain_name" {
+    description = "configure dhcp option with r53_domain_name"
+    default = false
+}
+
+variable "subnets_offset_public" {
+    description = "start numbering public subnets with this value"
+    default = 0
+}
+
+variable "subnets_offset_private" {
+    description = "start numbering private subnets with this value"
+    default = 128
+}
+
+variable "peering_connection_ids" {
+    type = "list"
+    description = "pcx ids of accepted vpc peerings"
+    default = []
+}
+
+variable "ssh_allowed_cidr" {
+    type = "list"
+    description = "list of additional cidr blocks to allow SSH traffic from"
+    default = []
+}
\ No newline at end of file
diff --git a/infrastructure/modules/tf_aws_vpc/version.tf b/infrastructure/modules/tf_aws_vpc/version.tf
new file mode 100644 (file)
index 0000000..cc0789e
--- /dev/null
@@ -0,0 +1,4 @@
+terraform {
+  required_version = ">= 0.9.11"
+}
+
diff --git a/infrastructure/modules/vpcaccess-stack/main.tf b/infrastructure/modules/vpcaccess-stack/main.tf
new file mode 100644 (file)
index 0000000..30f4375
--- /dev/null
@@ -0,0 +1,94 @@
+resource "aws_eip" "vpn" {
+       count = 1
+       vpc = true
+}
+
+resource "aws_security_group" "vpn" {
+       vpc_id = "${var.vpc_id}"
+       name = "${var.name}-vpn"
+       description = "Allow VPN traffic."
+}
+
+resource "aws_security_group_rule" "vpn-out-all" {
+       security_group_id = "${aws_security_group.vpn.id}"
+       type = "egress"
+       from_port = 0
+       to_port = 0
+       protocol = "all"
+       cidr_blocks = ["0.0.0.0/0"]
+}
+
+resource "aws_security_group_rule" "vpn-in-user" {
+       security_group_id = "${aws_security_group.vpn.id}"
+       type = "ingress"
+       from_port = 1195
+       to_port = 1195
+       protocol = "tcp"
+       cidr_blocks = ["0.0.0.0/0"]
+}
+
+resource "aws_security_group_rule" "vpn-in-bridge" {
+       security_group_id = "${aws_security_group.vpn.id}"
+       type = "ingress"
+       from_port = 1194
+       to_port = 1194
+       protocol = "udp"
+       cidr_blocks = ["0.0.0.0/0"]
+}
+
+resource "aws_security_group_rule" "vpn-in-bastion" {
+       security_group_id = "${aws_security_group.vpn.id}"
+       type = "ingress"
+       from_port = 22
+       to_port = 22
+       protocol = "tcp"
+       cidr_blocks = ["0.0.0.0/0"]
+}
+
+resource "aws_elb" "default" {
+       count = "${var.vpcaccess_elb}"
+       name = "${var.name}-int-elb"
+       subnets = ["${var.subnet_ids}"]
+       internal = true
+       listener {
+               lb_port = 22
+               lb_protocol = "tcp"
+               instance_port = 22
+               instance_protocol = "tcp"
+       }
+       health_check {
+               healthy_threshold = 3
+               unhealthy_threshold = 2
+               interval = 30
+               timeout = 5
+               target = "TCP:1195"
+       }
+       idle_timeout = 600
+       tags {
+               module = "${var.name}"
+               phase = "${var.environment}"
+       }
+}
+
+module "asg-stack" {
+       source = "../modules/tf_aws_asg_stack"
+       vpc_id = "${var.vpc_id}"
+       acct_name = "${var.acct_name}"
+       notification_arns = ["${var.notification_arns}"]
+       module = "${var.name}"
+       phase = "${var.environment}"
+       instance_type = "${var.instance_type}"
+       key_name = "${var.key_name}"
+       public_ips = true
+       subnet_ids = ["${var.subnet_ids}"]
+       iam_policy_arns = ["${var.role_policy_arns}"]
+       security_group_ids = ["${concat(var.security_group_ids, list(aws_security_group.vpn.id))}"]
+       max_size = 1
+       min_size = 0
+       iam_allow_actions = [
+        "ec2:AssociateAddress",
+               "ec2:ModifyInstanceAttribute",
+               "ec2:ModifyNetworkInterfaceAttribute"
+       ]
+       elbs = ["${var.vpcaccess_elb ? aws_elb.default.id : ""}"]
+}
diff --git a/infrastructure/modules/vpcaccess-stack/outputs.tf b/infrastructure/modules/vpcaccess-stack/outputs.tf
new file mode 100644 (file)
index 0000000..5bd8ad7
--- /dev/null
@@ -0,0 +1,2 @@
+output "vpn_eip_id" { value = "${aws_eip.vpn.id}" }
+output "vpn_eip_ip" { value = "${aws_eip.vpn.public_ip}"}
diff --git a/infrastructure/modules/vpcaccess-stack/variables.tf b/infrastructure/modules/vpcaccess-stack/variables.tf
new file mode 100644 (file)
index 0000000..609ff9d
--- /dev/null
@@ -0,0 +1,11 @@
+variable "vpc_id" {}
+variable "name" { default = "vpcaccess" }
+variable "subnet_ids" { type="list" }
+variable "security_group_ids" { type="list" }
+variable "role_policy_arns" { type="list" }
+variable "key_name" {}
+variable "environment" {}
+variable "acct_name" {}
+variable "notification_arns" { type="list"}
+variable "instance_type" { default = "t2.small" }
+varaible "vpcaccess_elb" { default = false }
diff --git a/infrastructure/terraform-infrastructure/main.tf b/infrastructure/terraform-infrastructure/main.tf
new file mode 100644 (file)
index 0000000..903f99b
--- /dev/null
@@ -0,0 +1,10 @@
+provider "aws" {
+       region = "${var.region}"
+}
+
+module "terraform-infrastructure" {
+       source = "../modules/terraform-infrastructure"
+       region = "${var.region}"
+       remote_state_bucket = "${var.remote_state_bucket}"
+       remote_state_table = "${var.remote_state_table}"
+}
diff --git a/infrastructure/terraform-infrastructure/outputs.tf b/infrastructure/terraform-infrastructure/outputs.tf
new file mode 100644 (file)
index 0000000..95a89f0
--- /dev/null
@@ -0,0 +1,4 @@
+output "region" { value = "${var.region}" }
+output "remote_state_bucket" { value = "${var.remote_state_bucket}" }
+output "remote_state_table" { value = "${var.remote_state_table}" }
+output "environment" { value = "${var.environment}" }
diff --git a/infrastructure/terraform-infrastructure/terraform.tfvars b/infrastructure/terraform-infrastructure/terraform.tfvars
new file mode 120000 (symlink)
index 0000000..ac9c2a0
--- /dev/null
@@ -0,0 +1 @@
+../terraform.tfvars
\ No newline at end of file
diff --git a/infrastructure/terraform-infrastructure/variables.tf b/infrastructure/terraform-infrastructure/variables.tf
new file mode 100644 (file)
index 0000000..c6794b0
--- /dev/null
@@ -0,0 +1,4 @@
+variable "region" {}
+variable "remote_state_bucket" {}
+variable "remote_state_table" {}
+variable "environment" {}
diff --git a/infrastructure/terraform.tfvars b/infrastructure/terraform.tfvars
new file mode 100644 (file)
index 0000000..3ec9dbb
--- /dev/null
@@ -0,0 +1,10 @@
+region = "us-east-1"
+remote_state_bucket = "test-terraform-state"
+remote_state_table = "terraform-state"
+acct_name = "testAcct"
+project = "test"
+environment = "dev"
+vpc_cidr = "10.83.0.0/16"
+vpc_public_azs = ["us-east-1e"]
+vpc_private_azs = ["us-east-1c"]
+key_name = "somekey"
diff --git a/infrastructure/vpc/main.tf b/infrastructure/vpc/main.tf
new file mode 100644 (file)
index 0000000..87a1b5c
--- /dev/null
@@ -0,0 +1,13 @@
+provider "aws" {
+       region = "${var.region}"
+}
+
+module "vpc" {
+       source = "../modules/tf_aws_vpc"
+       project = "${var.project}"
+       environment = "${var.environment}"
+       cidr = "${var.vpc_cidr}"
+       public_azs = "${var.vpc_public_azs}"
+       private_azs = "${var.vpc_private_azs}"
+       ssh_allowed_cidr = "${var.ssh_allowed_cidr}"
+}
diff --git a/infrastructure/vpc/outputs.tf b/infrastructure/vpc/outputs.tf
new file mode 100644 (file)
index 0000000..4f98b3c
--- /dev/null
@@ -0,0 +1,23 @@
+output "vpc_id" {
+       value = "${module.vpc.vpc_id}"
+}
+
+output "public_subnets" {
+       value = "${module.vpc.public_subnets}"
+}
+
+output "private_subnets" {
+       value = "${module.vpc.private_subnets}"
+}
+
+output "nat_gateway_ips" {
+       value = "${module.vpc.nat_gateway_ips}"
+}
+
+output "base_policy_arn" {
+  value = "${module.vpc.base_policy_arn}"
+}
+
+output "general_access_sg_id" {
+  value = "${module.vpc.general_access_sg_id}"
+}
diff --git a/infrastructure/vpc/terraform.tfvars b/infrastructure/vpc/terraform.tfvars
new file mode 120000 (symlink)
index 0000000..ac9c2a0
--- /dev/null
@@ -0,0 +1 @@
+../terraform.tfvars
\ No newline at end of file
diff --git a/infrastructure/vpc/variables.tf b/infrastructure/vpc/variables.tf
new file mode 100644 (file)
index 0000000..f8d5281
--- /dev/null
@@ -0,0 +1,7 @@
+variable "region" {}
+variable "project" {}
+variable "environment" {}
+variable "vpc_cidr" {}
+variable "vpc_public_azs" {type="list"}
+variable "vpc_private_azs" {type="list"}
+variable "ssh_allowed_cidr" {type="list", default=[], description="List of extra cidrs to allow SSH traffic from"}
diff --git a/infrastructure/vpcaccess-stack/data_management-stack.tf b/infrastructure/vpcaccess-stack/data_management-stack.tf
new file mode 100644 (file)
index 0000000..9e75357
--- /dev/null
@@ -0,0 +1,9 @@
+data "terraform_remote_state" "management" {
+       backend = "s3"
+       config {
+               bucket = "${var.remote_state_bucket}"
+               region = "${var.region}"
+               key = "${var.environment}/management-stack.tfstate"
+               dynamodb_table = "${var.remote_state_table}"
+       }
+}
diff --git a/infrastructure/vpcaccess-stack/data_vpc.tf b/infrastructure/vpcaccess-stack/data_vpc.tf
new file mode 100644 (file)
index 0000000..12f8be7
--- /dev/null
@@ -0,0 +1,9 @@
+data "terraform_remote_state" "vpc" {
+       backend = "s3"
+       config {
+               bucket = "${var.remote_state_bucket}"
+               region = "${var.region}"
+               key = "${var.environment}/vpc.tfstate"
+               dynamodb_table = "${var.remote_state_table}"
+       }
+}
diff --git a/infrastructure/vpcaccess-stack/main.tf b/infrastructure/vpcaccess-stack/main.tf
new file mode 100644 (file)
index 0000000..df66995
--- /dev/null
@@ -0,0 +1,15 @@
+provider "aws" {
+       region = "${var.region}"
+}
+
+module "vpcaccess-stack" {
+       source = "../modules/vpcaccess-stack"
+       vpc_id = "${data.terraform_remote_state.vpc.vpc_id}"
+       subnet_ids = "${data.terraform_remote_state.vpc.public_subnets}"
+       security_group_ids = ["${data.terraform_remote_state.vpc.general_access_sg_id}"]
+       role_policy_arns = ["${data.terraform_remote_state.vpc.role_policy_arn}"]
+       key_name = "${var.key_name}"
+       environment = "${var.environment}"
+       acct_name = "${var.acct_name}"
+       notification_arns = ["${data.terraform_remote_state.management.events_topic_arn}"]
+}
diff --git a/infrastructure/vpcaccess-stack/outputs.tf b/infrastructure/vpcaccess-stack/outputs.tf
new file mode 100644 (file)
index 0000000..e94880f
--- /dev/null
@@ -0,0 +1 @@
+output "vpn_eip_ip" { value = "${module.vpcaccess-stack.vpn_eip_ip}"}
diff --git a/infrastructure/vpcaccess-stack/variables.tf b/infrastructure/vpcaccess-stack/variables.tf
new file mode 100644 (file)
index 0000000..851f8fe
--- /dev/null
@@ -0,0 +1,6 @@
+variable "region" {}
+variable "environment" {}
+variable "remote_state_bucket" {}
+variable "remote_state_table" {}
+variable "acct_name" {}
+variable "key_name" {}