From b1a81f904a76f8ffa00d50f12063d7841cb189f7 Mon Sep 17 00:00:00 2001 From: Thomas Obenaus Date: Mon, 21 Oct 2019 23:06:24 +0200 Subject: [PATCH] Upgrade code to be terraform 0.12 compatible (#71) * .Fix fixed outdated certificate * .Fix fixed missing ami problem * .Update use available ami for example * .Update switch to last pre terraform 12 consul module tag * .Update switch to consul 0.7.0 module * .Update upgrade consul example to tf 12 * .Update upgraded consul module to tf 12 * .Update upgrade bastion module to tf 12 * .Update upgrade networking to tf 12 * .Update upgrade nomad module to tf 12 * .Update removed unused consul_cluster_security_group_id * .Update added needed security groups to enable nomad to register at consul * .Update upgrade nomad-datacenter module to tf 12 * .Update upgrade ui-access module to tf 12 * .Update added changelog * .Update upgrade root-module to tf 12 * .Update changelog * .Fix used available variable instead of removed local * .Fix used available variable instead of removed local --- CHANGELOG.md | 20 ++ examples/bastion/main.tf | 18 +- examples/bastion/outputs.tf | 2 +- examples/bastion/versions.tf | 4 + examples/consul/main.tf | 18 +- examples/consul/outputs.tf | 8 +- examples/consul/versions.tf | 4 + examples/networking/main.tf | 6 +- examples/networking/versions.tf | 4 + examples/nomad-datacenter/main.tf | 33 ++- examples/nomad-datacenter/vars.tf | 2 +- examples/nomad-datacenter/versions.tf | 4 + examples/nomad/main.tf | 44 +-- examples/nomad/outputs.tf | 9 +- examples/nomad/sg_consul_nomad.tf | 26 ++ examples/nomad/sg_nomad_consul.tf | 18 ++ examples/nomad/vars.tf | 2 +- examples/nomad/versions.tf | 4 + examples/root-example/README.md | 48 +++- examples/root-example/create_ami_output.png | Bin 0 -> 58118 bytes examples/root-example/main.tf | 92 +++--- examples/root-example/outputs.tf | 57 ++-- examples/root-example/ref_ami.png | Bin 0 -> 25751 bytes examples/root-example/vars.tf | 24 +- examples/root-example/versions.tf | 4 + examples/ui-access/main.tf | 46 +-- examples/ui-access/outputs.tf | 6 +- examples/ui-access/versions.tf | 4 + main.tf | 270 +++++++++--------- modules/bastion/main.tf | 47 +-- modules/bastion/outputs.tf | 4 +- modules/bastion/vars.tf | 2 +- modules/bastion/versions.tf | 4 + modules/consul/main.tf | 36 +-- modules/consul/outputs.tf | 8 +- modules/consul/sg.tf | 2 +- modules/consul/versions.tf | 4 + modules/networking/backoffice_alb.tf | 14 +- modules/networking/backoffice_alb_sg.tf | 9 +- modules/networking/outputs.tf | 21 +- modules/networking/public_services_alb.tf | 21 +- modules/networking/public_services_alb_sg.tf | 11 +- modules/networking/subn_backoffice.tf | 31 +- modules/networking/subn_contentconnector.tf | 33 +-- modules/networking/subn_egress_aws.tf | 65 +++-- modules/networking/subn_egress_public.tf | 39 +-- modules/networking/subn_public.tf | 31 +- modules/networking/subn_services.tf | 31 +- modules/networking/vars.tf | 26 +- modules/networking/versions.tf | 4 + modules/networking/vpc.tf | 15 +- modules/nomad-datacenter/access_full.tf | 7 +- .../alb_ingress_attachment.tf | 21 +- modules/nomad-datacenter/datacenter.tf | 96 ++++--- modules/nomad-datacenter/datacenter_sg.tf | 7 +- modules/nomad-datacenter/ecr.tf | 7 +- modules/nomad-datacenter/main.tf | 9 +- modules/nomad-datacenter/outputs.tf | 15 +- modules/nomad-datacenter/vars.tf | 18 +- modules/nomad-datacenter/versions.tf | 4 + modules/nomad/main.tf | 10 +- modules/nomad/outputs.tf | 19 +- modules/nomad/server_sg.tf | 15 +- modules/nomad/servers.tf | 60 ++-- modules/nomad/vars.tf | 10 +- modules/nomad/versions.tf | 4 + modules/sgrules/sg_consul_nomad_clients.tf | 82 +++--- modules/sgrules/sg_consul_nomad_server.tf | 21 +- modules/sgrules/sg_consul_ui_alb.tf | 5 +- modules/sgrules/sg_nomad_clients.tf | 67 ++--- modules/sgrules/sg_nomad_clients_consul.tf | 33 +-- modules/sgrules/sg_nomad_clients_docker.tf | 17 +- modules/sgrules/sg_nomad_clients_igress.tf | 11 +- .../sgrules/sg_nomad_clients_server_access.tf | 33 +-- .../sgrules/sg_nomad_server_clients_access.tf | 33 +-- modules/sgrules/sg_nomad_server_consul.tf | 9 +- modules/sgrules/sg_nomad_server_ui_alb.tf | 5 +- modules/sgrules/versions.tf | 4 + modules/ui-access/consul_ui_alb.tf | 39 +-- modules/ui-access/fabio_ui_alb.tf | 39 +-- modules/ui-access/main.tf | 6 +- modules/ui-access/nomad_ui_alb.tf | 39 +-- modules/ui-access/outputs.tf | 31 +- modules/ui-access/ui_alb_sg.tf | 31 +- modules/ui-access/vars.tf | 5 +- modules/ui-access/versions.tf | 4 + outputs.tf | 59 ++-- vars.tf | 79 +++-- versions.tf | 4 + 89 files changed, 1241 insertions(+), 952 deletions(-) create mode 100644 CHANGELOG.md create mode 100644 examples/bastion/versions.tf create mode 100644 examples/consul/versions.tf create mode 100644 examples/networking/versions.tf create mode 100644 examples/nomad-datacenter/versions.tf create mode 100644 examples/nomad/sg_consul_nomad.tf create mode 100644 examples/nomad/sg_nomad_consul.tf create mode 100644 examples/nomad/versions.tf create mode 100644 examples/root-example/create_ami_output.png create mode 100644 examples/root-example/ref_ami.png create mode 100644 examples/root-example/versions.tf create mode 100644 examples/ui-access/versions.tf create mode 100644 modules/bastion/versions.tf create mode 100644 modules/consul/versions.tf create mode 100644 modules/networking/versions.tf create mode 100644 modules/nomad-datacenter/versions.tf create mode 100644 modules/nomad/versions.tf create mode 100644 modules/sgrules/versions.tf create mode 100644 modules/ui-access/versions.tf create mode 100644 versions.tf diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..9c8b64c --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,20 @@ +# Changelog + +## v0.2.0 (2019-??-??) + +- **major (incompatible)**, Refactor: With [#70](https://github.com/MatthiasScholz/cos/issues/70) the cos module was upgraded to be compatible to terraform 0.12.0. + - Furthermore the depending modules where upgraded as well: + - terraform-aws-consul from [v0.3.1](https://github.com/hashicorp/terraform-aws-consul/tree/v0.3.1) to [v0.7.0](https://github.com/hashicorp/terraform-aws-consul/tree/v0.7.0) + - terraform-aws-nomad from [v0.4.5](https://github.com/hashicorp/terraform-aws-nomad/tree/v0.4.5) to [v0.5.0](https://github.com/hashicorp/terraform-aws-nomad/tree/v0.5.0) +- License: With [9156e49](https://github.com/MatthiasScholz/cos/commit/9156e49f0eabbfc50100aeb778e6a776ba376b96) the license model was changed from GPL to LGPL, a more relaxed one. +- Test: With PR [#68](https://github.com/MatthiasScholz/cos/pull/68) tests (terratest) where added to ensure functionality of the COS. + +## v0.1.1 (2019-07-20) + +## v0.1.0 (2019-06-14) + +## v0.0.3 (2019-01-01) + +## v0.0.2 (2018-12-13) + +## v0.0.1 (2018-04-30) diff --git a/examples/bastion/main.tf b/examples/bastion/main.tf index b3ea528..c2491b6 100644 --- a/examples/bastion/main.tf +++ b/examples/bastion/main.tf @@ -6,8 +6,8 @@ locals { } provider "aws" { - profile = "${var.deploy_profile}" - region = "${local.aws_region}" + profile = var.deploy_profile + region = local.aws_region } resource "random_pet" "unicorn" { @@ -21,22 +21,22 @@ data "aws_vpc" "default" { } data "aws_subnet_ids" "all" { - vpc_id = "${data.aws_vpc.default.id}" + vpc_id = data.aws_vpc.default.id } module "bastion" { source = "../../modules/bastion" ## required parameters - vpc_id = "${data.aws_vpc.default.id}" - subnet_id = "${element(data.aws_subnet_ids.all.ids,0)}" - ami_id = "${local.ami_id}" + vpc_id = data.aws_vpc.default.id + subnet_id = element(tolist(data.aws_subnet_ids.all.ids), 0) + ami_id = local.ami_id ssh_key_name = "${var.ssh_key_name}" ## optional parameters - aws_region = "${local.aws_region}" - env_name = "${local.env_name}" - stack_name = "${local.stack_name}" + aws_region = local.aws_region + env_name = local.env_name + stack_name = local.stack_name allowed_ssh_cidr_blocks = { "all" = "0.0.0.0/0" diff --git a/examples/bastion/outputs.tf b/examples/bastion/outputs.tf index 46c2017..5d42a88 100644 --- a/examples/bastion/outputs.tf +++ b/examples/bastion/outputs.tf @@ -1,5 +1,5 @@ output "bastion_ip" { - value = "${module.bastion.bastion_ip}" + value = module.bastion.bastion_ip } output "ssh_login" { diff --git a/examples/bastion/versions.tf b/examples/bastion/versions.tf new file mode 100644 index 0000000..ac97c6a --- /dev/null +++ b/examples/bastion/versions.tf @@ -0,0 +1,4 @@ + +terraform { + required_version = ">= 0.12" +} diff --git a/examples/consul/main.tf b/examples/consul/main.tf index b4bc89c..d015ea2 100644 --- a/examples/consul/main.tf +++ b/examples/consul/main.tf @@ -4,8 +4,8 @@ locals { } provider "aws" { - profile = "${var.deploy_profile}" - region = "${var.aws_region}" + profile = var.deploy_profile + region = var.aws_region } ### obtaining default vpc, security group and subnet of the env @@ -14,21 +14,21 @@ data "aws_vpc" "default" { } data "aws_subnet_ids" "all" { - vpc_id = "${data.aws_vpc.default.id}" + vpc_id = data.aws_vpc.default.id } module "consul" { source = "../../modules/consul" ## required parameters - vpc_id = "${data.aws_vpc.default.id}" - subnet_ids = "${data.aws_subnet_ids.all.ids}" - ami_id = "${var.ami_id}" + vpc_id = data.aws_vpc.default.id + subnet_ids = data.aws_subnet_ids.all.ids + ami_id = var.ami_id ## optional parameters - aws_region = "${var.aws_region}" - env_name = "${local.env_name}" - stack_name = "${local.stack_name}" + aws_region = var.aws_region + env_name = local.env_name + stack_name = local.stack_name cluster_tag_key = "consul-servers" cluster_tag_value = "${local.stack_name}-${local.env_name}-consul-srv" allowed_ssh_cidr_blocks = ["0.0.0.0/0"] diff --git a/examples/consul/outputs.tf b/examples/consul/outputs.tf index 05a1e49..23f704d 100644 --- a/examples/consul/outputs.tf +++ b/examples/consul/outputs.tf @@ -1,15 +1,15 @@ output "asg_name_consul_servers" { - value = "${module.consul.asg_name_consul_servers}" + value = module.consul.asg_name_consul_servers } output "security_group_id_consul_servers" { - value = "${module.consul.security_group_id_consul_servers}" + value = module.consul.security_group_id_consul_servers } output "consul_servers_cluster_tag_key" { - value = "${module.consul.consul_servers_cluster_tag_key}" + value = module.consul.consul_servers_cluster_tag_key } output "consul_servers_cluster_tag_value" { - value = "${module.consul.consul_servers_cluster_tag_value}" + value = module.consul.consul_servers_cluster_tag_value } diff --git a/examples/consul/versions.tf b/examples/consul/versions.tf new file mode 100644 index 0000000..ac97c6a --- /dev/null +++ b/examples/consul/versions.tf @@ -0,0 +1,4 @@ + +terraform { + required_version = ">= 0.12" +} diff --git a/examples/networking/main.tf b/examples/networking/main.tf index 77cd204..edf2f4a 100644 --- a/examples/networking/main.tf +++ b/examples/networking/main.tf @@ -1,9 +1,9 @@ provider "aws" { - profile = "${var.deploy_profile}" - region = "${var.aws_region}" + profile = var.deploy_profile + region = var.aws_region } module "networking" { source = "../../modules/networking" - region = "${var.aws_region}" + region = var.aws_region } diff --git a/examples/networking/versions.tf b/examples/networking/versions.tf new file mode 100644 index 0000000..ac97c6a --- /dev/null +++ b/examples/networking/versions.tf @@ -0,0 +1,4 @@ + +terraform { + required_version = ">= 0.12" +} diff --git a/examples/nomad-datacenter/main.tf b/examples/nomad-datacenter/main.tf index d9d10e8..c30e58e 100644 --- a/examples/nomad-datacenter/main.tf +++ b/examples/nomad-datacenter/main.tf @@ -4,8 +4,8 @@ locals { } provider "aws" { - profile = "${var.deploy_profile}" - region = "${var.aws_region}" + profile = var.deploy_profile + region = var.aws_region } resource "random_pet" "unicorn" { @@ -19,11 +19,11 @@ data "aws_vpc" "default" { } data "aws_subnet_ids" "all" { - vpc_id = "${data.aws_vpc.default.id}" + vpc_id = data.aws_vpc.default.id } resource "aws_security_group" "sg_nomad_server" { - vpc_id = "${data.aws_vpc.default.id}" + vpc_id = data.aws_vpc.default.id name_prefix = "sg_nomad_server" description = "Sample nomad server sg." } @@ -32,17 +32,17 @@ module "nomad-datacenter" { source = "../../modules/nomad-datacenter" ## required parameters - vpc_id = "${data.aws_vpc.default.id}" - subnet_ids = "${data.aws_subnet_ids.all.ids}" - ami_id = "${var.ami_id}" + vpc_id = data.aws_vpc.default.id + subnet_ids = data.aws_subnet_ids.all.ids + ami_id = var.ami_id consul_cluster_tag_key = "consul-servers" consul_cluster_tag_value = "${local.stack_name}-${local.env_name}-consul-srv" - server_sg_id = "${aws_security_group.sg_nomad_server.id}" + server_sg_id = aws_security_group.sg_nomad_server.id ## optional parameters - aws_region = "${var.aws_region}" - env_name = "${local.env_name}" - stack_name = "${local.stack_name}" + aws_region = var.aws_region + env_name = local.env_name + stack_name = local.stack_name allowed_ssh_cidr_blocks = ["0.0.0.0/0"] ssh_key_name = "${var.ssh_key_name}" datacenter_name = "public-services" @@ -64,8 +64,11 @@ module "nomad-datacenter" { "desired_capacity" = 1 } - ebs_block_devices = [{ - "device_name" = "/dev/xvdf" - "volume_size" = "50" - }] + ebs_block_devices = [ + { + "device_name" = "/dev/xvdf" + "volume_size" = "50" + }, + ] } + diff --git a/examples/nomad-datacenter/vars.tf b/examples/nomad-datacenter/vars.tf index 838785c..4f39c5b 100644 --- a/examples/nomad-datacenter/vars.tf +++ b/examples/nomad-datacenter/vars.tf @@ -4,7 +4,7 @@ variable "deploy_profile" { variable "ami_id" { description = "Id of the AMI for the nomad and consul nodes." - default = "ami-a23feadf" + default = "ami-09118e4b58586b75d" } variable "aws_region" { diff --git a/examples/nomad-datacenter/versions.tf b/examples/nomad-datacenter/versions.tf new file mode 100644 index 0000000..ac97c6a --- /dev/null +++ b/examples/nomad-datacenter/versions.tf @@ -0,0 +1,4 @@ + +terraform { + required_version = ">= 0.12" +} diff --git a/examples/nomad/main.tf b/examples/nomad/main.tf index bc6e4f2..2cca5d3 100644 --- a/examples/nomad/main.tf +++ b/examples/nomad/main.tf @@ -1,15 +1,15 @@ locals { stack_name = "COS" env_name = "playground" - consul_ami_id = "${var.ami_id}" - nomad_ami_id = "${var.ami_id}" + consul_ami_id = var.ami_id + nomad_ami_id = var.ami_id consul_cluster_tag_key = "consul-servers" consul_cluster_tag_value = "${local.stack_name}-SDCFG-consul-${random_pet.unicorn.id}" } provider "aws" { - profile = "${var.deploy_profile}" - region = "${var.aws_region}" + profile = var.deploy_profile + region = var.aws_region } resource "random_pet" "unicorn" { @@ -23,23 +23,23 @@ data "aws_vpc" "default" { } data "aws_subnet_ids" "all" { - vpc_id = "${data.aws_vpc.default.id}" + vpc_id = data.aws_vpc.default.id } module "consul" { source = "../../modules/consul" ## required parameters - vpc_id = "${data.aws_vpc.default.id}" - subnet_ids = "${data.aws_subnet_ids.all.ids}" - ami_id = "${local.consul_ami_id}" + vpc_id = data.aws_vpc.default.id + subnet_ids = data.aws_subnet_ids.all.ids + ami_id = local.consul_ami_id ## optional parameters - aws_region = "${var.aws_region}" - env_name = "${local.env_name}" - stack_name = "${local.stack_name}" - cluster_tag_key = "${local.consul_cluster_tag_key}" - cluster_tag_value = "${local.consul_cluster_tag_value}" + aws_region = var.aws_region + env_name = local.env_name + stack_name = local.stack_name + cluster_tag_key = local.consul_cluster_tag_key + cluster_tag_value = local.consul_cluster_tag_value allowed_ssh_cidr_blocks = ["0.0.0.0/0"] ssh_key_name = "${var.ssh_key_name}" } @@ -48,17 +48,16 @@ module "nomad" { source = "../../modules/nomad" ## required parameters - vpc_id = "${data.aws_vpc.default.id}" - subnet_ids = "${data.aws_subnet_ids.all.ids}" - ami_id = "${local.nomad_ami_id}" - consul_cluster_tag_key = "${local.consul_cluster_tag_key}" - consul_cluster_tag_value = "${local.consul_cluster_tag_value}" - consul_cluster_security_group_id = "${module.consul.security_group_id_consul_servers}" + vpc_id = data.aws_vpc.default.id + subnet_ids = data.aws_subnet_ids.all.ids + ami_id = local.nomad_ami_id + consul_cluster_tag_key = local.consul_cluster_tag_key + consul_cluster_tag_value = local.consul_cluster_tag_value ## optional parameters - aws_region = "${var.aws_region}" - env_name = "${local.env_name}" - stack_name = "${local.stack_name}" + aws_region = var.aws_region + env_name = local.env_name + stack_name = local.stack_name allowed_ssh_cidr_blocks = ["0.0.0.0/0"] ssh_key_name = "${var.ssh_key_name}" instance_type = "t2.micro" @@ -71,3 +70,4 @@ module "nomad" { "desired_capacity" = 3 } } + diff --git a/examples/nomad/outputs.tf b/examples/nomad/outputs.tf index e392fbe..a7a7e48 100644 --- a/examples/nomad/outputs.tf +++ b/examples/nomad/outputs.tf @@ -1,15 +1,16 @@ output "aws_region" { - value = "${var.aws_region}" + value = var.aws_region } output "nomad_servers_cluster_tag_key" { - value = "${module.nomad.nomad_servers_cluster_tag_key}" + value = module.nomad.nomad_servers_cluster_tag_key } output "nomad_servers_cluster_tag_value" { - value = "${module.nomad.nomad_servers_cluster_tag_value}" + value = module.nomad.nomad_servers_cluster_tag_value } output "num_nomad_servers" { - value = "${module.nomad.num_nomad_servers}" + value = module.nomad.num_nomad_servers } + diff --git a/examples/nomad/sg_consul_nomad.tf b/examples/nomad/sg_consul_nomad.tf new file mode 100644 index 0000000..9f396ce --- /dev/null +++ b/examples/nomad/sg_consul_nomad.tf @@ -0,0 +1,26 @@ +locals { + # The rule_map contains the spec for the security group rules that should be applied. + # An entry is of the form "" = ["",,] + rule_map = { + "Grants access from nomad (rcp, serf: lan, wan - tcp)" = ["tcp",8300,8302], + "Grants access from nomad (rcp, serf: lan, wan - udp)" = ["udp",8301,8302], + "Grants access from nomad (http)" = ["tcp",8500,8500], + "Grants access from nomad (dns tcp)" = ["tcp",8600,8600], + "Grants access from nomad (dns udp)" = ["udp",8600,8600], + } +} + +# rule granting access from nomad to consul on ports defined in rule_map +# [nomad>consul] +resource "aws_security_group_rule" "sgr_nomad_to_consul" { + + for_each = local.rule_map + + type = "ingress" + description = each.key + protocol = element(each.value,0) + from_port = element(each.value,1) + to_port = element(each.value,2) + source_security_group_id = module.nomad.security_group_id_nomad_servers + security_group_id = module.consul.security_group_id_consul_servers +} \ No newline at end of file diff --git a/examples/nomad/sg_nomad_consul.tf b/examples/nomad/sg_nomad_consul.tf new file mode 100644 index 0000000..1cb951f --- /dev/null +++ b/examples/nomad/sg_nomad_consul.tf @@ -0,0 +1,18 @@ +locals { + protocols = ["tcp","udp"] +} + +# rule granting access from consul to nomad server on ports +# 8300...8302 tcp and udp +# [consul>nomad] RCP, Serf LAN and WAN, TCP + UDP +resource "aws_security_group_rule" "sgr_consul_to_nomad_server" { + count = length(local.protocols) + + type = "ingress" + description = "Grants access from consul server (rcp, serf: lan, wan - ${element(local.protocols,count.index)})" + from_port = 8300 + to_port = 8302 + protocol = element(local.protocols,count.index) + source_security_group_id = module.consul.security_group_id_consul_servers + security_group_id = module.nomad.security_group_id_nomad_servers +} \ No newline at end of file diff --git a/examples/nomad/vars.tf b/examples/nomad/vars.tf index 23f1cb7..f6f4a02 100644 --- a/examples/nomad/vars.tf +++ b/examples/nomad/vars.tf @@ -4,7 +4,7 @@ variable "deploy_profile" { variable "ami_id" { description = "Id of the AMI for the nomad and consul nodes." - default = "ami-a23feadf" + default = "ami-09118e4b58586b75d" } variable "ssh_key_name" { diff --git a/examples/nomad/versions.tf b/examples/nomad/versions.tf new file mode 100644 index 0000000..ac97c6a --- /dev/null +++ b/examples/nomad/versions.tf @@ -0,0 +1,4 @@ + +terraform { + required_version = ">= 0.12" +} diff --git a/examples/root-example/README.md b/examples/root-example/README.md index 0a33be7..c9cbf89 100644 --- a/examples/root-example/README.md +++ b/examples/root-example/README.md @@ -24,7 +24,6 @@ source ./bootstrap.sh Or you follow the preceding instructions. - ## Setup helper scripts ```bash @@ -139,7 +138,52 @@ sshuttle_login.sh ### Datacenter Configuration -* [ ** TODO: Describe to configuration of the different nomad datacenters. +- [ ] TODO: Describe to configuration of the different nomad datacenters. + +## Troubleshooting + +### No images found for AMI + +If you see the following error, then you don't have the AMI which is referenced available in your account. + +```bash +module.nomad-infra.module.dc-backoffice.module.data_center.aws_launch_configuration.launch_configuration: 1 error occurred: +aws_launch_configuration.launch_configuration: No images found for AMI ami-02d24827dece83bef +``` + +To solve this issue you have to build it and to reference the newly built AMI in the example. + +#### Build the AMI + +How to do this see paragraph `Build the AMI using Packer` in [modules/ami2/README.md](../../modules/ami2/README.md). + +![output of ami creation](create_ami_output.png) + +#### Reference the AMI in root-example + +Open the file `vars.tf` and there replace the value of the field `default` for variables `nomad_ami_id_clients` and `nomad_ami_id_servers` with the id of the ami that was just created with packer. + +![reference the ami](ref_ami.png) + +### MalformedCertificate: Certificate is no longer valid + +If the used certificate is not valid any more you will receive the following (or similar) error. + +```bash +aws_iam_server_certificate.certificate_alb: 1 error occurred: +aws_iam_server_certificate.certificate_alb: Error uploading server certificate, error: MalformedCertificate: Certificate is no longer valid. The 'Not After' date restriction on the certificate has passed. +``` + +To solve this issue a new certificate has to be created. + +#### Create the self signed Certificate + +```bash +openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 -nodes +``` + +Then copy the content of `cert.pem` into the field `certificate_body` of the file `alb_cert.tf`. +And copy the content of `key.pem` into the field `private_key` of the file `alb_cert.tf`. ## Remarks diff --git a/examples/root-example/create_ami_output.png b/examples/root-example/create_ami_output.png new file mode 100644 index 0000000000000000000000000000000000000000..b084d2f90992f22eb3872036aae34015c6b732a6 GIT binary patch literal 58118 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 literal 0 HcmV?d00001 diff --git a/examples/root-example/main.tf b/examples/root-example/main.tf index accaa4c..2e14509 100644 --- a/examples/root-example/main.tf +++ b/examples/root-example/main.tf @@ -9,8 +9,8 @@ locals { } provider "aws" { - profile = "${var.deploy_profile}" - region = "${var.aws_region}" + profile = var.deploy_profile + region = var.aws_region } resource "random_pet" "unicorn" { @@ -20,8 +20,8 @@ resource "random_pet" "unicorn" { module "networking" { source = "../../modules/networking" - region = "${var.aws_region}" - env_name = "${var.env_name}" + region = var.aws_region + env_name = var.env_name unique_postfix = "-${random_pet.unicorn.id}" az_postfixes = ["a", "b"] } @@ -30,16 +30,16 @@ module "bastion" { source = "../../modules/bastion" ## required parameters - vpc_id = "${module.networking.vpc_id}" - subnet_id = "${element(module.networking.public_subnet_ids,0)}" - ami_id = "${local.ami_id_bastion}" - ssh_key_name = "${var.ssh_key_name}" + vpc_id = module.networking.vpc_id + subnet_id = element(module.networking.public_subnet_ids, 0) + ami_id = local.ami_id_bastion + ssh_key_name = var.ssh_key_name ## optional parameters - aws_region = "${var.aws_region}" - env_name = "${var.env_name}" - stack_name = "${var.stack_name}" - allowed_ssh_cidr_blocks = "${local.allowed_cidr_blocks}" + aws_region = var.aws_region + env_name = var.env_name + stack_name = var.stack_name + allowed_ssh_cidr_blocks = local.allowed_cidr_blocks instance_type = "t2.micro" unique_postfix = "-${random_pet.unicorn.id}" } @@ -48,39 +48,39 @@ module "nomad-infra" { source = "../../" # [General] Required variables - aws_region = "${var.aws_region}" - vpc_id = "${module.networking.vpc_id}" - alb_subnet_ids = "${module.networking.public_subnet_ids}" + aws_region = var.aws_region + vpc_id = module.networking.vpc_id + alb_subnet_ids = module.networking.public_subnet_ids # HACK: Use an http listener here to avoid the need to create a certificate. # In a production environmant you should pass in a https listener instead. - alb_ingress_https_listener_arn = "${module.networking.alb_ingress_http_listener_arn}" + alb_ingress_https_listener_arn = module.networking.alb_ingress_http_listener_arn - alb_backoffice_https_listener_arn = "${module.networking.alb_backoffice_https_listener_arn}" + alb_backoffice_https_listener_arn = module.networking.alb_backoffice_https_listener_arn attach_backoffice_alb_listener = true # [Nomad] Required variables nomad_ami_id_servers = "${var.ami_id}" nomad_ami_id_clients = "${var.ami_id}" - nomad_server_subnet_ids = "${module.networking.backoffice_subnet_ids}" - nomad_clients_public_services_subnet_ids = "${module.networking.services_subnet_ids}" - nomad_clients_private_services_subnet_ids = "${module.networking.services_subnet_ids}" - nomad_clients_content_connector_subnet_ids = "${module.networking.content_connector_subnet_ids}" - nomad_clients_backoffice_subnet_ids = "${module.networking.backoffice_subnet_ids}" + nomad_server_subnet_ids = module.networking.backoffice_subnet_ids + nomad_clients_public_services_subnet_ids = module.networking.services_subnet_ids + nomad_clients_private_services_subnet_ids = module.networking.services_subnet_ids + nomad_clients_content_connector_subnet_ids = module.networking.content_connector_subnet_ids + nomad_clients_backoffice_subnet_ids = module.networking.backoffice_subnet_ids # [Consul] Required variables + consul_server_subnet_ids = module.networking.backoffice_subnet_ids consul_ami_id = "${var.ami_id}" - consul_server_subnet_ids = "${module.networking.backoffice_subnet_ids}" # [General] Optional variables - stack_name = "${var.stack_name}" - env_name = "${var.env_name}" + stack_name = var.stack_name + env_name = var.env_name unique_postfix = "-${random_pet.unicorn.id}" instance_type_server = "t2.micro" - ssh_key_name = "${var.ssh_key_name}" - allowed_ssh_cidr_blocks = ["${values(local.allowed_cidr_blocks)}"] + ssh_key_name = var.ssh_key_name + allowed_ssh_cidr_blocks = values(local.allowed_cidr_blocks) - allowed_cidr_blocks_for_ui_alb = "${local.allowed_cidr_blocks}" + allowed_cidr_blocks_for_ui_alb = local.allowed_cidr_blocks # INFO: uncomment the following two lines if you want to deploy the cluster having https endpoints # for the ui-albs (nomad-ui, consul-ui and fabio-ui). @@ -91,24 +91,26 @@ module "nomad-infra" { #ui_alb_use_https_listener = true # [Nomad] Optional variables - nomad_server_scaling_cfg = "${var.server_scaling_cfg}" - nomad_private_services_dc_node_cfg = "${var.nomad_dc_node_cfg}" - nomad_public_services_dc_node_cfg = "${var.nomad_dc_node_cfg}" - nomad_content_connector_dc_node_cfg = "${var.nomad_dc_node_cfg}" - nomad_backoffice_dc_node_cfg = "${var.nomad_dc_node_cfg}" - ebs_block_devices_private_services_dc = "${var.ebs_block_devices_sample}" - ebs_block_devices_public_services_dc = "${var.ebs_block_devices_sample}" - ebs_block_devices_backoffice_dc = "${var.ebs_block_devices_sample}" - ebs_block_devices_content_connector_dc = "${var.ebs_block_devices_sample}" - device_to_mount_target_map_public_services_dc = "${var.device_to_mount_target_map_sample}" - device_to_mount_target_map_private_services_dc = "${var.device_to_mount_target_map_sample}" - device_to_mount_target_map_backoffice_dc = "${var.device_to_mount_target_map_sample}" - device_to_mount_target_map_content_connector_dc = "${var.device_to_mount_target_map_sample}" - additional_instance_tags_public_services_dc = "${var.additional_instance_tags_sample}" - additional_instance_tags_private_services_dc = "${var.additional_instance_tags_sample}" - additional_instance_tags_backoffice_dc = "${var.additional_instance_tags_sample}" - additional_instance_tags_content_connector_dc = "${var.additional_instance_tags_sample}" + nomad_server_scaling_cfg = var.server_scaling_cfg + nomad_private_services_dc_node_cfg = var.nomad_dc_node_cfg + nomad_public_services_dc_node_cfg = var.nomad_dc_node_cfg + nomad_content_connector_dc_node_cfg = var.nomad_dc_node_cfg + nomad_backoffice_dc_node_cfg = var.nomad_dc_node_cfg + ebs_block_devices_private_services_dc = var.ebs_block_devices_sample + ebs_block_devices_public_services_dc = var.ebs_block_devices_sample + ebs_block_devices_backoffice_dc = var.ebs_block_devices_sample + ebs_block_devices_content_connector_dc = var.ebs_block_devices_sample + device_to_mount_target_map_public_services_dc = var.device_to_mount_target_map_sample + device_to_mount_target_map_private_services_dc = var.device_to_mount_target_map_sample + device_to_mount_target_map_backoffice_dc = var.device_to_mount_target_map_sample + device_to_mount_target_map_content_connector_dc = var.device_to_mount_target_map_sample + additional_instance_tags_public_services_dc = var.additional_instance_tags_sample + additional_instance_tags_private_services_dc = var.additional_instance_tags_sample + additional_instance_tags_backoffice_dc = var.additional_instance_tags_sample + additional_instance_tags_content_connector_dc = var.additional_instance_tags_sample + # [Consul] Optional variables consul_num_servers = 3 consul_instance_type = "t2.micro" } + diff --git a/examples/root-example/outputs.tf b/examples/root-example/outputs.tf index 09539f2..a89fd0d 100644 --- a/examples/root-example/outputs.tf +++ b/examples/root-example/outputs.tf @@ -1,25 +1,25 @@ output "aws_region" { - value = "${var.aws_region}" + value = var.aws_region } output "nomad_servers_cluster_tag_key" { - value = "${module.nomad-infra.nomad_servers_cluster_tag_key}" + value = module.nomad-infra.nomad_servers_cluster_tag_key } output "nomad_servers_cluster_tag_value" { - value = "${module.nomad-infra.nomad_servers_cluster_tag_value}" + value = module.nomad-infra.nomad_servers_cluster_tag_value } output "num_nomad_servers" { - value = "${module.nomad-infra.num_nomad_servers}" + value = module.nomad-infra.num_nomad_servers } output "nomad_clients_public_services_cluster_tag_value" { - value = "${module.nomad-infra.nomad_clients_public_services_cluster_tag_value}" + value = module.nomad-infra.nomad_clients_public_services_cluster_tag_value } output "nomad_ui_alb_dns" { - value = "${module.nomad-infra.nomad_ui_alb_dns_name}" + value = module.nomad-infra.nomad_ui_alb_dns_name } output "curl_nomad_ui" { @@ -31,7 +31,7 @@ output "export_nomad_cmd" { } output "consul_ui_alb_dns" { - value = "${module.nomad-infra.consul_ui_alb_dns_name}" + value = module.nomad-infra.consul_ui_alb_dns_name } output "curl_consul_ui" { @@ -39,7 +39,7 @@ output "curl_consul_ui" { } output "fabio_ui_alb_dns" { - value = "${module.nomad-infra.fabio_ui_alb_dns_name}" + value = module.nomad-infra.fabio_ui_alb_dns_name } output "curl_fabio_ui" { @@ -51,11 +51,11 @@ output "curl_ping_service" { } output "ingress_alb_dns" { - value = "${module.networking.alb_public_services_dns}" + value = module.networking.alb_public_services_dns } output "bastion_ip" { - value = "${module.bastion.bastion_ip}" + value = module.bastion.bastion_ip } output "ssh_login" { @@ -63,73 +63,74 @@ output "ssh_login" { } output "ssh_key_name" { - value = "${module.nomad-infra.ssh_key_name}" + value = module.nomad-infra.ssh_key_name } output "vpc_id" { - value = "${module.nomad-infra.vpc_id}" + value = module.nomad-infra.vpc_id } output "vpc_cidr_block" { - value = "${module.networking.vpc_cidr_block}" + value = module.networking.vpc_cidr_block } output "cluster_prefix" { - value = "${module.nomad-infra.cluster_prefix}" + value = module.nomad-infra.cluster_prefix } output "consul_servers_cluster_tag_key" { - value = "${module.nomad-infra.consul_servers_cluster_tag_key}" + value = module.nomad-infra.consul_servers_cluster_tag_key } output "consul_servers_cluster_tag_value" { - value = "${module.nomad-infra.consul_servers_cluster_tag_value}" + value = module.nomad-infra.consul_servers_cluster_tag_value } output "nomad_ui_alb_dns_name" { - value = "${module.nomad-infra.nomad_ui_alb_dns_name}" + value = module.nomad-infra.nomad_ui_alb_dns_name } output "nomad_ui_alb_https_targetgroup_arn" { - value = "${module.nomad-infra.nomad_ui_alb_https_targetgroup_arn}" + value = module.nomad-infra.nomad_ui_alb_https_targetgroup_arn } output "nomad_ui_alb_https_listener_arn" { - value = "${module.nomad-infra.nomad_ui_alb_https_listener_arn}" + value = module.nomad-infra.nomad_ui_alb_https_listener_arn } output "consul_ui_alb_dns_name" { - value = "${module.nomad-infra.consul_ui_alb_dns_name}" + value = module.nomad-infra.consul_ui_alb_dns_name } output "consul_ui_alb_https_targetgroup_arn" { - value = "${module.nomad-infra.consul_ui_alb_https_targetgroup_arn}" + value = module.nomad-infra.consul_ui_alb_https_targetgroup_arn } output "consul_ui_alb_https_listener_arn" { - value = "${module.nomad-infra.consul_ui_alb_https_listener_arn}" + value = module.nomad-infra.consul_ui_alb_https_listener_arn } output "fabio_ui_alb_dns_name" { - value = "${module.nomad-infra.fabio_ui_alb_dns_name}" + value = module.nomad-infra.fabio_ui_alb_dns_name } output "fabio_ui_alb_https_targetgroup_arn" { - value = "${module.nomad-infra.fabio_ui_alb_https_targetgroup_arn}" + value = module.nomad-infra.fabio_ui_alb_https_targetgroup_arn } output "fabio_ui_alb_https_listener_arn" { - value = "${module.nomad-infra.fabio_ui_alb_https_listener_arn}" + value = module.nomad-infra.fabio_ui_alb_https_listener_arn } output "dc-public-services_alb_https_targetgroup_arn" { - value = "${module.nomad-infra.dc-public-services_alb_https_targetgroup_arn}" + value = module.nomad-infra.dc-public-services_alb_https_targetgroup_arn } output "dc-private-services_alb_https_targetgroup_arn" { - value = "${module.nomad-infra.dc-private-services_alb_https_targetgroup_arn}" + value = module.nomad-infra.dc-private-services_alb_https_targetgroup_arn } output "dc-backoffice_alb_https_targetgroup_arn" { - value = "${module.nomad-infra.dc-backoffice_alb_https_targetgroup_arn}" + value = module.nomad-infra.dc-backoffice_alb_https_targetgroup_arn } + diff --git a/examples/root-example/ref_ami.png b/examples/root-example/ref_ami.png new file mode 100644 index 0000000000000000000000000000000000000000..5cfd5fda31748e8721b7e285b59ebf2b778e029a GIT binary patch literal 25751 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 literal 0 HcmV?d00001 diff --git a/examples/root-example/vars.tf b/examples/root-example/vars.tf index c728806..d34d612 100644 --- a/examples/root-example/vars.tf +++ b/examples/root-example/vars.tf @@ -30,7 +30,7 @@ variable "stack_name" { variable "server_scaling_cfg" { description = "Number of nomad server" - type = "map" + type = map(string) default = { "min" = 3 @@ -41,7 +41,7 @@ variable "server_scaling_cfg" { variable "nomad_dc_node_cfg" { description = "Configuration for the private data-center nodes" - type = "map" + type = map(string) default = { "min" = 1 @@ -52,12 +52,13 @@ variable "nomad_dc_node_cfg" { } variable "ebs_block_devices_sample" { - type = "list" + type = any - default = [{ - "device_name" = "/dev/xvde" - "volume_size" = "50" - }, + default = [ + { + "device_name" = "/dev/xvde" + "volume_size" = "50" + }, { "device_name" = "/dev/xvdf" "volume_size" = "80" @@ -66,13 +67,17 @@ variable "ebs_block_devices_sample" { } variable "device_to_mount_target_map_sample" { - type = "list" + type = list(string) default = ["/dev/xvde:/mnt/map1", "/dev/xvdf:/mnt/map2"] } variable "additional_instance_tags_sample" { - type = "list" + type = list(object({ + key = string + value = string + propagate_at_launch = bool + })) default = [ { @@ -82,3 +87,4 @@ variable "additional_instance_tags_sample" { }, ] } + diff --git a/examples/root-example/versions.tf b/examples/root-example/versions.tf new file mode 100644 index 0000000..ac97c6a --- /dev/null +++ b/examples/root-example/versions.tf @@ -0,0 +1,4 @@ + +terraform { + required_version = ">= 0.12" +} diff --git a/examples/ui-access/main.tf b/examples/ui-access/main.tf index 9c91b38..d4c6392 100644 --- a/examples/ui-access/main.tf +++ b/examples/ui-access/main.tf @@ -4,8 +4,8 @@ locals { } provider "aws" { - profile = "${var.deploy_profile}" - region = "${var.aws_region}" + profile = var.deploy_profile + region = var.aws_region } ### obtaining default vpc, security group and subnet of the env @@ -14,12 +14,12 @@ data "aws_vpc" "default" { } data "aws_subnet_ids" "all" { - vpc_id = "${data.aws_vpc.default.id}" + vpc_id = data.aws_vpc.default.id } resource "aws_security_group" "sg_sample" { name_prefix = "sg_sample_" - vpc_id = "${data.aws_vpc.default.id}" + vpc_id = data.aws_vpc.default.id lifecycle { create_before_destroy = true @@ -33,7 +33,7 @@ resource "aws_security_group_rule" "allow_all_inbound" { protocol = "-1" cidr_blocks = ["0.0.0.0/0"] - security_group_id = "${aws_security_group.sg_sample.id}" + security_group_id = aws_security_group.sg_sample.id } resource "aws_security_group_rule" "allow_all_outbound" { @@ -43,25 +43,25 @@ resource "aws_security_group_rule" "allow_all_outbound" { protocol = "-1" cidr_blocks = ["0.0.0.0/0"] - security_group_id = "${aws_security_group.sg_sample.id}" + security_group_id = aws_security_group.sg_sample.id } resource "aws_autoscaling_group" "asg_sample" { - launch_configuration = "${aws_launch_configuration.lc_sample.name}" + launch_configuration = aws_launch_configuration.lc_sample.name name_prefix = "asg-sample-" - vpc_zone_identifier = ["${data.aws_subnet_ids.all.ids}"] + vpc_zone_identifier = data.aws_subnet_ids.all.ids min_size = "1" max_size = "1" } resource "aws_launch_configuration" "lc_sample" { name_prefix = "lc-sample-" - image_id = "ami-43a15f3e" # Ubuntu Server 16.04 LTS (HVM) + image_id = "ami-43a15f3e" # Ubuntu Server 16.04 LTS (HVM) instance_type = "t2.micro" - user_data = "${data.template_file.user_data.rendered}" + user_data = data.template_file.user_data.rendered key_name = "${var.ssh_key_name}" associate_public_ip_address = true - security_groups = ["${aws_security_group.sg_sample.id}"] + security_groups = [aws_security_group.sg_sample.id] lifecycle { create_before_destroy = true @@ -69,9 +69,9 @@ resource "aws_launch_configuration" "lc_sample" { } data "template_file" "user_data" { - template = "${file("${path.module}/user-data.sh")}" + template = file("${path.module}/user-data.sh") - vars { + vars = { nomad_ui_port = 4646 consul_ui_port = 8500 fabio_ui_port = 9998 @@ -82,23 +82,25 @@ module "ui-access" { source = "../../modules/ui-access" ## required parameters - vpc_id = "${data.aws_vpc.default.id}" - subnet_ids = "${data.aws_subnet_ids.all.ids}" - nomad_server_asg_name = "${aws_autoscaling_group.asg_sample.name}" - consul_server_asg_name = "${aws_autoscaling_group.asg_sample.name}" - fabio_server_asg_name = "${aws_autoscaling_group.asg_sample.name}" + vpc_id = data.aws_vpc.default.id + subnet_ids = data.aws_subnet_ids.all.ids + nomad_server_asg_name = aws_autoscaling_group.asg_sample.name + consul_server_asg_name = aws_autoscaling_group.asg_sample.name + fabio_server_asg_name = aws_autoscaling_group.asg_sample.name ## optional parameters - aws_region = "${var.aws_region}" - env_name = "${local.env_name}" - stack_name = "${local.stack_name}" + aws_region = var.aws_region + env_name = local.env_name + stack_name = local.stack_name nomad_ui_port = 4646 consul_ui_port = 8500 fabio_ui_port = 9998 allowed_cidr_blocks_for_ui_alb = { - "all" = "0.0.0.0/0" + "all" = "0.0.0.0/0", + "another" = "10.10.0.0/16" } unique_postfix = "" } + diff --git a/examples/ui-access/outputs.tf b/examples/ui-access/outputs.tf index 7ca6948..ae2934a 100644 --- a/examples/ui-access/outputs.tf +++ b/examples/ui-access/outputs.tf @@ -1,5 +1,5 @@ output "nomad_ui_alb_dns" { - value = "${module.ui-access.nomad_ui_alb_dns_name}" + value = module.ui-access.nomad_ui_alb_dns_name } output "curl_nomad_ui" { @@ -11,7 +11,7 @@ output "url_nomad_ui" { } output "consul_ui_alb_dns" { - value = "${module.ui-access.consul_ui_alb_dns_name}" + value = module.ui-access.consul_ui_alb_dns_name } output "curl_consul_ui" { @@ -23,7 +23,7 @@ output "url_consul_ui" { } output "fabio_ui_alb_dns" { - value = "${module.ui-access.fabio_ui_alb_dns_name}" + value = module.ui-access.fabio_ui_alb_dns_name } output "curl_fabio_ui" { diff --git a/examples/ui-access/versions.tf b/examples/ui-access/versions.tf new file mode 100644 index 0000000..ac97c6a --- /dev/null +++ b/examples/ui-access/versions.tf @@ -0,0 +1,4 @@ + +terraform { + required_version = ">= 0.12" +} diff --git a/main.tf b/main.tf index 2cd9305..efed6e0 100644 --- a/main.tf +++ b/main.tf @@ -4,195 +4,207 @@ locals { } module "ui-access" { - source = "modules/ui-access" + source = "./modules/ui-access" ## required parameters - vpc_id = "${var.vpc_id}" - subnet_ids = "${var.alb_subnet_ids}" - consul_server_asg_name = "${module.consul.asg_name_consul_servers}" - nomad_server_asg_name = "${module.nomad.asg_name_nomad_servers}" - fabio_server_asg_name = "${module.dc-public-services.asg_name}" - ui_alb_https_listener_cert_arn = "${var.ui_alb_https_listener_cert_arn}" - ui_alb_use_https_listener = "${var.ui_alb_use_https_listener}" + vpc_id = var.vpc_id + subnet_ids = var.alb_subnet_ids + consul_server_asg_name = module.consul.asg_name_consul_servers + nomad_server_asg_name = module.nomad.asg_name_nomad_servers + fabio_server_asg_name = module.dc-public-services.asg_name + ui_alb_https_listener_cert_arn = var.ui_alb_https_listener_cert_arn + ui_alb_use_https_listener = var.ui_alb_use_https_listener ## optional parameters - aws_region = "${var.aws_region}" - env_name = "${var.env_name}" - stack_name = "${var.stack_name}" - unique_postfix = "${var.unique_postfix}" - allowed_cidr_blocks_for_ui_alb = "${var.allowed_cidr_blocks_for_ui_alb}" + aws_region = var.aws_region + env_name = var.env_name + stack_name = var.stack_name + unique_postfix = var.unique_postfix + allowed_cidr_blocks_for_ui_alb = var.allowed_cidr_blocks_for_ui_alb } module "consul" { - source = "modules/consul" + source = "./modules/consul" ## required parameters - ami_id = "${var.consul_ami_id}" - vpc_id = "${var.vpc_id}" - subnet_ids = "${var.consul_server_subnet_ids}" + ami_id = var.consul_ami_id + vpc_id = var.vpc_id + subnet_ids = var.consul_server_subnet_ids ## optional parameters - env_name = "${var.env_name}" - aws_region = "${var.aws_region}" - stack_name = "${var.stack_name}" - cluster_tag_key = "${local.consul_cluster_tag_key}" - cluster_tag_value = "${local.consul_cluster_tag_value}" - allowed_ssh_cidr_blocks = "${var.allowed_ssh_cidr_blocks}" - num_servers = "${var.consul_num_servers}" - instance_type = "${var.consul_instance_type}" - ssh_key_name = "${var.ssh_key_name}" + env_name = var.env_name + aws_region = var.aws_region + stack_name = var.stack_name + cluster_tag_key = local.consul_cluster_tag_key + cluster_tag_value = local.consul_cluster_tag_value + allowed_ssh_cidr_blocks = var.allowed_ssh_cidr_blocks + num_servers = var.consul_num_servers + instance_type = var.consul_instance_type + ssh_key_name = var.ssh_key_name } #### DC: PUBLIC-SERVICES ################################################### module "dc-public-services" { - source = "modules/nomad-datacenter" + source = "./modules/nomad-datacenter" ## required parameters - vpc_id = "${var.vpc_id}" - subnet_ids = "${var.nomad_clients_public_services_subnet_ids}" - ami_id = "${var.nomad_ami_id_clients}" - consul_cluster_tag_key = "${local.consul_cluster_tag_key}" - consul_cluster_tag_value = "${local.consul_cluster_tag_value}" - server_sg_id = "${module.nomad.security_group_id_nomad_servers}" + vpc_id = var.vpc_id + subnet_ids = var.nomad_clients_public_services_subnet_ids + ami_id = var.nomad_ami_id_clients + consul_cluster_tag_key = local.consul_cluster_tag_key + consul_cluster_tag_value = local.consul_cluster_tag_value + server_sg_id = module.nomad.security_group_id_nomad_servers ## optional parameters - env_name = "${var.env_name}" - stack_name = "${var.stack_name}" - aws_region = "${var.aws_region}" - instance_type = "${lookup(var.nomad_public_services_dc_node_cfg,"instance_type","INVALID")}" - allowed_ssh_cidr_blocks = "${var.allowed_ssh_cidr_blocks}" - ssh_key_name = "${var.ssh_key_name}" + env_name = var.env_name + stack_name = var.stack_name + aws_region = var.aws_region + instance_type = lookup( + var.nomad_public_services_dc_node_cfg, + "instance_type", + "INVALID", + ) + allowed_ssh_cidr_blocks = var.allowed_ssh_cidr_blocks + ssh_key_name = var.ssh_key_name datacenter_name = "public-services" - unique_postfix = "${var.unique_postfix}" - alb_ingress_https_listener_arn = "${var.alb_ingress_https_listener_arn}" + unique_postfix = var.unique_postfix + alb_ingress_https_listener_arn = var.alb_ingress_https_listener_arn attach_ingress_alb_listener = true - node_scaling_cfg = "${var.nomad_public_services_dc_node_cfg}" - ebs_block_devices = "${var.ebs_block_devices_public_services_dc}" - device_to_mount_target_map = "${var.device_to_mount_target_map_public_services_dc}" - additional_instance_tags = "${var.additional_instance_tags_public_services_dc}" + node_scaling_cfg = var.nomad_public_services_dc_node_cfg + ebs_block_devices = var.ebs_block_devices_public_services_dc + device_to_mount_target_map = var.device_to_mount_target_map_public_services_dc + additional_instance_tags = var.additional_instance_tags_public_services_dc } #### DC: PRIVATE-SERVICES ################################################### module "dc-private-services" { - source = "modules/nomad-datacenter" + source = "./modules/nomad-datacenter" ## required parameters - vpc_id = "${var.vpc_id}" - subnet_ids = "${var.nomad_clients_private_services_subnet_ids}" - ami_id = "${var.nomad_ami_id_clients}" - consul_cluster_tag_key = "${local.consul_cluster_tag_key}" - consul_cluster_tag_value = "${local.consul_cluster_tag_value}" - server_sg_id = "${module.nomad.security_group_id_nomad_servers}" + vpc_id = var.vpc_id + subnet_ids = var.nomad_clients_private_services_subnet_ids + ami_id = var.nomad_ami_id_clients + consul_cluster_tag_key = local.consul_cluster_tag_key + consul_cluster_tag_value = local.consul_cluster_tag_value + server_sg_id = module.nomad.security_group_id_nomad_servers ## optional parameters - env_name = "${var.env_name}" - stack_name = "${var.stack_name}" - aws_region = "${var.aws_region}" - instance_type = "${lookup(var.nomad_private_services_dc_node_cfg,"instance_type","INVALID")}" - allowed_ssh_cidr_blocks = "${var.allowed_ssh_cidr_blocks}" - ssh_key_name = "${var.ssh_key_name}" + env_name = var.env_name + stack_name = var.stack_name + aws_region = var.aws_region + instance_type = lookup( + var.nomad_private_services_dc_node_cfg, + "instance_type", + "INVALID", + ) + allowed_ssh_cidr_blocks = var.allowed_ssh_cidr_blocks + ssh_key_name = var.ssh_key_name datacenter_name = "private-services" - unique_postfix = "${var.unique_postfix}" - node_scaling_cfg = "${var.nomad_private_services_dc_node_cfg}" - efs_dns_name = "${var.efs_dns_name}" - map_bucket_name = "${var.map_bucket_name}" - ebs_block_devices = "${var.ebs_block_devices_private_services_dc}" - device_to_mount_target_map = "${var.device_to_mount_target_map_private_services_dc}" - additional_instance_tags = "${var.additional_instance_tags_private_services_dc}" + unique_postfix = var.unique_postfix + node_scaling_cfg = var.nomad_private_services_dc_node_cfg + efs_dns_name = var.efs_dns_name + map_bucket_name = var.map_bucket_name + ebs_block_devices = var.ebs_block_devices_private_services_dc + device_to_mount_target_map = var.device_to_mount_target_map_private_services_dc + additional_instance_tags = var.additional_instance_tags_private_services_dc } #### DC: BACKOFFICE ################################################### module "dc-backoffice" { - source = "modules/nomad-datacenter" + source = "./modules/nomad-datacenter" ## required parameters - vpc_id = "${var.vpc_id}" - subnet_ids = "${var.nomad_clients_backoffice_subnet_ids}" - ami_id = "${var.nomad_ami_id_clients}" - consul_cluster_tag_key = "${local.consul_cluster_tag_key}" - consul_cluster_tag_value = "${local.consul_cluster_tag_value}" - server_sg_id = "${module.nomad.security_group_id_nomad_servers}" + vpc_id = var.vpc_id + subnet_ids = var.nomad_clients_backoffice_subnet_ids + ami_id = var.nomad_ami_id_clients + consul_cluster_tag_key = local.consul_cluster_tag_key + consul_cluster_tag_value = local.consul_cluster_tag_value + server_sg_id = module.nomad.security_group_id_nomad_servers ## optional parameters - env_name = "${var.env_name}" - stack_name = "${var.stack_name}" - aws_region = "${var.aws_region}" - instance_type = "${lookup(var.nomad_backoffice_dc_node_cfg,"instance_type","INVALID")}" - allowed_ssh_cidr_blocks = "${var.allowed_ssh_cidr_blocks}" - ssh_key_name = "${var.ssh_key_name}" + env_name = var.env_name + stack_name = var.stack_name + aws_region = var.aws_region + instance_type = lookup(var.nomad_backoffice_dc_node_cfg, "instance_type", "INVALID") + allowed_ssh_cidr_blocks = var.allowed_ssh_cidr_blocks + ssh_key_name = var.ssh_key_name datacenter_name = "backoffice" - unique_postfix = "${var.unique_postfix}" - alb_ingress_https_listener_arn = "${var.alb_backoffice_https_listener_arn}" - attach_ingress_alb_listener = "${var.attach_backoffice_alb_listener}" - node_scaling_cfg = "${var.nomad_backoffice_dc_node_cfg}" - ebs_block_devices = "${var.ebs_block_devices_backoffice_dc}" - device_to_mount_target_map = "${var.device_to_mount_target_map_backoffice_dc}" - additional_instance_tags = "${var.additional_instance_tags_backoffice_dc}" + unique_postfix = var.unique_postfix + alb_ingress_https_listener_arn = var.alb_backoffice_https_listener_arn + attach_ingress_alb_listener = var.attach_backoffice_alb_listener + node_scaling_cfg = var.nomad_backoffice_dc_node_cfg + ebs_block_devices = var.ebs_block_devices_backoffice_dc + device_to_mount_target_map = var.device_to_mount_target_map_backoffice_dc + additional_instance_tags = var.additional_instance_tags_backoffice_dc } #### DC: CONTENT-CONNECTOR ################################################### module "dc-content-connector" { - source = "modules/nomad-datacenter" + source = "./modules/nomad-datacenter" ## required parameters - vpc_id = "${var.vpc_id}" - subnet_ids = "${var.nomad_clients_content_connector_subnet_ids}" - ami_id = "${var.nomad_ami_id_clients}" - consul_cluster_tag_key = "${local.consul_cluster_tag_key}" - consul_cluster_tag_value = "${local.consul_cluster_tag_value}" - server_sg_id = "${module.nomad.security_group_id_nomad_servers}" + vpc_id = var.vpc_id + subnet_ids = var.nomad_clients_content_connector_subnet_ids + ami_id = var.nomad_ami_id_clients + consul_cluster_tag_key = local.consul_cluster_tag_key + consul_cluster_tag_value = local.consul_cluster_tag_value + server_sg_id = module.nomad.security_group_id_nomad_servers ## optional parameters - env_name = "${var.env_name}" - stack_name = "${var.stack_name}" - aws_region = "${var.aws_region}" - instance_type = "${lookup(var.nomad_content_connector_dc_node_cfg,"instance_type","INVALID")}" - allowed_ssh_cidr_blocks = "${var.allowed_ssh_cidr_blocks}" - ssh_key_name = "${var.ssh_key_name}" + env_name = var.env_name + stack_name = var.stack_name + aws_region = var.aws_region + instance_type = lookup( + var.nomad_content_connector_dc_node_cfg, + "instance_type", + "INVALID", + ) + allowed_ssh_cidr_blocks = var.allowed_ssh_cidr_blocks + ssh_key_name = var.ssh_key_name datacenter_name = "content-connector" - unique_postfix = "${var.unique_postfix}" - node_scaling_cfg = "${var.nomad_content_connector_dc_node_cfg}" - ebs_block_devices = "${var.ebs_block_devices_content_connector_dc}" - device_to_mount_target_map = "${var.device_to_mount_target_map_content_connector_dc}" - additional_instance_tags = "${var.additional_instance_tags_content_connector_dc}" + unique_postfix = var.unique_postfix + node_scaling_cfg = var.nomad_content_connector_dc_node_cfg + ebs_block_devices = var.ebs_block_devices_content_connector_dc + device_to_mount_target_map = var.device_to_mount_target_map_content_connector_dc + additional_instance_tags = var.additional_instance_tags_content_connector_dc } module "nomad" { - source = "modules/nomad" + source = "./modules/nomad" ## required parameters - vpc_id = "${var.vpc_id}" - subnet_ids = "${var.nomad_server_subnet_ids}" - ami_id = "${var.nomad_ami_id_servers}" - consul_cluster_tag_key = "${local.consul_cluster_tag_key}" - consul_cluster_tag_value = "${local.consul_cluster_tag_value}" - consul_cluster_security_group_id = "${module.consul.security_group_id_consul_servers}" + vpc_id = var.vpc_id + subnet_ids = var.nomad_server_subnet_ids + ami_id = var.nomad_ami_id_servers + consul_cluster_tag_key = local.consul_cluster_tag_key + consul_cluster_tag_value = local.consul_cluster_tag_value ## optional parameters - env_name = "${var.env_name}" - stack_name = "${var.stack_name}" - aws_region = "${var.aws_region}" - instance_type = "${var.instance_type_server}" - allowed_ssh_cidr_blocks = "${var.allowed_ssh_cidr_blocks}" - ssh_key_name = "${var.ssh_key_name}" - node_scaling_cfg = "${var.nomad_server_scaling_cfg}" - unique_postfix = "${var.unique_postfix}" + env_name = var.env_name + stack_name = var.stack_name + aws_region = var.aws_region + instance_type = var.instance_type_server + allowed_ssh_cidr_blocks = var.allowed_ssh_cidr_blocks + ssh_key_name = var.ssh_key_name + node_scaling_cfg = var.nomad_server_scaling_cfg + unique_postfix = var.unique_postfix } module "sgrules" { - source = "modules/sgrules" - sg_id_public_services_dc = "${module.dc-public-services.sg_datacenter_id}" - sg_id_private_services_dc = "${module.dc-private-services.sg_datacenter_id}" - sg_id_content_connector_dc = "${module.dc-content-connector.sg_datacenter_id}" - sg_id_backoffice_dc = "${module.dc-backoffice.sg_datacenter_id}" - sg_id_consul = "${module.consul.security_group_id_consul_servers}" - sg_id_nomad_server = "${module.nomad.security_group_id_nomad_servers}" - sg_id_ui_alb_nomad = "${module.ui-access.nomad_ui_alb_sg_id}" - sg_id_ui_alb_consul = "${module.ui-access.consul_ui_alb_sg_id}" + source = "./modules/sgrules" + sg_id_public_services_dc = module.dc-public-services.sg_datacenter_id + sg_id_private_services_dc = module.dc-private-services.sg_datacenter_id + sg_id_content_connector_dc = module.dc-content-connector.sg_datacenter_id + sg_id_backoffice_dc = module.dc-backoffice.sg_datacenter_id + sg_id_consul = module.consul.security_group_id_consul_servers + sg_id_nomad_server = module.nomad.security_group_id_nomad_servers + sg_id_ui_alb_nomad = module.ui-access.nomad_ui_alb_sg_id + sg_id_ui_alb_consul = module.ui-access.consul_ui_alb_sg_id } module "ecr" { - source = "modules/ecr" + source = "./modules/ecr" - ecr_repositories = "${var.ecr_repositories}" + ecr_repositories = var.ecr_repositories } + diff --git a/modules/bastion/main.tf b/modules/bastion/main.tf index 3b14cf0..7ec7d92 100644 --- a/modules/bastion/main.tf +++ b/modules/bastion/main.tf @@ -1,22 +1,22 @@ resource "aws_instance" "ec2_bastion" { - ami = "${var.ami_id}" - instance_type = "${var.instance_type}" - key_name = "${var.ssh_key_name}" - subnet_id = "${var.subnet_id}" + ami = var.ami_id + instance_type = var.instance_type + key_name = var.ssh_key_name + subnet_id = var.subnet_id - vpc_security_group_ids = ["${aws_security_group.sg_bastion.id}"] + vpc_security_group_ids = [aws_security_group.sg_bastion.id] - tags { + tags = { Name = "${var.stack_name}-EC2-bastion${var.unique_postfix}" } } resource "aws_security_group" "sg_bastion" { - vpc_id = "${var.vpc_id}" + vpc_id = var.vpc_id name = "${var.stack_name}-SG-bastion${var.unique_postfix}" description = "Security Group for basition server" - tags { + tags = { Name = "${var.stack_name}-SG-bastion${var.unique_postfix}" } @@ -34,30 +34,35 @@ resource "aws_security_group_rule" "sgr_bastion_egAll" { description = "egress all tcp" cidr_blocks = ["0.0.0.0/0"] - security_group_id = "${aws_security_group.sg_bastion.id}" + security_group_id = aws_security_group.sg_bastion.id } locals { - keys = "${keys(var.allowed_ssh_cidr_blocks)}" + keys = keys(var.allowed_ssh_cidr_blocks) } resource "aws_security_group_rule" "sgr_bastion_ig_ssh" { - count = "${length(local.keys)}" - description = "${element(local.keys,count.index)}: igress ssh" - type = "ingress" - from_port = 22 - to_port = 22 - protocol = "tcp" - cidr_blocks = ["${lookup(var.allowed_ssh_cidr_blocks,element(local.keys,count.index),"0.0.0.0/32")}"] - security_group_id = "${aws_security_group.sg_bastion.id}" + count = length(local.keys) + description = "${element(local.keys, count.index)}: igress ssh" + type = "ingress" + from_port = 22 + to_port = 22 + protocol = "tcp" + + cidr_blocks = [lookup( + var.allowed_ssh_cidr_blocks, + element(local.keys, count.index), + "0.0.0.0/32", + )] + security_group_id = aws_security_group.sg_bastion.id } # elastic ips needed for the bastion resource "aws_eip" "eip_bastion" { - instance = "${aws_instance.ec2_bastion.id}" + instance = aws_instance.ec2_bastion.id vpc = true - tags { + tags = { Name = "${var.stack_name}-EIP-bastion${var.unique_postfix}" } -} +} \ No newline at end of file diff --git a/modules/bastion/outputs.tf b/modules/bastion/outputs.tf index 0db7f28..a050f53 100644 --- a/modules/bastion/outputs.tf +++ b/modules/bastion/outputs.tf @@ -1,7 +1,7 @@ output "bastion_ip" { - value = "${aws_eip.eip_bastion.public_ip}" + value = aws_eip.eip_bastion.public_ip } output "ssh_key_name" { - value = "${var.ssh_key_name}" + value = var.ssh_key_name } diff --git a/modules/bastion/vars.tf b/modules/bastion/vars.tf index b4abe11..d168ecf 100644 --- a/modules/bastion/vars.tf +++ b/modules/bastion/vars.tf @@ -43,7 +43,7 @@ variable "unique_postfix" { variable "allowed_ssh_cidr_blocks" { description = "Map for cidr blocks that should get access to the bastion. The format is name:cidr-block. I.e. 'my_cidr'='90.250.75.79/32'" - type = "map" + type = map(string) default = { "all" = "0.0.0.0/0" diff --git a/modules/bastion/versions.tf b/modules/bastion/versions.tf new file mode 100644 index 0000000..8007815 --- /dev/null +++ b/modules/bastion/versions.tf @@ -0,0 +1,4 @@ +terraform { + required_version = ">= 0.12" +} + diff --git a/modules/consul/main.tf b/modules/consul/main.tf index f09ba0a..fe9ef8d 100644 --- a/modules/consul/main.tf +++ b/modules/consul/main.tf @@ -1,34 +1,28 @@ -# Terraform 0.9.5 suffered from https://github.com/hashicorp/terraform/issues/14399, which causes this template the -# conditionals in this template to fail. -terraform { - required_version = ">= 0.9.3, != 0.9.5" -} - # --------------------------------------------------------------------------------------------------------------------- # DEPLOY THE CONSUL SERVER NODES # --------------------------------------------------------------------------------------------------------------------- module "consul_servers" { - source = "git::https://github.com/hashicorp/terraform-aws-consul.git//modules/consul-cluster?ref=v0.4.4" + source = "git::https://github.com/hashicorp/terraform-aws-consul.git//modules/consul-cluster?ref=v0.7.0" - cluster_name = "${var.cluster_tag_value}" - cluster_size = "${var.num_servers}" - instance_type = "${var.instance_type}" + cluster_name = var.cluster_tag_value + cluster_size = var.num_servers + instance_type = var.instance_type # The EC2 Instances will use these tags to automatically discover each other and form a cluster - cluster_tag_key = "${var.cluster_tag_key}" - cluster_tag_value = "${var.cluster_tag_value}" + cluster_tag_key = var.cluster_tag_key + cluster_tag_value = var.cluster_tag_value - ami_id = "${var.ami_id}" - user_data = "${data.template_file.user_data_consul_server.rendered}" + ami_id = var.ami_id + user_data = data.template_file.user_data_consul_server.rendered - vpc_id = "${var.vpc_id}" - subnet_ids = "${var.subnet_ids}" + vpc_id = var.vpc_id + subnet_ids = var.subnet_ids - allowed_ssh_cidr_blocks = "${var.allowed_ssh_cidr_blocks}" + allowed_ssh_cidr_blocks = var.allowed_ssh_cidr_blocks allowed_inbound_cidr_blocks = [] allowed_inbound_security_group_count = 0 - ssh_key_name = "${var.ssh_key_name}" + ssh_key_name = var.ssh_key_name } # --------------------------------------------------------------------------------------------------------------------- @@ -38,8 +32,8 @@ module "consul_servers" { data "template_file" "user_data_consul_server" { template = "${file("${path.module}/user-data-consul-server.sh")}" - vars { - cluster_tag_key = "${var.cluster_tag_key}" - cluster_tag_value = "${var.cluster_tag_value}" + vars = { + cluster_tag_key = var.cluster_tag_key + cluster_tag_value = var.cluster_tag_value } } diff --git a/modules/consul/outputs.tf b/modules/consul/outputs.tf index 4793080..a846542 100644 --- a/modules/consul/outputs.tf +++ b/modules/consul/outputs.tf @@ -1,15 +1,15 @@ output "asg_name_consul_servers" { - value = "${module.consul_servers.asg_name}" + value = module.consul_servers.asg_name } output "security_group_id_consul_servers" { - value = "${module.consul_servers.security_group_id}" + value = module.consul_servers.security_group_id } output "consul_servers_cluster_tag_key" { - value = "${module.consul_servers.cluster_tag_key}" + value = module.consul_servers.cluster_tag_key } output "consul_servers_cluster_tag_value" { - value = "${module.consul_servers.cluster_tag_value}" + value = module.consul_servers.cluster_tag_value } diff --git a/modules/consul/sg.tf b/modules/consul/sg.tf index 33b66d7..c41c8bd 100644 --- a/modules/consul/sg.tf +++ b/modules/consul/sg.tf @@ -1,6 +1,6 @@ # obtain consul sg in order to add rules needed data "aws_security_group" "consul_sg" { - id = "${module.consul_servers.security_group_id}" + id = module.consul_servers.security_group_id } # Consul ports see: https://www.consul.io/docs/agent/options.html in section 'Ports Used' diff --git a/modules/consul/versions.tf b/modules/consul/versions.tf new file mode 100644 index 0000000..ac97c6a --- /dev/null +++ b/modules/consul/versions.tf @@ -0,0 +1,4 @@ + +terraform { + required_version = ">= 0.12" +} diff --git a/modules/networking/backoffice_alb.tf b/modules/networking/backoffice_alb.tf index 66a70a0..9b0df7f 100644 --- a/modules/networking/backoffice_alb.tf +++ b/modules/networking/backoffice_alb.tf @@ -2,10 +2,10 @@ resource "aws_alb" "alb_backoffice" { name = "${var.stack_name}-backoffice${var.unique_postfix}" internal = false - subnets = ["${aws_subnet.subn_public.*.id}"] - security_groups = ["${aws_security_group.sg_backoffice_alb.id}"] + subnets = aws_subnet.subn_public.*.id + security_groups = [aws_security_group.sg_backoffice_alb.id] - tags { + tags = { Name = "${var.stack_name}-backoffice${var.unique_postfix}" internal = false } @@ -16,23 +16,23 @@ resource "aws_alb_target_group" "tgr_dummy_backoffice" { name = "${var.stack_name}-backoffice-dummy${var.unique_postfix}" port = 5000 protocol = "HTTP" - vpc_id = "${aws_vpc.vpc_main.id}" + vpc_id = aws_vpc.vpc_main.id - tags { + tags = { Name = "${var.stack_name}-backoffice-dummy${var.unique_postfix}" } } # listener for https with one default action to a dummy target group resource "aws_alb_listener" "alb_backoffice_https" { - load_balancer_arn = "${aws_alb.alb_backoffice.arn}" + load_balancer_arn = aws_alb.alb_backoffice.arn # HACK: currently protocol is https although this is the https listener. protocol = "HTTP" port = "443" default_action { - target_group_arn = "${aws_alb_target_group.tgr_dummy_backoffice.arn}" + target_group_arn = aws_alb_target_group.tgr_dummy_backoffice.arn type = "forward" } } diff --git a/modules/networking/backoffice_alb_sg.tf b/modules/networking/backoffice_alb_sg.tf index 2d2bc48..20cd742 100644 --- a/modules/networking/backoffice_alb_sg.tf +++ b/modules/networking/backoffice_alb_sg.tf @@ -1,9 +1,9 @@ resource "aws_security_group" "sg_backoffice_alb" { - vpc_id = "${aws_vpc.vpc_main.id}" + vpc_id = aws_vpc.vpc_main.id name = "${var.stack_name}-backoffice-alb${var.unique_postfix}" description = "security group that allows ingress access to everyone." - tags { + tags = { Name = "${var.stack_name}-backoffice${var.unique_postfix}" } @@ -19,7 +19,7 @@ resource "aws_security_group_rule" "sgr_alb_backoffice_ig_https" { to_port = 443 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] - security_group_id = "${aws_security_group.sg_backoffice_alb.id}" + security_group_id = aws_security_group.sg_backoffice_alb.id } # grants access for all tcp but only to the services subnet @@ -31,5 +31,6 @@ resource "aws_security_group_rule" "sgr_alb_backoffice_egAll_server" { protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] - security_group_id = "${aws_security_group.sg_backoffice_alb.id}" + security_group_id = aws_security_group.sg_backoffice_alb.id } + diff --git a/modules/networking/outputs.tf b/modules/networking/outputs.tf index 805f8c3..8e46379 100644 --- a/modules/networking/outputs.tf +++ b/modules/networking/outputs.tf @@ -1,39 +1,40 @@ output "services_subnet_ids" { - value = "${aws_subnet.subn_services.*.id}" + value = aws_subnet.subn_services.*.id } output "public_subnet_ids" { - value = "${aws_subnet.subn_public.*.id}" + value = aws_subnet.subn_public.*.id } output "backoffice_subnet_ids" { - value = "${aws_subnet.subn_backoffice.*.id}" + value = aws_subnet.subn_backoffice.*.id } output "content_connector_subnet_ids" { - value = "${aws_subnet.subn_contentconnector.*.id}" + value = aws_subnet.subn_contentconnector.*.id } output "vpc_id" { - value = "${aws_vpc.vpc_main.id}" + value = aws_vpc.vpc_main.id } output "alb_ingress_http_listener_arn" { - value = "${aws_alb_listener.alb_ingress_http.arn}" + value = aws_alb_listener.alb_ingress_http.arn } output "alb_ingress_https_listener_arn" { - value = "${aws_alb_listener.alb_ingress_https.arn}" + value = aws_alb_listener.alb_ingress_https.arn } output "alb_backoffice_https_listener_arn" { - value = "${aws_alb_listener.alb_backoffice_https.arn}" + value = aws_alb_listener.alb_backoffice_https.arn } output "alb_public_services_dns" { - value = "${aws_alb.alb_public_services.dns_name}" + value = aws_alb.alb_public_services.dns_name } output "vpc_cidr_block" { - value = "${aws_vpc.vpc_main.cidr_block}" + value = aws_vpc.vpc_main.cidr_block } + diff --git a/modules/networking/public_services_alb.tf b/modules/networking/public_services_alb.tf index b6d61d7..c7a1e6a 100644 --- a/modules/networking/public_services_alb.tf +++ b/modules/networking/public_services_alb.tf @@ -6,10 +6,10 @@ locals { resource "aws_alb" "alb_public_services" { name = "${var.stack_name}-ingress${var.unique_postfix}" internal = false - subnets = ["${aws_subnet.subn_public.*.id}"] - security_groups = ["${aws_security_group.sg_public_services_alb.id}"] + subnets = aws_subnet.subn_public.*.id + security_groups = [aws_security_group.sg_public_services_alb.id] - tags { + tags = { Name = "${var.stack_name}-ingress${var.unique_postfix}" internal = false } @@ -18,18 +18,18 @@ resource "aws_alb" "alb_public_services" { # Listener with empty dummy target group resource "aws_alb_target_group" "tgr_dummy_public_services" { name = "${var.stack_name}-igress-dummy${var.unique_postfix}" - port = "${local.dummy_port}" + port = local.dummy_port protocol = "HTTP" - vpc_id = "${aws_vpc.vpc_main.id}" + vpc_id = aws_vpc.vpc_main.id - tags { + tags = { Name = "${var.stack_name}-igress-dummy${var.unique_postfix}" } } # listener for https with one default action to a dummy target group resource "aws_alb_listener" "alb_ingress_https" { - load_balancer_arn = "${aws_alb.alb_public_services.arn}" + load_balancer_arn = aws_alb.alb_public_services.arn # HACK: currently protocol is https although this is the https listener. protocol = "HTTP" @@ -40,19 +40,20 @@ resource "aws_alb_listener" "alb_ingress_https" { #certificate_arn = "${var.dummy_listener_certificate_arn}" default_action { - target_group_arn = "${aws_alb_target_group.tgr_dummy_public_services.arn}" + target_group_arn = aws_alb_target_group.tgr_dummy_public_services.arn type = "forward" } } # listener for http with one default action to a dummy target group resource "aws_alb_listener" "alb_ingress_http" { - load_balancer_arn = "${aws_alb.alb_public_services.arn}" + load_balancer_arn = aws_alb.alb_public_services.arn protocol = "HTTP" port = "80" default_action { - target_group_arn = "${aws_alb_target_group.tgr_dummy_public_services.arn}" + target_group_arn = aws_alb_target_group.tgr_dummy_public_services.arn type = "forward" } } + diff --git a/modules/networking/public_services_alb_sg.tf b/modules/networking/public_services_alb_sg.tf index d62a456..35420df 100644 --- a/modules/networking/public_services_alb_sg.tf +++ b/modules/networking/public_services_alb_sg.tf @@ -1,9 +1,9 @@ resource "aws_security_group" "sg_public_services_alb" { - vpc_id = "${aws_vpc.vpc_main.id}" + vpc_id = aws_vpc.vpc_main.id name = "${var.stack_name}-ingress${var.unique_postfix}" description = "security group that allows ingress access to everyone." - tags { + tags = { Name = "${var.stack_name}-ingress${var.unique_postfix}" } @@ -20,7 +20,7 @@ resource "aws_security_group_rule" "sgr_alb_ig_http" { to_port = 80 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] - security_group_id = "${aws_security_group.sg_public_services_alb.id}" + security_group_id = aws_security_group.sg_public_services_alb.id } resource "aws_security_group_rule" "sgr_alb_ig_https" { @@ -30,7 +30,7 @@ resource "aws_security_group_rule" "sgr_alb_ig_https" { to_port = 443 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] - security_group_id = "${aws_security_group.sg_public_services_alb.id}" + security_group_id = aws_security_group.sg_public_services_alb.id } # grants access for all tcp but only to the services subnet @@ -42,5 +42,6 @@ resource "aws_security_group_rule" "sgr_alb_egAll_server" { protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] - security_group_id = "${aws_security_group.sg_public_services_alb.id}" + security_group_id = aws_security_group.sg_public_services_alb.id } + diff --git a/modules/networking/subn_backoffice.tf b/modules/networking/subn_backoffice.tf index 637510b..cf2266f 100644 --- a/modules/networking/subn_backoffice.tf +++ b/modules/networking/subn_backoffice.tf @@ -1,41 +1,42 @@ # BACKOFFICE subnets resource "aws_subnet" "subn_backoffice" { # one for each az - count = "${length(var.az_postfixes)}" - vpc_id = "${aws_vpc.vpc_main.id}" + count = length(var.az_postfixes) + vpc_id = aws_vpc.vpc_main.id cidr_block = "${var.ip_prefix}.${140 + count.index}.0/24" - availability_zone = "${var.region}${element(var.az_postfixes,count.index)}" + availability_zone = "${var.region}${element(var.az_postfixes, count.index)}" - tags { - Name = "MNG-${var.stack_name}-${var.region}${element(var.az_postfixes,count.index)}-${var.env_name}-SUBN-backoffice" + tags = { + Name = "MNG-${var.stack_name}-${var.region}${element(var.az_postfixes, count.index)}-${var.env_name}-SUBN-backoffice" } } # route-table for the backoffice subnets resource "aws_route_table" "rtb_backoffice" { - vpc_id = "${aws_vpc.vpc_main.id}" + vpc_id = aws_vpc.vpc_main.id # one for each az - count = "${length(var.az_postfixes)}" + count = length(var.az_postfixes) - tags { - Name = "MNG-${var.stack_name}-${var.region}${element(var.az_postfixes,count.index)}-${var.env_name}-RTB-backoffice" + tags = { + Name = "MNG-${var.stack_name}-${var.region}${element(var.az_postfixes, count.index)}-${var.env_name}-RTB-backoffice" } } # association between the backoffice subnets and the backoffice routetable resource "aws_route_table_association" "rtassoc_backoffice" { # one for each az - count = "${length(var.az_postfixes)}" - subnet_id = "${element(aws_subnet.subn_backoffice.*.id,count.index)}" - route_table_id = "${element(aws_route_table.rtb_backoffice.*.id,count.index)}" + count = length(var.az_postfixes) + subnet_id = element(aws_subnet.subn_backoffice.*.id, count.index) + route_table_id = element(aws_route_table.rtb_backoffice.*.id, count.index) } # this is the route to the egress_aws natgateway resource "aws_route" "r_backoffice_egress_aws_ngw" { # one for each az - count = "${length(var.az_postfixes)}" - route_table_id = "${element(aws_route_table.rtb_backoffice.*.id,count.index)}" + count = length(var.az_postfixes) + route_table_id = element(aws_route_table.rtb_backoffice.*.id, count.index) destination_cidr_block = "0.0.0.0/0" - nat_gateway_id = "${element(aws_nat_gateway.ngw_egress_aws.*.id,count.index)}" + nat_gateway_id = element(aws_nat_gateway.ngw_egress_aws.*.id, count.index) } + diff --git a/modules/networking/subn_contentconnector.tf b/modules/networking/subn_contentconnector.tf index ff7d8aa..8ad6d9a 100644 --- a/modules/networking/subn_contentconnector.tf +++ b/modules/networking/subn_contentconnector.tf @@ -1,41 +1,42 @@ # CONTENTCONNECTOR subnets resource "aws_subnet" "subn_contentconnector" { # one for each az - count = "${length(var.az_postfixes)}" - vpc_id = "${aws_vpc.vpc_main.id}" - cidr_block = "${var.ip_prefix}.${132 + (count.index*2)}.0/23" - availability_zone = "${var.region}${element(var.az_postfixes,count.index)}" + count = length(var.az_postfixes) + vpc_id = aws_vpc.vpc_main.id + cidr_block = "${var.ip_prefix}.${132 + count.index * 2}.0/23" + availability_zone = "${var.region}${element(var.az_postfixes, count.index)}" - tags { - Name = "MNG-${var.stack_name}-${var.region}${element(var.az_postfixes,count.index)}-${var.env_name}-SUBN-contentconnector" + tags = { + Name = "MNG-${var.stack_name}-${var.region}${element(var.az_postfixes, count.index)}-${var.env_name}-SUBN-contentconnector" } } # route-table for the contentconnector subnets resource "aws_route_table" "rtb_contentconnector" { - vpc_id = "${aws_vpc.vpc_main.id}" + vpc_id = aws_vpc.vpc_main.id # one for each az - count = "${length(var.az_postfixes)}" + count = length(var.az_postfixes) - tags { - Name = "MNG-${var.stack_name}-${var.region}${element(var.az_postfixes,count.index)}-${var.env_name}-RTB-contentconnector" + tags = { + Name = "MNG-${var.stack_name}-${var.region}${element(var.az_postfixes, count.index)}-${var.env_name}-RTB-contentconnector" } } # association between the contentconnector subnets and the contentconnector routetable resource "aws_route_table_association" "rtassoc_contentconnector" { # one for each az - count = "${length(var.az_postfixes)}" - subnet_id = "${element(aws_subnet.subn_contentconnector.*.id,count.index)}" - route_table_id = "${element(aws_route_table.rtb_contentconnector.*.id,count.index)}" + count = length(var.az_postfixes) + subnet_id = element(aws_subnet.subn_contentconnector.*.id, count.index) + route_table_id = element(aws_route_table.rtb_contentconnector.*.id, count.index) } # this is the route to the egress_public natgateway resource "aws_route" "r_egress_public_ngw" { # one for each az - count = "${length(var.az_postfixes)}" - route_table_id = "${element(aws_route_table.rtb_contentconnector.*.id,count.index)}" + count = length(var.az_postfixes) + route_table_id = element(aws_route_table.rtb_contentconnector.*.id, count.index) destination_cidr_block = "0.0.0.0/0" - nat_gateway_id = "${element(aws_nat_gateway.ngw_egress_public.*.id,count.index)}" + nat_gateway_id = element(aws_nat_gateway.ngw_egress_public.*.id, count.index) } + diff --git a/modules/networking/subn_egress_aws.tf b/modules/networking/subn_egress_aws.tf index 37e1115..d1bacc3 100644 --- a/modules/networking/subn_egress_aws.tf +++ b/modules/networking/subn_egress_aws.tf @@ -1,56 +1,81 @@ # EGRESS AWS subnets resource "aws_subnet" "subn_egress_aws" { # one for each az - count = "${length(var.az_postfixes)}" - vpc_id = "${aws_vpc.vpc_main.id}" + count = length(var.az_postfixes) + vpc_id = aws_vpc.vpc_main.id cidr_block = "${var.ip_prefix}.${144 + count.index}.0/24" - availability_zone = "${var.region}${element(var.az_postfixes,count.index)}" + availability_zone = "${var.region}${element(var.az_postfixes, count.index)}" - tags { - Name = "MNG-${var.stack_name}-${var.region}${element(var.az_postfixes,count.index)}-${var.env_name}-SUBN-egress_aws" + tags = { + Name = "MNG-${var.stack_name}-${var.region}${element(var.az_postfixes, count.index)}-${var.env_name}-SUBN-egress_aws" } } +locals { + # This variable contains the cidr's that should be allowed to be routed to per route-table (per availability zone) + # This variable is list of lists. Each element of the list contains two elements. First the id of the route-table the route should be added to, + # second the destination cidr for that route. + # Example: (one rtb-id, three cidr's: setproduct(["rtb-00415f0251d6bfa34"],["72.0.0.0/8","75.0.0.0/8","174.0.0.0/8"]) ) + # [ + # [ + # "rtb-00415f0251d6bfa34", + # "72.0.0.0/8" + # ], + # [ + # "rtb-00415f0251d6bfa34", + # "75.0.0.0/8" + # ], + # [ + # "rtb-00415f0251d6bfa34", + # "174.0.0.0/8" + # ] + # ] + cidr_per_route_table_id = setproduct(aws_route_table.rtb_egress_aws.*.id, var.aws_ip_address_ranges) +} + + # route-table for the egress_aws subnets resource "aws_route_table" "rtb_egress_aws" { - vpc_id = "${aws_vpc.vpc_main.id}" + vpc_id = aws_vpc.vpc_main.id # one for each az - count = "${length(var.az_postfixes)}" + count = length(var.az_postfixes) - tags { - Name = "MNG-${var.stack_name}-${var.region}${element(var.az_postfixes,count.index)}-${var.env_name}-RTB-egress_aws" + tags = { + Name = "MNG-${var.stack_name}-${var.region}${element(var.az_postfixes, count.index)}-${var.env_name}-RTB-egress_aws" } } # association between the egress_aws subnets and the egress_aws routetable resource "aws_route_table_association" "rtassoc_egress_aws" { # one for each az - count = "${length(var.az_postfixes)}" - subnet_id = "${element(aws_subnet.subn_egress_aws.*.id,count.index)}" - route_table_id = "${element(aws_route_table.rtb_egress_aws.*.id,count.index)}" + count = length(var.az_postfixes) + subnet_id = element(aws_subnet.subn_egress_aws.*.id, count.index) + route_table_id = element(aws_route_table.rtb_egress_aws.*.id, count.index) } # this is the route to the aws service ip-ranges resource "aws_route" "r_egress_aws_ips" { # one for each az - count = "${length(var.aws_ip_address_ranges) * length(var.az_postfixes)}" - route_table_id = "${element(aws_route_table.rtb_egress_aws.*.id, (count.index / length(var.aws_ip_address_ranges)) % length(var.az_postfixes))}" - destination_cidr_block = "${element(var.aws_ip_address_ranges,count.index % length(var.aws_ip_address_ranges))}" - gateway_id = "${aws_internet_gateway.igw_main.id}" + count = length(local.cidr_per_route_table_id) + + route_table_id = element(element(local.cidr_per_route_table_id, count.index), 0) + destination_cidr_block = element(element(local.cidr_per_route_table_id, count.index), 1) + gateway_id = aws_internet_gateway.igw_main.id } # elastic ips needed for the egress_aws natgateways resource "aws_eip" "eip_egress_aws" { # one for each az - count = "${length(var.az_postfixes)}" + count = length(var.az_postfixes) vpc = true } # the natgateways for egress aws access resource "aws_nat_gateway" "ngw_egress_aws" { # one for each az - count = "${length(var.az_postfixes)}" - allocation_id = "${element(aws_eip.eip_egress_aws.*.id,count.index)}" - subnet_id = "${element(aws_subnet.subn_egress_aws.*.id,count.index)}" + count = length(var.az_postfixes) + allocation_id = element(aws_eip.eip_egress_aws.*.id, count.index) + subnet_id = element(aws_subnet.subn_egress_aws.*.id, count.index) } + diff --git a/modules/networking/subn_egress_public.tf b/modules/networking/subn_egress_public.tf index c897ede..80b6efd 100644 --- a/modules/networking/subn_egress_public.tf +++ b/modules/networking/subn_egress_public.tf @@ -1,56 +1,57 @@ # EGRESS PUBLIC subnets resource "aws_subnet" "subn_egress_public" { # one for each az - count = "${length(var.az_postfixes)}" - vpc_id = "${aws_vpc.vpc_main.id}" + count = length(var.az_postfixes) + vpc_id = aws_vpc.vpc_main.id cidr_block = "${var.ip_prefix}.${148 + count.index}.0/24" - availability_zone = "${var.region}${element(var.az_postfixes,count.index)}" + availability_zone = "${var.region}${element(var.az_postfixes, count.index)}" - tags { - Name = "MNG-${var.stack_name}-${var.region}${element(var.az_postfixes,count.index)}-${var.env_name}-SUBN-egress_public" + tags = { + Name = "MNG-${var.stack_name}-${var.region}${element(var.az_postfixes, count.index)}-${var.env_name}-SUBN-egress_public" } } # route-table for the egress_public subnets resource "aws_route_table" "rtb_egress_public" { - vpc_id = "${aws_vpc.vpc_main.id}" + vpc_id = aws_vpc.vpc_main.id # one for each az - count = "${length(var.az_postfixes)}" + count = length(var.az_postfixes) - tags { - Name = "MNG-${var.stack_name}-${var.region}${element(var.az_postfixes,count.index)}-${var.env_name}-RTB-egress_public" + tags = { + Name = "MNG-${var.stack_name}-${var.region}${element(var.az_postfixes, count.index)}-${var.env_name}-RTB-egress_public" } } # association between the egress_public subnets and the egress_public routetable resource "aws_route_table_association" "rtassoc_egress_public" { # one for each az - count = "${length(var.az_postfixes)}" - subnet_id = "${element(aws_subnet.subn_egress_public.*.id,count.index)}" - route_table_id = "${element(aws_route_table.rtb_egress_public.*.id,count.index)}" + count = length(var.az_postfixes) + subnet_id = element(aws_subnet.subn_egress_public.*.id, count.index) + route_table_id = element(aws_route_table.rtb_egress_public.*.id, count.index) } # this is the route to the internet resource "aws_route" "r_egress_public_inet" { # one for each az - count = "${length(var.az_postfixes)}" - route_table_id = "${element(aws_route_table.rtb_egress_public.*.id,count.index)}" + count = length(var.az_postfixes) + route_table_id = element(aws_route_table.rtb_egress_public.*.id, count.index) destination_cidr_block = "0.0.0.0/0" - gateway_id = "${aws_internet_gateway.igw_main.id}" + gateway_id = aws_internet_gateway.igw_main.id } # elastic ips needed for the natgateways resource "aws_eip" "eip_egress_public" { # one for each az - count = "${length(var.az_postfixes)}" + count = length(var.az_postfixes) vpc = true } # the natgateways for egress public access resource "aws_nat_gateway" "ngw_egress_public" { # one for each az - count = "${length(var.az_postfixes)}" - allocation_id = "${element(aws_eip.eip_egress_public.*.id,count.index)}" - subnet_id = "${element(aws_subnet.subn_egress_public.*.id,count.index)}" + count = length(var.az_postfixes) + allocation_id = element(aws_eip.eip_egress_public.*.id, count.index) + subnet_id = element(aws_subnet.subn_egress_public.*.id, count.index) } + diff --git a/modules/networking/subn_public.tf b/modules/networking/subn_public.tf index 8d6a54d..68a59de 100644 --- a/modules/networking/subn_public.tf +++ b/modules/networking/subn_public.tf @@ -1,41 +1,42 @@ # PUBLIC subnets resource "aws_subnet" "subn_public" { # one for each az - count = "${length(var.az_postfixes)}" - vpc_id = "${aws_vpc.vpc_main.id}" + count = length(var.az_postfixes) + vpc_id = aws_vpc.vpc_main.id cidr_block = "${var.ip_prefix}.${128 + count.index}.0/24" - availability_zone = "${var.region}${element(var.az_postfixes,count.index)}" + availability_zone = "${var.region}${element(var.az_postfixes, count.index)}" - tags { - Name = "MNG-${var.stack_name}-${var.region}${element(var.az_postfixes,count.index)}-SUBN-public" + tags = { + Name = "MNG-${var.stack_name}-${var.region}${element(var.az_postfixes, count.index)}-SUBN-public" } } # route-table for the public subnet resource "aws_route_table" "rtb_public" { - vpc_id = "${aws_vpc.vpc_main.id}" + vpc_id = aws_vpc.vpc_main.id # one for each az - count = "${length(var.az_postfixes)}" + count = length(var.az_postfixes) - tags { - Name = "MNG-${var.stack_name}-${var.region}${element(var.az_postfixes,count.index)}-RTB-public" + tags = { + Name = "MNG-${var.stack_name}-${var.region}${element(var.az_postfixes, count.index)}-RTB-public" } } # association between the public subnets and the public routetable resource "aws_route_table_association" "rtassoc_public" { # one for each az - count = "${length(var.az_postfixes)}" - subnet_id = "${element(aws_subnet.subn_public.*.id,count.index)}" - route_table_id = "${element(aws_route_table.rtb_public.*.id,count.index)}" + count = length(var.az_postfixes) + subnet_id = element(aws_subnet.subn_public.*.id, count.index) + route_table_id = element(aws_route_table.rtb_public.*.id, count.index) } # this is the route to the internet resource "aws_route" "r_public_inet" { # one for each az - count = "${length(var.az_postfixes)}" - route_table_id = "${element(aws_route_table.rtb_public.*.id,count.index)}" + count = length(var.az_postfixes) + route_table_id = element(aws_route_table.rtb_public.*.id, count.index) destination_cidr_block = "0.0.0.0/0" - gateway_id = "${aws_internet_gateway.igw_main.id}" + gateway_id = aws_internet_gateway.igw_main.id } + diff --git a/modules/networking/subn_services.tf b/modules/networking/subn_services.tf index 8372413..ae43c28 100644 --- a/modules/networking/subn_services.tf +++ b/modules/networking/subn_services.tf @@ -1,41 +1,42 @@ # SERVICES subnets resource "aws_subnet" "subn_services" { # one for each az - count = "${length(var.az_postfixes)}" - vpc_id = "${aws_vpc.vpc_main.id}" + count = length(var.az_postfixes) + vpc_id = aws_vpc.vpc_main.id cidr_block = "${var.ip_prefix}.${0 + count.index * 32}.0/19" - availability_zone = "${var.region}${element(var.az_postfixes,count.index)}" + availability_zone = "${var.region}${element(var.az_postfixes, count.index)}" - tags { - Name = "${var.stack_name}-${var.region}${element(var.az_postfixes,count.index)}-SUBN-services" + tags = { + Name = "${var.stack_name}-${var.region}${element(var.az_postfixes, count.index)}-SUBN-services" } } # route-table for the services subnets resource "aws_route_table" "rtb_services" { - vpc_id = "${aws_vpc.vpc_main.id}" + vpc_id = aws_vpc.vpc_main.id # one for each az - count = "${length(var.az_postfixes)}" + count = length(var.az_postfixes) - tags { - Name = "${var.stack_name}-${var.region}${element(var.az_postfixes,count.index)}-RTB-services" + tags = { + Name = "${var.stack_name}-${var.region}${element(var.az_postfixes, count.index)}-RTB-services" } } # association between the services subnets and the services routetable resource "aws_route_table_association" "rtassoc_services" { # one for each az - count = "${length(var.az_postfixes)}" - subnet_id = "${element(aws_subnet.subn_services.*.id,count.index)}" - route_table_id = "${element(aws_route_table.rtb_services.*.id,count.index)}" + count = length(var.az_postfixes) + subnet_id = element(aws_subnet.subn_services.*.id, count.index) + route_table_id = element(aws_route_table.rtb_services.*.id, count.index) } # this is the route to the egress_aws natgateway resource "aws_route" "r_services_egress_aws_ngw" { # one for each az - count = "${length(var.az_postfixes)}" - route_table_id = "${element(aws_route_table.rtb_services.*.id,count.index)}" + count = length(var.az_postfixes) + route_table_id = element(aws_route_table.rtb_services.*.id, count.index) destination_cidr_block = "0.0.0.0/0" - nat_gateway_id = "${element(aws_nat_gateway.ngw_egress_aws.*.id,count.index)}" + nat_gateway_id = element(aws_nat_gateway.ngw_egress_aws.*.id, count.index) } + diff --git a/modules/networking/vars.tf b/modules/networking/vars.tf index bd81c85..11cbbe1 100644 --- a/modules/networking/vars.tf +++ b/modules/networking/vars.tf @@ -10,7 +10,7 @@ variable "stack_name" { variable "az_postfixes" { description = "list of AZ postfixes" - type = "list" + type = list(string) default = ["a", "b", "c"] } @@ -30,9 +30,29 @@ variable "unique_postfix" { variable "aws_ip_address_ranges" { description = "List of ip-ranges for accessing aws services (S3, EC2, ElastiCache, ..) in us-east-1 see: http://docs.aws.amazon.com/general/latest/gr/aws-ip-ranges.html" - type = "list" + type = list(string) - default = ["18.0.0.0/8", "23.0.0.0/8", "34.0.0.0/8", "35.0.0.0/8", "50.0.0.0/8", "52.0.0.0/8", "54.0.0.0/8", "67.0.0.0/8", "72.0.0.0/8", "75.0.0.0/8", "107.0.0.0/8", "174.0.0.0/8", "184.0.0.0/8", "204.0.0.0/8", "216.0.0.0/8", "172.0.0.0/8", "176.0.0.0/8", "205.0.0.0/8", "207.0.0.0/8", + default = [ + "18.0.0.0/8", + "23.0.0.0/8", + "34.0.0.0/8", + "35.0.0.0/8", + "50.0.0.0/8", + "52.0.0.0/8", + "54.0.0.0/8", + "67.0.0.0/8", + "72.0.0.0/8", + "75.0.0.0/8", + "107.0.0.0/8", + "174.0.0.0/8", + "184.0.0.0/8", + "204.0.0.0/8", + "216.0.0.0/8", + "172.0.0.0/8", + "176.0.0.0/8", + "205.0.0.0/8", + "207.0.0.0/8", "192.30.253.0/24", ] # HACK: "192.30.253.0/24" is for github } + diff --git a/modules/networking/versions.tf b/modules/networking/versions.tf new file mode 100644 index 0000000..ac97c6a --- /dev/null +++ b/modules/networking/versions.tf @@ -0,0 +1,4 @@ + +terraform { + required_version = ">= 0.12" +} diff --git a/modules/networking/vpc.tf b/modules/networking/vpc.tf index c73db24..60d780b 100644 --- a/modules/networking/vpc.tf +++ b/modules/networking/vpc.tf @@ -5,7 +5,7 @@ resource "aws_vpc" "vpc_main" { enable_dns_hostnames = "true" enable_dns_support = "true" - tags { + tags = { Name = "${var.stack_name}-VPC-main" } } @@ -17,23 +17,24 @@ locals { #dhcp options resource "aws_vpc_dhcp_options" "vpc_main_dns" { domain_name = "nomad-${var.region}" - domain_name_servers = ["${local.dns_ip}", "AmazonProvidedDNS"] + domain_name_servers = [local.dns_ip, "AmazonProvidedDNS"] - tags { + tags = { Name = "${var.stack_name}-DOPT-vpc" } } resource "aws_vpc_dhcp_options_association" "vpc_main_dns_resolver" { - vpc_id = "${aws_vpc.vpc_main.id}" - dhcp_options_id = "${aws_vpc_dhcp_options.vpc_main_dns.id}" + vpc_id = aws_vpc.vpc_main.id + dhcp_options_id = aws_vpc_dhcp_options.vpc_main_dns.id } # the internet gateway resource "aws_internet_gateway" "igw_main" { - vpc_id = "${aws_vpc.vpc_main.id}" + vpc_id = aws_vpc.vpc_main.id - tags { + tags = { Name = "${var.stack_name}-IGW-main" } } + diff --git a/modules/nomad-datacenter/access_full.tf b/modules/nomad-datacenter/access_full.tf index f41ee79..22a61b6 100644 --- a/modules/nomad-datacenter/access_full.tf +++ b/modules/nomad-datacenter/access_full.tf @@ -1,11 +1,12 @@ # Add policy to the already created iam role of the nomad clients in the nomad cluster module. # Policy-attachment that grants full access to all AWS services for nomad clients resource "aws_iam_role_policy_attachment" "irpa_full_access" { - role = "${module.data_center.iam_role_id}" - policy_arn = "${aws_iam_policy.ip_full_access.arn}" + role = module.data_center.iam_role_id + policy_arn = aws_iam_policy.ip_full_access.arn } resource "aws_iam_policy" "ip_full_access" { name = "${var.stack_name}-${var.datacenter_name}${var.unique_postfix}-full" - policy = "${file("${path.module}/access_full.json")}" + policy = file("${path.module}/access_full.json") } + diff --git a/modules/nomad-datacenter/alb_ingress_attachment.tf b/modules/nomad-datacenter/alb_ingress_attachment.tf index 88e5ff7..35150a4 100644 --- a/modules/nomad-datacenter/alb_ingress_attachment.tf +++ b/modules/nomad-datacenter/alb_ingress_attachment.tf @@ -5,18 +5,18 @@ # Define autoscaling attachments to connect the ingress-controller target group with the autoscaling group having the ingress-contoller instances. resource "aws_autoscaling_attachment" "asga_ingress_controller" { - count = "${var.attach_ingress_alb_listener}" - autoscaling_group_name = "${module.data_center.asg_name}" - alb_target_group_arn = "${aws_alb_target_group.tgr_ingress_controller.arn}" + count = var.attach_ingress_alb_listener ? 1 : 0 + autoscaling_group_name = module.data_center.asg_name + alb_target_group_arn = aws_alb_target_group.tgr_ingress_controller[0].arn } # Targetgroup that points to the ingress-controller (i.e. fabio) port resource "aws_alb_target_group" "tgr_ingress_controller" { - count = "${var.attach_ingress_alb_listener}" + count = var.attach_ingress_alb_listener ? 1 : 0 name = "${var.datacenter_name}-inctl${var.unique_postfix}" - port = "${var.ingress_controller_port}" + port = var.ingress_controller_port protocol = "HTTP" - vpc_id = "${var.vpc_id}" + vpc_id = var.vpc_id health_check { interval = 15 @@ -28,19 +28,19 @@ resource "aws_alb_target_group" "tgr_ingress_controller" { unhealthy_threshold = 2 } - tags { + tags = { Name = "${var.stack_name}-${var.datacenter_name}-ingress-controller${var.unique_postfix}" } } # listener rule for HTTPS resource "aws_alb_listener_rule" "alr_ingress_https" { - count = "${var.attach_ingress_alb_listener}" - listener_arn = "${var.alb_ingress_https_listener_arn}" + count = var.attach_ingress_alb_listener ? 1 : 0 + listener_arn = var.alb_ingress_https_listener_arn action { type = "forward" - target_group_arn = "${aws_alb_target_group.tgr_ingress_controller.arn}" + target_group_arn = aws_alb_target_group.tgr_ingress_controller[0].arn } condition { @@ -48,3 +48,4 @@ resource "aws_alb_listener_rule" "alr_ingress_https" { values = ["/*"] } } + diff --git a/modules/nomad-datacenter/datacenter.tf b/modules/nomad-datacenter/datacenter.tf index 7a9786d..4511921 100644 --- a/modules/nomad-datacenter/datacenter.tf +++ b/modules/nomad-datacenter/datacenter.tf @@ -1,54 +1,58 @@ # reading values from the node_scaling_cfg locals { - min = "${lookup(var.node_scaling_cfg,"min","INVALID")}" - max = "${lookup(var.node_scaling_cfg,"max","INVALID")}" - desired_capacity = "${lookup(var.node_scaling_cfg,"desired_capacity","INVALID")}" + min = lookup(var.node_scaling_cfg, "min", "INVALID") + max = lookup(var.node_scaling_cfg, "max", "INVALID") + desired_capacity = lookup(var.node_scaling_cfg, "desired_capacity", "INVALID") cluster_name = "${local.base_cluster_name}${var.unique_postfix}" + + default_tags = [ + { + "key" = "datacenter" + "value" = var.datacenter_name + "propagate_at_launch" = "true" + }, + { + "key" = "node-type" + "value" = "client" + "propagate_at_launch" = "true" + }, + ] } module "data_center" { - source = "git::https://github.com/hashicorp/terraform-aws-nomad.git//modules/nomad-cluster?ref=v0.4.5" + source = "git::https://github.com/hashicorp/terraform-aws-nomad.git//modules/nomad-cluster?ref=v0.5.0" - cluster_name = "${local.cluster_name}" - cluster_tag_value = "${local.cluster_name}" - instance_type = "${var.instance_type}" - ami_id = "${var.ami_id}" - vpc_id = "${var.vpc_id}" - subnet_ids = "${var.subnet_ids}" - allowed_ssh_cidr_blocks = "${var.allowed_ssh_cidr_blocks}" - user_data = "${data.template_file.user_data_data_center.rendered}" - ssh_key_name = "${var.ssh_key_name}" + cluster_name = local.cluster_name + cluster_tag_value = local.cluster_name + instance_type = var.instance_type + ami_id = var.ami_id + vpc_id = var.vpc_id + subnet_ids = var.subnet_ids + allowed_ssh_cidr_blocks = var.allowed_ssh_cidr_blocks + user_data = data.template_file.user_data_data_center.rendered + ssh_key_name = var.ssh_key_name associate_public_ip_address = false # To keep the example simple, we are using a fixed-size cluster. In real-world usage, you could use auto scaling # policies to dynamically resize the cluster in response to load. - min_size = "${local.min}" - max_size = "${local.max}" - desired_capacity = "${local.desired_capacity}" + min_size = local.min + max_size = local.max + desired_capacity = local.desired_capacity security_groups = [ - "${aws_security_group.sg_datacenter.id}", + aws_security_group.sg_datacenter.id, ] + # Access over cidr blocks is disabled here. # The need access for the nomad-server is granted over the # aws_security_group.sg_nomad_server_access.id. allowed_inbound_cidr_blocks = ["0.0.0.0/32"] + # propagate tags to the instances - tags = [ - { - "key" = "datacenter" - "value" = "${var.datacenter_name}" - "propagate_at_launch" = "true" - }, - { - "key" = "node-type" - "value" = "client" - "propagate_at_launch" = "true" - }, - "${var.additional_instance_tags}", - ] + tags = concat(local.default_tags,var.additional_instance_tags) + # Configuration for additional ebs_block devices - ebs_block_devices = "${var.ebs_block_devices}" + ebs_block_devices = var.ebs_block_devices } # --------------------------------------------------------------------------------------------------------------------- @@ -57,26 +61,28 @@ module "data_center" { # the Consul AWS Module's consul-iam-policies module. # --------------------------------------------------------------------------------------------------------------------- module "consul_iam_policies_datacenter" { - source = "git::https://github.com/hashicorp/terraform-aws-consul.git//modules/consul-iam-policies?ref=v0.3.1" + source = "git::https://github.com/hashicorp/terraform-aws-consul.git//modules/consul-iam-policies?ref=v0.7.0" - iam_role_id = "${module.data_center.iam_role_id}" + iam_role_id = module.data_center.iam_role_id } -data "aws_caller_identity" "aws_account_id" {} +data "aws_caller_identity" "aws_account_id" { +} # This script will configure and start Consul and Nomad data "template_file" "user_data_data_center" { - template = "${file("${path.module}/user-data-nomad-client.sh")}" + template = file("${path.module}/user-data-nomad-client.sh") - vars { - cluster_tag_key = "${var.consul_cluster_tag_key}" - cluster_tag_value = "${var.consul_cluster_tag_value}" - datacenter = "${var.datacenter_name}" - efs_dns_name = "${var.efs_dns_name}" - map_bucket_name = "${var.map_bucket_name}" - device_to_mount_target_map = "${join(" ", var.device_to_mount_target_map)}" - fs_type = "${var.fs_type}" - aws_account_id = "${data.aws_caller_identity.aws_account_id.account_id}" - aws_region = "${var.aws_region}" + vars = { + cluster_tag_key = var.consul_cluster_tag_key + cluster_tag_value = var.consul_cluster_tag_value + datacenter = var.datacenter_name + efs_dns_name = var.efs_dns_name + map_bucket_name = var.map_bucket_name + device_to_mount_target_map = join(" ", var.device_to_mount_target_map) + fs_type = var.fs_type + aws_account_id = data.aws_caller_identity.aws_account_id.account_id + aws_region = var.aws_region } } + diff --git a/modules/nomad-datacenter/datacenter_sg.tf b/modules/nomad-datacenter/datacenter_sg.tf index 8e759b3..522fe18 100644 --- a/modules/nomad-datacenter/datacenter_sg.tf +++ b/modules/nomad-datacenter/datacenter_sg.tf @@ -6,11 +6,11 @@ # Every client can get requests for the automatically assigned ports for each nomad job, # for example fabio will use consul to figure out the port mapping and direct requests directly to this ports. resource "aws_security_group" "sg_datacenter" { - vpc_id = "${var.vpc_id}" + vpc_id = var.vpc_id name = "${var.stack_name}-${var.datacenter_name}${var.unique_postfix}" description = "Security group that allows ingress access for the nomad service handling and docker ports." - tags { + tags = { Name = "${var.stack_name}-${var.datacenter_name}${var.unique_postfix}" } @@ -28,5 +28,6 @@ resource "aws_security_group_rule" "sgr_datacenter_eg_all" { to_port = 0 protocol = "-1" cidr_blocks = ["0.0.0.0/0"] - security_group_id = "${aws_security_group.sg_datacenter.id}" + security_group_id = aws_security_group.sg_datacenter.id } + diff --git a/modules/nomad-datacenter/ecr.tf b/modules/nomad-datacenter/ecr.tf index 64430df..b2542e1 100644 --- a/modules/nomad-datacenter/ecr.tf +++ b/modules/nomad-datacenter/ecr.tf @@ -2,13 +2,13 @@ # Policy-attachment that grants read access to AWS ECR for nomad clients resource "aws_iam_role_policy_attachment" "irpa_ecr_read_access" { # FIXME: Because of this constellation it is not possible to provide the ECR access configuration as module. - role = "${module.data_center.iam_role_id}" - policy_arn = "${aws_iam_policy.ip_ecr_read_access.arn}" + role = module.data_center.iam_role_id + policy_arn = aws_iam_policy.ip_ecr_read_access.arn } resource "aws_iam_policy" "ip_ecr_read_access" { name = "${var.stack_name}-${var.datacenter_name}${var.unique_postfix}" - policy = "${data.aws_iam_policy_document.ipd_ecr_read_access.json}" + policy = data.aws_iam_policy_document.ipd_ecr_read_access.json } data "aws_iam_policy_document" "ipd_ecr_read_access" { @@ -23,3 +23,4 @@ data "aws_iam_policy_document" "ipd_ecr_read_access" { resources = ["*"] } } + diff --git a/modules/nomad-datacenter/main.tf b/modules/nomad-datacenter/main.tf index 402b629..a5729ce 100644 --- a/modules/nomad-datacenter/main.tf +++ b/modules/nomad-datacenter/main.tf @@ -1,11 +1,6 @@ -# Terraform 0.9.5 suffered from https://github.com/hashicorp/terraform/issues/14399, which causes this template the -# conditionals in this template to fail. -terraform { - required_version = ">= 0.9.3, != 0.9.5" -} - locals { - short_dc_name = "${format("%.10s",var.datacenter_name)}" + short_dc_name = format("%.10s", var.datacenter_name) cluster_prefix = "${var.stack_name}-NMC" base_cluster_name = "${local.cluster_prefix}-${local.short_dc_name}" } + diff --git a/modules/nomad-datacenter/outputs.tf b/modules/nomad-datacenter/outputs.tf index 17b8b25..953fe19 100644 --- a/modules/nomad-datacenter/outputs.tf +++ b/modules/nomad-datacenter/outputs.tf @@ -1,27 +1,28 @@ output "num_nodes" { - value = "${module.data_center.cluster_size}" + value = module.data_center.cluster_size } output "asg_name" { - value = "${module.data_center.asg_name}" + value = module.data_center.asg_name } output "aws_region" { - value = "${var.aws_region}" + value = var.aws_region } output "cluster_tag_value" { - value = "${module.data_center.cluster_tag_value}" + value = module.data_center.cluster_tag_value } output "cluster_prefix" { - value = "${local.cluster_prefix}" + value = local.cluster_prefix } output "sg_datacenter_id" { - value = "${aws_security_group.sg_datacenter.id}" + value = aws_security_group.sg_datacenter.id } output "alb_https_targetgroup_arn" { - value = "${aws_alb_target_group.tgr_ingress_controller.*.arn}" + value = aws_alb_target_group.tgr_ingress_controller.*.arn } + diff --git a/modules/nomad-datacenter/vars.tf b/modules/nomad-datacenter/vars.tf index 9958f02..c9a4db9 100644 --- a/modules/nomad-datacenter/vars.tf +++ b/modules/nomad-datacenter/vars.tf @@ -21,7 +21,7 @@ variable "consul_cluster_tag_value" { variable "subnet_ids" { description = "Subnet id's for nomad client nodes providing this data-center." - type = "list" + type = list(string) } #### Optional Variables ############################################ @@ -62,7 +62,7 @@ variable "datacenter_name" { variable "node_scaling_cfg" { description = "Scaling configuration for the nomad nodes to deploy for this datacenter. You can deploy as many as you need to run your jobs." - type = "map" + type = map(string) default = { "min" = 1 @@ -83,7 +83,7 @@ variable "ssh_key_name" { variable "allowed_ssh_cidr_blocks" { description = "A list of cidr block from which inbound ssh traffic should be allowed for this datacenter." - type = "list" + type = list(string) default = [] } @@ -113,8 +113,7 @@ variable "map_bucket_name" { # }] variable "ebs_block_devices" { description = "List of ebs volume definitions for those ebs_volumes that should be added to the instances created with the EC2 launch-configurationd. Each element in the list is a map containing keys defined for ebs_block_device (see: https://www.terraform.io/docs/providers/aws/r/launch_configuration.html#ebs_block_device." - type = "list" - + type = any default = [] } @@ -125,7 +124,7 @@ variable "ebs_block_devices" { # Example: ["/dev/xvde:/mnt/map1","/dev/xvdf:/mnt/map2"] variable "device_to_mount_target_map" { description = "List of device to mount target entries." - type = "list" + type = list(string) default = [] } @@ -152,6 +151,11 @@ variable "fs_type" { # }] variable "additional_instance_tags" { description = "List of tags to add to the datacenter instances. The entries of the list are maps consiting of key, value and propagate at launch." - type = "list" + type = list(object({ + key = string + value = string + propagate_at_launch = bool + })) default = [] } + diff --git a/modules/nomad-datacenter/versions.tf b/modules/nomad-datacenter/versions.tf new file mode 100644 index 0000000..ac97c6a --- /dev/null +++ b/modules/nomad-datacenter/versions.tf @@ -0,0 +1,4 @@ + +terraform { + required_version = ">= 0.12" +} diff --git a/modules/nomad/main.tf b/modules/nomad/main.tf index 0335d23..df6d9bd 100644 --- a/modules/nomad/main.tf +++ b/modules/nomad/main.tf @@ -1,10 +1,4 @@ -# Terraform 0.9.5 suffered from https://github.com/hashicorp/terraform/issues/14399, which causes this template the -# conditionals in this template to fail. -terraform { - required_version = ">= 0.9.3, != 0.9.5" -} - locals { - short_dc_name = "${format("%.10s",var.datacenter_name)}" + short_dc_name = format("%.10s", var.datacenter_name) base_cluster_name = "${var.stack_name}-NMS-${local.short_dc_name}" -} +} \ No newline at end of file diff --git a/modules/nomad/outputs.tf b/modules/nomad/outputs.tf index ef2d1bb..45bfefa 100644 --- a/modules/nomad/outputs.tf +++ b/modules/nomad/outputs.tf @@ -1,35 +1,36 @@ output "num_nomad_servers" { - value = "${module.nomad_servers.cluster_size}" + value = module.nomad_servers.cluster_size } output "asg_name_nomad_servers" { - value = "${module.nomad_servers.asg_name}" + value = module.nomad_servers.asg_name } output "launch_config_name_nomad_servers" { - value = "${module.nomad_servers.launch_config_name}" + value = module.nomad_servers.launch_config_name } output "iam_role_arn_nomad_servers" { - value = "${module.nomad_servers.iam_role_arn}" + value = module.nomad_servers.iam_role_arn } output "iam_role_id_nomad_servers" { - value = "${module.nomad_servers.iam_role_id}" + value = module.nomad_servers.iam_role_id } output "security_group_id_nomad_servers" { - value = "${aws_security_group.sg_server.id}" + value = aws_security_group.sg_server.id } output "aws_region" { - value = "${var.aws_region}" + value = var.aws_region } output "nomad_servers_cluster_tag_key" { - value = "${module.nomad_servers.cluster_tag_key}" + value = module.nomad_servers.cluster_tag_key } output "nomad_servers_cluster_tag_value" { - value = "${module.nomad_servers.cluster_tag_value}" + value = module.nomad_servers.cluster_tag_value } + diff --git a/modules/nomad/server_sg.tf b/modules/nomad/server_sg.tf index b558da6..2c9e888 100644 --- a/modules/nomad/server_sg.tf +++ b/modules/nomad/server_sg.tf @@ -1,9 +1,9 @@ resource "aws_security_group" "sg_server" { - vpc_id = "${var.vpc_id}" + vpc_id = var.vpc_id name = "${local.base_cluster_name}-SG${var.unique_postfix}" description = "Security group for the nomad-server." - tags { + tags = { Name = "${local.base_cluster_name}-SG${var.unique_postfix}" } @@ -21,7 +21,7 @@ resource "aws_security_group_rule" "sgr_server_eg_all" { to_port = 0 protocol = "-1" cidr_blocks = ["0.0.0.0/0"] - security_group_id = "${aws_security_group.sg_server.id}" + security_group_id = aws_security_group.sg_server.id } # Inject rule into sg of nomad server to get access over ports 4646..4648 @@ -32,8 +32,8 @@ resource "aws_security_group_rule" "sgr_server_to_server_ig4646_4648" { to_port = 4648 protocol = "tcp" - source_security_group_id = "${aws_security_group.sg_server.id}" - security_group_id = "${aws_security_group.sg_server.id}" + source_security_group_id = aws_security_group.sg_server.id + security_group_id = aws_security_group.sg_server.id } # Inject rule into sg of nomad server to get access over ports 4648 @@ -44,6 +44,7 @@ resource "aws_security_group_rule" "sgr_serversto_server_ig4648" { to_port = 4648 protocol = "udp" - source_security_group_id = "${aws_security_group.sg_server.id}" - security_group_id = "${aws_security_group.sg_server.id}" + source_security_group_id = aws_security_group.sg_server.id + security_group_id = aws_security_group.sg_server.id } + diff --git a/modules/nomad/servers.tf b/modules/nomad/servers.tf index 9640017..64155e0 100644 --- a/modules/nomad/servers.tf +++ b/modules/nomad/servers.tf @@ -1,8 +1,8 @@ # reading values from the node_scaling_cfg locals { - min = "${lookup(var.node_scaling_cfg,"min","INVALID")}" - max = "${lookup(var.node_scaling_cfg,"max","INVALID")}" - desired_capacity = "${lookup(var.node_scaling_cfg,"desired_capacity","INVALID")}" + min = lookup(var.node_scaling_cfg, "min", "INVALID") + max = lookup(var.node_scaling_cfg, "max", "INVALID") + desired_capacity = lookup(var.node_scaling_cfg, "desired_capacity", "INVALID") cluster_name = "${local.base_cluster_name}${var.unique_postfix}" } @@ -10,25 +10,25 @@ locals { # DEPLOY THE NOMAD SERVER NODES # --------------------------------------------------------------------------------------------------------------------- module "nomad_servers" { - source = "git::https://github.com/hashicorp/terraform-aws-nomad.git//modules/nomad-cluster?ref=v0.4.5" + source = "git::https://github.com/hashicorp/terraform-aws-nomad.git//modules/nomad-cluster?ref=v0.5.0" - cluster_name = "${local.cluster_name}" - cluster_tag_value = "${local.cluster_name}" - instance_type = "${var.instance_type}" - ami_id = "${var.ami_id}" - vpc_id = "${var.vpc_id}" - subnet_ids = "${var.subnet_ids}" - allowed_ssh_cidr_blocks = "${var.allowed_ssh_cidr_blocks}" - user_data = "${data.template_file.user_data_server.rendered}" - ssh_key_name = "${var.ssh_key_name}" + cluster_name = local.cluster_name + cluster_tag_value = local.cluster_name + instance_type = var.instance_type + ami_id = var.ami_id + vpc_id = var.vpc_id + subnet_ids = var.subnet_ids + allowed_ssh_cidr_blocks = var.allowed_ssh_cidr_blocks + user_data = data.template_file.user_data_server.rendered + ssh_key_name = var.ssh_key_name associate_public_ip_address = false # You should typically use a fixed size of 3 or 5 for your Nomad server cluster - min_size = "${local.min}" - max_size = "${local.max}" - desired_capacity = "${local.desired_capacity}" + min_size = local.min + max_size = local.max + desired_capacity = local.desired_capacity - security_groups = ["${aws_security_group.sg_server.id}"] + security_groups = [aws_security_group.sg_server.id] # Access over cidr blocks is disabled here. # The need access for the nomad-server is granted over the @@ -39,7 +39,7 @@ module "nomad_servers" { tags = [ { "key" = "datacenter" - "value" = "${var.datacenter_name}" + "value" = var.datacenter_name "propagate_at_launch" = "true" }, { @@ -56,22 +56,24 @@ module "nomad_servers" { # the Consul AWS Module's consul-iam-policies module. # --------------------------------------------------------------------------------------------------------------------- module "consul_iam_policies_servers" { - source = "git::https://github.com/hashicorp/terraform-aws-consul.git//modules/consul-iam-policies?ref=v0.3.1" - iam_role_id = "${module.nomad_servers.iam_role_id}" + source = "git::https://github.com/hashicorp/terraform-aws-consul.git//modules/consul-iam-policies?ref=v0.7.0" + iam_role_id = module.nomad_servers.iam_role_id } -data "aws_caller_identity" "aws_account_id" {} +data "aws_caller_identity" "aws_account_id" { +} # This script will configure and start Consul and Nomad data "template_file" "user_data_server" { - template = "${file("${path.module}/user-data-nomad-server.sh")}" + template = file("${path.module}/user-data-nomad-server.sh") - vars { - num_servers = "${local.desired_capacity}" - cluster_tag_key = "${var.consul_cluster_tag_key}" - cluster_tag_value = "${var.consul_cluster_tag_value}" - datacenter = "${var.datacenter_name}" - aws_account_id = "${data.aws_caller_identity.aws_account_id.account_id}" - aws_region = "${var.aws_region}" + vars = { + num_servers = local.desired_capacity + cluster_tag_key = var.consul_cluster_tag_key + cluster_tag_value = var.consul_cluster_tag_value + datacenter = var.datacenter_name + aws_account_id = data.aws_caller_identity.aws_account_id.account_id + aws_region = var.aws_region } } + diff --git a/modules/nomad/vars.tf b/modules/nomad/vars.tf index c5294fb..c9c2108 100644 --- a/modules/nomad/vars.tf +++ b/modules/nomad/vars.tf @@ -9,7 +9,7 @@ variable "vpc_id" { variable "subnet_ids" { description = "Ids of the subnets to deploy the nomad servers into." - type = "list" + type = list(string) } variable "consul_cluster_tag_key" { @@ -20,10 +20,6 @@ variable "consul_cluster_tag_value" { description = "This variable defines the value of the tag defined by consul_cluster_tag_key. This is used to find the consul servers (see: consul_cluster_tag_key)." } -variable "consul_cluster_security_group_id" { - description = "Id of the security-group of the consul server." -} - #### Optional Variables ############################################ variable "env_name" { description = "name of the environment (i.e. prod)" @@ -57,7 +53,7 @@ variable "unique_postfix" { variable "allowed_ssh_cidr_blocks" { description = "A list of cidr block from which inbound ssh traffic should be allowed." - type = "list" + type = list(string) default = [] } @@ -68,7 +64,7 @@ variable "datacenter_name" { variable "node_scaling_cfg" { description = "Scaling configuration for the nomad servers." - type = "map" + type = map(string) default = { "min" = 3 diff --git a/modules/nomad/versions.tf b/modules/nomad/versions.tf new file mode 100644 index 0000000..ac97c6a --- /dev/null +++ b/modules/nomad/versions.tf @@ -0,0 +1,4 @@ + +terraform { + required_version = ">= 0.12" +} diff --git a/modules/sgrules/sg_consul_nomad_clients.tf b/modules/sgrules/sg_consul_nomad_clients.tf index 050c949..ae6f171 100644 --- a/modules/sgrules/sg_consul_nomad_clients.tf +++ b/modules/sgrules/sg_consul_nomad_clients.tf @@ -16,8 +16,8 @@ resource "aws_security_group_rule" "sgr_public_services_to_consul_tcp" { from_port = 8300 to_port = 8302 protocol = "tcp" - source_security_group_id = "${var.sg_id_public_services_dc}" - security_group_id = "${var.sg_id_consul}" + source_security_group_id = var.sg_id_public_services_dc + security_group_id = var.sg_id_consul } # rule granting access from private-services data-center consul on ports @@ -29,8 +29,8 @@ resource "aws_security_group_rule" "sgr_private_services_to_consul_tcp" { from_port = 8300 to_port = 8302 protocol = "tcp" - source_security_group_id = "${var.sg_id_private_services_dc}" - security_group_id = "${var.sg_id_consul}" + source_security_group_id = var.sg_id_private_services_dc + security_group_id = var.sg_id_consul } # rule granting access from content-connector data-center consul on ports @@ -42,8 +42,8 @@ resource "aws_security_group_rule" "sgr_content_connector_to_consul_tcp" { from_port = 8300 to_port = 8302 protocol = "tcp" - source_security_group_id = "${var.sg_id_content_connector_dc}" - security_group_id = "${var.sg_id_consul}" + source_security_group_id = var.sg_id_content_connector_dc + security_group_id = var.sg_id_consul } # rule granting access from backoffice data-center consul on ports @@ -55,8 +55,8 @@ resource "aws_security_group_rule" "sgr_backoffice_to_consul_tcp" { from_port = 8300 to_port = 8302 protocol = "tcp" - source_security_group_id = "${var.sg_id_backoffice_dc}" - security_group_id = "${var.sg_id_consul}" + source_security_group_id = var.sg_id_backoffice_dc + security_group_id = var.sg_id_consul } # rule granting access from public-services data-center consul on ports @@ -68,8 +68,8 @@ resource "aws_security_group_rule" "sgr_public_services_to_consul_udp" { from_port = 8301 to_port = 8302 protocol = "udp" - source_security_group_id = "${var.sg_id_public_services_dc}" - security_group_id = "${var.sg_id_consul}" + source_security_group_id = var.sg_id_public_services_dc + security_group_id = var.sg_id_consul } # rule granting access from private-services data-center consul on ports @@ -81,8 +81,8 @@ resource "aws_security_group_rule" "sgr_private_services_to_consul_udp" { from_port = 8301 to_port = 8302 protocol = "udp" - source_security_group_id = "${var.sg_id_private_services_dc}" - security_group_id = "${var.sg_id_consul}" + source_security_group_id = var.sg_id_private_services_dc + security_group_id = var.sg_id_consul } # rule granting access from content-connector data-center consul on ports @@ -94,8 +94,8 @@ resource "aws_security_group_rule" "sgr_content_connector_to_consul_udp" { from_port = 8301 to_port = 8302 protocol = "udp" - source_security_group_id = "${var.sg_id_content_connector_dc}" - security_group_id = "${var.sg_id_consul}" + source_security_group_id = var.sg_id_content_connector_dc + security_group_id = var.sg_id_consul } # rule granting access from backoffice data-center consul on ports @@ -107,8 +107,8 @@ resource "aws_security_group_rule" "sgr_backoffice_to_consul_udp" { from_port = 8301 to_port = 8302 protocol = "udp" - source_security_group_id = "${var.sg_id_backoffice_dc}" - security_group_id = "${var.sg_id_consul}" + source_security_group_id = var.sg_id_backoffice_dc + security_group_id = var.sg_id_consul } # rule granting access from public-services data-center consul on ports @@ -120,8 +120,8 @@ resource "aws_security_group_rule" "sgr_public_services_to_consul_http" { from_port = 8500 to_port = 8500 protocol = "tcp" - source_security_group_id = "${var.sg_id_public_services_dc}" - security_group_id = "${var.sg_id_consul}" + source_security_group_id = var.sg_id_public_services_dc + security_group_id = var.sg_id_consul } # rule granting access from private-services data-center consul on ports @@ -133,8 +133,8 @@ resource "aws_security_group_rule" "sgr_private_services_to_consul_http" { from_port = 8500 to_port = 8500 protocol = "tcp" - source_security_group_id = "${var.sg_id_private_services_dc}" - security_group_id = "${var.sg_id_consul}" + source_security_group_id = var.sg_id_private_services_dc + security_group_id = var.sg_id_consul } # rule granting access from content-connector data-center consul on ports @@ -146,8 +146,8 @@ resource "aws_security_group_rule" "sgr_content_connector_to_consul_http" { from_port = 8500 to_port = 8500 protocol = "tcp" - source_security_group_id = "${var.sg_id_content_connector_dc}" - security_group_id = "${var.sg_id_consul}" + source_security_group_id = var.sg_id_content_connector_dc + security_group_id = var.sg_id_consul } # rule granting access from backoffice data-center consul on ports @@ -159,8 +159,8 @@ resource "aws_security_group_rule" "sgr_backoffice_to_consul_http" { from_port = 8500 to_port = 8500 protocol = "tcp" - source_security_group_id = "${var.sg_id_backoffice_dc}" - security_group_id = "${var.sg_id_consul}" + source_security_group_id = var.sg_id_backoffice_dc + security_group_id = var.sg_id_consul } # rule granting access from public-services data-center consul on ports @@ -172,8 +172,8 @@ resource "aws_security_group_rule" "sgr_public_services_to_consul_dns_tcp" { from_port = 8600 to_port = 8600 protocol = "tcp" - source_security_group_id = "${var.sg_id_public_services_dc}" - security_group_id = "${var.sg_id_consul}" + source_security_group_id = var.sg_id_public_services_dc + security_group_id = var.sg_id_consul } # rule granting access from private-services data-center consul on ports @@ -185,8 +185,8 @@ resource "aws_security_group_rule" "sgr_private_services_to_consul_dns_tcp" { from_port = 8600 to_port = 8600 protocol = "tcp" - source_security_group_id = "${var.sg_id_private_services_dc}" - security_group_id = "${var.sg_id_consul}" + source_security_group_id = var.sg_id_private_services_dc + security_group_id = var.sg_id_consul } # rule granting access from content-connector data-center consul on ports @@ -198,8 +198,8 @@ resource "aws_security_group_rule" "sgr_content_connector_to_consul_dns_tcp" { from_port = 8600 to_port = 8600 protocol = "tcp" - source_security_group_id = "${var.sg_id_content_connector_dc}" - security_group_id = "${var.sg_id_consul}" + source_security_group_id = var.sg_id_content_connector_dc + security_group_id = var.sg_id_consul } # rule granting access from backoffice data-center consul on ports @@ -211,8 +211,8 @@ resource "aws_security_group_rule" "sgr_backoffice_to_consul_dns_tcp" { from_port = 8600 to_port = 8600 protocol = "tcp" - source_security_group_id = "${var.sg_id_backoffice_dc}" - security_group_id = "${var.sg_id_consul}" + source_security_group_id = var.sg_id_backoffice_dc + security_group_id = var.sg_id_consul } # rule granting access from public-services data-center consul on ports @@ -224,8 +224,8 @@ resource "aws_security_group_rule" "sgr_public_services_to_consul_dns_udp" { from_port = 8600 to_port = 8600 protocol = "udp" - source_security_group_id = "${var.sg_id_public_services_dc}" - security_group_id = "${var.sg_id_consul}" + source_security_group_id = var.sg_id_public_services_dc + security_group_id = var.sg_id_consul } # rule granting access from private-services data-center consul on ports @@ -237,8 +237,8 @@ resource "aws_security_group_rule" "sgr_private_services_to_consul_dns_udp" { from_port = 8600 to_port = 8600 protocol = "udp" - source_security_group_id = "${var.sg_id_private_services_dc}" - security_group_id = "${var.sg_id_consul}" + source_security_group_id = var.sg_id_private_services_dc + security_group_id = var.sg_id_consul } # rule granting access from content-connector data-center consul on ports @@ -250,8 +250,8 @@ resource "aws_security_group_rule" "sgr_content_connector_to_consul_dns_udp" { from_port = 8600 to_port = 8600 protocol = "udp" - source_security_group_id = "${var.sg_id_content_connector_dc}" - security_group_id = "${var.sg_id_consul}" + source_security_group_id = var.sg_id_content_connector_dc + security_group_id = var.sg_id_consul } # rule granting access from backoffice data-center consul on ports @@ -263,6 +263,6 @@ resource "aws_security_group_rule" "sgr_backoffice_to_consul_dns_udp" { from_port = 8600 to_port = 8600 protocol = "udp" - source_security_group_id = "${var.sg_id_backoffice_dc}" - security_group_id = "${var.sg_id_consul}" -} + source_security_group_id = var.sg_id_backoffice_dc + security_group_id = var.sg_id_consul +} \ No newline at end of file diff --git a/modules/sgrules/sg_consul_nomad_server.tf b/modules/sgrules/sg_consul_nomad_server.tf index fc08ddb..724180d 100644 --- a/modules/sgrules/sg_consul_nomad_server.tf +++ b/modules/sgrules/sg_consul_nomad_server.tf @@ -16,8 +16,8 @@ resource "aws_security_group_rule" "sgr_nomad_server_to_consul_tcp" { from_port = 8300 to_port = 8302 protocol = "tcp" - source_security_group_id = "${var.sg_id_nomad_server}" - security_group_id = "${var.sg_id_consul}" + source_security_group_id = var.sg_id_nomad_server + security_group_id = var.sg_id_consul } # rule granting access from nomad server to consul on ports @@ -29,8 +29,8 @@ resource "aws_security_group_rule" "sgr_nomad_server_to_consul_udp" { from_port = 8301 to_port = 8302 protocol = "udp" - source_security_group_id = "${var.sg_id_nomad_server}" - security_group_id = "${var.sg_id_consul}" + source_security_group_id = var.sg_id_nomad_server + security_group_id = var.sg_id_consul } # rule granting access from nomad server to consul on ports @@ -42,8 +42,8 @@ resource "aws_security_group_rule" "sgr_nomad_server_to_consul_http" { from_port = 8500 to_port = 8500 protocol = "tcp" - source_security_group_id = "${var.sg_id_nomad_server}" - security_group_id = "${var.sg_id_consul}" + source_security_group_id = var.sg_id_nomad_server + security_group_id = var.sg_id_consul } # rule granting access from nomad server to consul on ports @@ -55,8 +55,8 @@ resource "aws_security_group_rule" "sgr_nomad_server_to_consul_dns_tcp" { from_port = 8600 to_port = 8600 protocol = "tcp" - source_security_group_id = "${var.sg_id_nomad_server}" - security_group_id = "${var.sg_id_consul}" + source_security_group_id = var.sg_id_nomad_server + security_group_id = var.sg_id_consul } # rule granting access from nomad server to consul on ports @@ -68,6 +68,7 @@ resource "aws_security_group_rule" "sgr_nomad_server_to_consul_dns_udp" { from_port = 8600 to_port = 8600 protocol = "udp" - source_security_group_id = "${var.sg_id_nomad_server}" - security_group_id = "${var.sg_id_consul}" + source_security_group_id = var.sg_id_nomad_server + security_group_id = var.sg_id_consul } + diff --git a/modules/sgrules/sg_consul_ui_alb.tf b/modules/sgrules/sg_consul_ui_alb.tf index 76a168b..a27b3ee 100644 --- a/modules/sgrules/sg_consul_ui_alb.tf +++ b/modules/sgrules/sg_consul_ui_alb.tf @@ -6,6 +6,7 @@ resource "aws_security_group_rule" "sgr_ui_alb_to_consul_tcp" { from_port = 8500 to_port = 8500 protocol = "tcp" - source_security_group_id = "${var.sg_id_ui_alb_nomad}" - security_group_id = "${var.sg_id_consul}" + source_security_group_id = var.sg_id_ui_alb_nomad + security_group_id = var.sg_id_consul } + diff --git a/modules/sgrules/sg_nomad_clients.tf b/modules/sgrules/sg_nomad_clients.tf index e54ea80..ef1c274 100644 --- a/modules/sgrules/sg_nomad_clients.tf +++ b/modules/sgrules/sg_nomad_clients.tf @@ -9,8 +9,8 @@ resource "aws_security_group_rule" "sgr_private_to_public_services_http_rcp" { from_port = 4646 to_port = 4647 protocol = "tcp" - source_security_group_id = "${var.sg_id_private_services_dc}" - security_group_id = "${var.sg_id_public_services_dc}" + source_security_group_id = var.sg_id_private_services_dc + security_group_id = var.sg_id_public_services_dc } # rule granting access from content-connector to public services data-center on ports @@ -22,8 +22,8 @@ resource "aws_security_group_rule" "sgr_content_connector_to_public_services_htt from_port = 4646 to_port = 4647 protocol = "tcp" - source_security_group_id = "${var.sg_id_content_connector_dc}" - security_group_id = "${var.sg_id_public_services_dc}" + source_security_group_id = var.sg_id_content_connector_dc + security_group_id = var.sg_id_public_services_dc } # rule granting access from backoffice to public services data-center on ports @@ -35,8 +35,8 @@ resource "aws_security_group_rule" "sgr_backoffice_to_public_services_http_rcp" from_port = 4646 to_port = 4647 protocol = "tcp" - source_security_group_id = "${var.sg_id_backoffice_dc}" - security_group_id = "${var.sg_id_public_services_dc}" + source_security_group_id = var.sg_id_backoffice_dc + security_group_id = var.sg_id_public_services_dc } # rule granting access from public to private services data-center on ports @@ -48,8 +48,8 @@ resource "aws_security_group_rule" "sgr_public_to_private_services_http_rcp" { from_port = 4646 to_port = 4647 protocol = "tcp" - source_security_group_id = "${var.sg_id_public_services_dc}" - security_group_id = "${var.sg_id_private_services_dc}" + source_security_group_id = var.sg_id_public_services_dc + security_group_id = var.sg_id_private_services_dc } # rule granting access from content-connector to private services data-center on ports @@ -61,8 +61,8 @@ resource "aws_security_group_rule" "sgr_content_connector_to_private_services_ht from_port = 4646 to_port = 4647 protocol = "tcp" - source_security_group_id = "${var.sg_id_content_connector_dc}" - security_group_id = "${var.sg_id_private_services_dc}" + source_security_group_id = var.sg_id_content_connector_dc + security_group_id = var.sg_id_private_services_dc } # rule granting access from backoffice to private services data-center on ports @@ -74,8 +74,8 @@ resource "aws_security_group_rule" "sgr_backoffice_to_private_services_http_rcp" from_port = 4646 to_port = 4647 protocol = "tcp" - source_security_group_id = "${var.sg_id_backoffice_dc}" - security_group_id = "${var.sg_id_private_services_dc}" + source_security_group_id = var.sg_id_backoffice_dc + security_group_id = var.sg_id_private_services_dc } # rule granting access from public to content-connector data-center on ports @@ -87,8 +87,8 @@ resource "aws_security_group_rule" "sgr_public_to_content_connector_http_rcp" { from_port = 4646 to_port = 4647 protocol = "tcp" - source_security_group_id = "${var.sg_id_public_services_dc}" - security_group_id = "${var.sg_id_content_connector_dc}" + source_security_group_id = var.sg_id_public_services_dc + security_group_id = var.sg_id_content_connector_dc } # rule granting access from private-services to content-connector data-center on ports @@ -100,8 +100,8 @@ resource "aws_security_group_rule" "sgr_private_to_content_connector_http_rcp" { from_port = 4646 to_port = 4647 protocol = "tcp" - source_security_group_id = "${var.sg_id_private_services_dc}" - security_group_id = "${var.sg_id_content_connector_dc}" + source_security_group_id = var.sg_id_private_services_dc + security_group_id = var.sg_id_content_connector_dc } # rule granting access from backoffice to content-connector data-center on ports @@ -113,8 +113,8 @@ resource "aws_security_group_rule" "sgr_backoffice_to_content_connector_http_rcp from_port = 4646 to_port = 4647 protocol = "tcp" - source_security_group_id = "${var.sg_id_backoffice_dc}" - security_group_id = "${var.sg_id_content_connector_dc}" + source_security_group_id = var.sg_id_backoffice_dc + security_group_id = var.sg_id_content_connector_dc } # rule granting access from public to backoffice data-center on ports @@ -126,8 +126,8 @@ resource "aws_security_group_rule" "sgr_public_to_backoffice_http_rcp" { from_port = 4646 to_port = 4647 protocol = "tcp" - source_security_group_id = "${var.sg_id_public_services_dc}" - security_group_id = "${var.sg_id_backoffice_dc}" + source_security_group_id = var.sg_id_public_services_dc + security_group_id = var.sg_id_backoffice_dc } # rule granting access from content-connector to backoffice data-center on ports @@ -139,8 +139,8 @@ resource "aws_security_group_rule" "sgr_content_connector_to_backoffice_http_rcp from_port = 4646 to_port = 4647 protocol = "tcp" - source_security_group_id = "${var.sg_id_content_connector_dc}" - security_group_id = "${var.sg_id_backoffice_dc}" + source_security_group_id = var.sg_id_content_connector_dc + security_group_id = var.sg_id_backoffice_dc } # rule granting access from private to backoffice data-center on ports @@ -152,8 +152,8 @@ resource "aws_security_group_rule" "sgr_private_to_backoffice_http_rcp" { from_port = 4646 to_port = 4647 protocol = "tcp" - source_security_group_id = "${var.sg_id_private_services_dc}" - security_group_id = "${var.sg_id_backoffice_dc}" + source_security_group_id = var.sg_id_private_services_dc + security_group_id = var.sg_id_backoffice_dc } # rule granting self-access to backoffice data-center on ports @@ -165,8 +165,8 @@ resource "aws_security_group_rule" "sgr_backoffice_to_backoffice_http_rcp" { from_port = 4646 to_port = 4647 protocol = "tcp" - source_security_group_id = "${var.sg_id_backoffice_dc}" - security_group_id = "${var.sg_id_backoffice_dc}" + source_security_group_id = var.sg_id_backoffice_dc + security_group_id = var.sg_id_backoffice_dc } # rule granting self-access to private_services data-center on ports @@ -178,8 +178,8 @@ resource "aws_security_group_rule" "sgr_private_to_private_http_rcp" { from_port = 4646 to_port = 4647 protocol = "tcp" - source_security_group_id = "${var.sg_id_private_services_dc}" - security_group_id = "${var.sg_id_private_services_dc}" + source_security_group_id = var.sg_id_private_services_dc + security_group_id = var.sg_id_private_services_dc } # rule granting self-access to public_services data-center on ports @@ -191,8 +191,8 @@ resource "aws_security_group_rule" "sgr_public_to_public_http_rcp" { from_port = 4646 to_port = 4647 protocol = "tcp" - source_security_group_id = "${var.sg_id_public_services_dc}" - security_group_id = "${var.sg_id_public_services_dc}" + source_security_group_id = var.sg_id_public_services_dc + security_group_id = var.sg_id_public_services_dc } # rule granting self-access to content-connector data-center on ports @@ -204,6 +204,7 @@ resource "aws_security_group_rule" "sgr_content_connector_to_content_connector_h from_port = 4646 to_port = 4647 protocol = "tcp" - source_security_group_id = "${var.sg_id_content_connector_dc}" - security_group_id = "${var.sg_id_content_connector_dc}" -} \ No newline at end of file + source_security_group_id = var.sg_id_content_connector_dc + security_group_id = var.sg_id_content_connector_dc +} + diff --git a/modules/sgrules/sg_nomad_clients_consul.tf b/modules/sgrules/sg_nomad_clients_consul.tf index 7234ac1..063a994 100644 --- a/modules/sgrules/sg_nomad_clients_consul.tf +++ b/modules/sgrules/sg_nomad_clients_consul.tf @@ -16,8 +16,8 @@ resource "aws_security_group_rule" "sgr_consul_to_public_services_tcp" { from_port = 8301 to_port = 8302 protocol = "tcp" - source_security_group_id = "${var.sg_id_consul}" - security_group_id = "${var.sg_id_public_services_dc}" + source_security_group_id = var.sg_id_consul + security_group_id = var.sg_id_public_services_dc } # rule granting access from consul to private-services data-center on ports @@ -29,8 +29,8 @@ resource "aws_security_group_rule" "sgr_consul_to_private_services_tcp" { from_port = 8301 to_port = 8302 protocol = "tcp" - source_security_group_id = "${var.sg_id_consul}" - security_group_id = "${var.sg_id_private_services_dc}" + source_security_group_id = var.sg_id_consul + security_group_id = var.sg_id_private_services_dc } # rule granting access from consul to content-connector data-center on ports @@ -42,8 +42,8 @@ resource "aws_security_group_rule" "sgr_consul_to_content_connector_tcp" { from_port = 8301 to_port = 8302 protocol = "tcp" - source_security_group_id = "${var.sg_id_consul}" - security_group_id = "${var.sg_id_content_connector_dc}" + source_security_group_id = var.sg_id_consul + security_group_id = var.sg_id_content_connector_dc } # rule granting access from consul to backoffice data-center on ports @@ -55,8 +55,8 @@ resource "aws_security_group_rule" "sgr_consul_to_backoffice_tcp" { from_port = 8301 to_port = 8302 protocol = "tcp" - source_security_group_id = "${var.sg_id_consul}" - security_group_id = "${var.sg_id_backoffice_dc}" + source_security_group_id = var.sg_id_consul + security_group_id = var.sg_id_backoffice_dc } # rule granting access from consul to public-services data-center on ports @@ -68,8 +68,8 @@ resource "aws_security_group_rule" "sgr_consul_to_public_services_udp" { from_port = 8301 to_port = 8302 protocol = "udp" - source_security_group_id = "${var.sg_id_consul}" - security_group_id = "${var.sg_id_public_services_dc}" + source_security_group_id = var.sg_id_consul + security_group_id = var.sg_id_public_services_dc } # rule granting access from consul to private-services data-center on ports @@ -81,8 +81,8 @@ resource "aws_security_group_rule" "sgr_consul_to_private_services_udp" { from_port = 8301 to_port = 8302 protocol = "udp" - source_security_group_id = "${var.sg_id_consul}" - security_group_id = "${var.sg_id_private_services_dc}" + source_security_group_id = var.sg_id_consul + security_group_id = var.sg_id_private_services_dc } # rule granting access from consul to content-connector data-center on ports @@ -94,8 +94,8 @@ resource "aws_security_group_rule" "sgr_consul_to_content_connector_udp" { from_port = 8301 to_port = 8302 protocol = "udp" - source_security_group_id = "${var.sg_id_consul}" - security_group_id = "${var.sg_id_content_connector_dc}" + source_security_group_id = var.sg_id_consul + security_group_id = var.sg_id_content_connector_dc } # rule granting access from consul to backoffice data-center on ports @@ -107,6 +107,7 @@ resource "aws_security_group_rule" "sgr_consul_to_backoffice_udp" { from_port = 8301 to_port = 8302 protocol = "udp" - source_security_group_id = "${var.sg_id_consul}" - security_group_id = "${var.sg_id_backoffice_dc}" + source_security_group_id = var.sg_id_consul + security_group_id = var.sg_id_backoffice_dc } + diff --git a/modules/sgrules/sg_nomad_clients_docker.tf b/modules/sgrules/sg_nomad_clients_docker.tf index c982bfc..334cd14 100644 --- a/modules/sgrules/sg_nomad_clients_docker.tf +++ b/modules/sgrules/sg_nomad_clients_docker.tf @@ -9,7 +9,7 @@ resource "aws_security_group_rule" "sgr_to_public_services_docker" { to_port = 32000 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] - security_group_id = "${var.sg_id_public_services_dc}" + security_group_id = var.sg_id_public_services_dc } # rule granting access to private services data-center for docker ports @@ -21,7 +21,7 @@ resource "aws_security_group_rule" "sgr_to_private_services_docker" { to_port = 32000 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] - security_group_id = "${var.sg_id_private_services_dc}" + security_group_id = var.sg_id_private_services_dc } # rule granting access to content-conncetor data-center for docker ports @@ -33,7 +33,7 @@ resource "aws_security_group_rule" "sgr_to_content_connector_docker" { to_port = 32000 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] - security_group_id = "${var.sg_id_content_connector_dc}" + security_group_id = var.sg_id_content_connector_dc } # rule granting access to backoffice data-center for docker ports @@ -45,7 +45,7 @@ resource "aws_security_group_rule" "sgr_to_backoffice_docker" { to_port = 32000 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] - security_group_id = "${var.sg_id_backoffice_dc}" + security_group_id = var.sg_id_backoffice_dc } # rule granting access to public services data-center for docker ports @@ -57,7 +57,7 @@ resource "aws_security_group_rule" "sgr_to_public_services_docker_udp" { to_port = 32000 protocol = "udp" cidr_blocks = ["0.0.0.0/0"] - security_group_id = "${var.sg_id_public_services_dc}" + security_group_id = var.sg_id_public_services_dc } # rule granting access to private services data-center for docker ports @@ -69,7 +69,7 @@ resource "aws_security_group_rule" "sgr_to_private_services_docker_udp" { to_port = 32000 protocol = "udp" cidr_blocks = ["0.0.0.0/0"] - security_group_id = "${var.sg_id_private_services_dc}" + security_group_id = var.sg_id_private_services_dc } # rule granting access to content-conncetor data-center for docker ports @@ -81,7 +81,7 @@ resource "aws_security_group_rule" "sgr_to_content_connector_docker_udp" { to_port = 32000 protocol = "udp" cidr_blocks = ["0.0.0.0/0"] - security_group_id = "${var.sg_id_content_connector_dc}" + security_group_id = var.sg_id_content_connector_dc } # rule granting access to backoffice data-center for docker ports @@ -93,5 +93,6 @@ resource "aws_security_group_rule" "sgr_to_backoffice_docker_udp" { to_port = 32000 protocol = "udp" cidr_blocks = ["0.0.0.0/0"] - security_group_id = "${var.sg_id_backoffice_dc}" + security_group_id = var.sg_id_backoffice_dc } + diff --git a/modules/sgrules/sg_nomad_clients_igress.tf b/modules/sgrules/sg_nomad_clients_igress.tf index 7f5e64d..75f4260 100644 --- a/modules/sgrules/sg_nomad_clients_igress.tf +++ b/modules/sgrules/sg_nomad_clients_igress.tf @@ -9,7 +9,7 @@ resource "aws_security_group_rule" "sgr_public_services_ig_999x" { to_port = 9999 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] - security_group_id = "${var.sg_id_public_services_dc}" + security_group_id = var.sg_id_public_services_dc } # rule granting access on igress-ports to private services data-center on ports @@ -21,10 +21,9 @@ resource "aws_security_group_rule" "sgr_private_services_ig_999x" { to_port = 9999 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] - security_group_id = "${var.sg_id_private_services_dc}" + security_group_id = var.sg_id_private_services_dc } - # rule granting access on igress-ports to content-connector data-center on ports # 9998 ... 9999 resource "aws_security_group_rule" "sgr_content_connector_ig_999x" { @@ -34,10 +33,9 @@ resource "aws_security_group_rule" "sgr_content_connector_ig_999x" { to_port = 9999 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] - security_group_id = "${var.sg_id_content_connector_dc}" + security_group_id = var.sg_id_content_connector_dc } - # rule granting access on igress-ports to backoffice services data-center on ports # 9998 ... 9999 resource "aws_security_group_rule" "sgr_backoffice_ig_999x" { @@ -47,5 +45,6 @@ resource "aws_security_group_rule" "sgr_backoffice_ig_999x" { to_port = 9999 protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] - security_group_id = "${var.sg_id_backoffice_dc}" + security_group_id = var.sg_id_backoffice_dc } + diff --git a/modules/sgrules/sg_nomad_clients_server_access.tf b/modules/sgrules/sg_nomad_clients_server_access.tf index c392e1b..78e5a08 100644 --- a/modules/sgrules/sg_nomad_clients_server_access.tf +++ b/modules/sgrules/sg_nomad_clients_server_access.tf @@ -10,8 +10,8 @@ resource "aws_security_group_rule" "sgr_server_to_public_services_tcp" { from_port = 4646 to_port = 4648 protocol = "tcp" - source_security_group_id = "${var.sg_id_nomad_server}" - security_group_id = "${var.sg_id_public_services_dc}" + source_security_group_id = var.sg_id_nomad_server + security_group_id = var.sg_id_public_services_dc } # rule that grants TCP ingress access from nomad-server to private-services data-center on ports @@ -24,8 +24,8 @@ resource "aws_security_group_rule" "sgr_server_to_private_services_tcp" { from_port = 4646 to_port = 4648 protocol = "tcp" - source_security_group_id = "${var.sg_id_nomad_server}" - security_group_id = "${var.sg_id_private_services_dc}" + source_security_group_id = var.sg_id_nomad_server + security_group_id = var.sg_id_private_services_dc } # rule that grants TCP ingress access from nomad-server to content-connector data-center on ports @@ -38,8 +38,8 @@ resource "aws_security_group_rule" "sgr_server_to_content_connector_tcp" { from_port = 4646 to_port = 4648 protocol = "tcp" - source_security_group_id = "${var.sg_id_nomad_server}" - security_group_id = "${var.sg_id_content_connector_dc}" + source_security_group_id = var.sg_id_nomad_server + security_group_id = var.sg_id_content_connector_dc } # rule that grants TCP ingress access from nomad-server to backoffice data-center on ports @@ -52,8 +52,8 @@ resource "aws_security_group_rule" "sgr_server_to_backoffice_tcp" { from_port = 4646 to_port = 4648 protocol = "tcp" - source_security_group_id = "${var.sg_id_nomad_server}" - security_group_id = "${var.sg_id_backoffice_dc}" + source_security_group_id = var.sg_id_nomad_server + security_group_id = var.sg_id_backoffice_dc } # rule that grants UDP ingress access from nomad-server to public-services data-center on ports @@ -64,8 +64,8 @@ resource "aws_security_group_rule" "sgr_server_to_public_services_udp" { from_port = 4648 to_port = 4648 protocol = "udp" - source_security_group_id = "${var.sg_id_nomad_server}" - security_group_id = "${var.sg_id_public_services_dc}" + source_security_group_id = var.sg_id_nomad_server + security_group_id = var.sg_id_public_services_dc } # rule that grants UDP ingress access from nomad-server to private-services data-center on ports @@ -76,8 +76,8 @@ resource "aws_security_group_rule" "sgr_server_to_private_services_udp" { from_port = 4648 to_port = 4648 protocol = "udp" - source_security_group_id = "${var.sg_id_nomad_server}" - security_group_id = "${var.sg_id_private_services_dc}" + source_security_group_id = var.sg_id_nomad_server + security_group_id = var.sg_id_private_services_dc } # rule that grants UDP ingress access from nomad-server to content-connector data-center on ports @@ -88,8 +88,8 @@ resource "aws_security_group_rule" "sgr_server_to_content_connector_udp" { from_port = 4648 to_port = 4648 protocol = "udp" - source_security_group_id = "${var.sg_id_nomad_server}" - security_group_id = "${var.sg_id_content_connector_dc}" + source_security_group_id = var.sg_id_nomad_server + security_group_id = var.sg_id_content_connector_dc } # rule that grants UDP ingress access from nomad-server to backoffice data-center on ports @@ -100,6 +100,7 @@ resource "aws_security_group_rule" "sgr_server_to_backoffice_udp" { from_port = 4648 to_port = 4648 protocol = "udp" - source_security_group_id = "${var.sg_id_nomad_server}" - security_group_id = "${var.sg_id_backoffice_dc}" + source_security_group_id = var.sg_id_nomad_server + security_group_id = var.sg_id_backoffice_dc } + diff --git a/modules/sgrules/sg_nomad_server_clients_access.tf b/modules/sgrules/sg_nomad_server_clients_access.tf index c15cce7..f579658 100644 --- a/modules/sgrules/sg_nomad_server_clients_access.tf +++ b/modules/sgrules/sg_nomad_server_clients_access.tf @@ -10,8 +10,8 @@ resource "aws_security_group_rule" "sgr_public_services_to_server_tcp" { from_port = 4646 to_port = 4648 protocol = "tcp" - source_security_group_id = "${var.sg_id_public_services_dc}" - security_group_id = "${var.sg_id_nomad_server}" + source_security_group_id = var.sg_id_public_services_dc + security_group_id = var.sg_id_nomad_server } # rule that grants TCP ingress access from private-services data-center to nomad-server to on ports @@ -24,8 +24,8 @@ resource "aws_security_group_rule" "sgr_private_services_to_server_tcp" { from_port = 4646 to_port = 4648 protocol = "tcp" - source_security_group_id = "${var.sg_id_private_services_dc}" - security_group_id = "${var.sg_id_nomad_server}" + source_security_group_id = var.sg_id_private_services_dc + security_group_id = var.sg_id_nomad_server } # rule that grants TCP ingress access from content-connector data-center to nomad-server to on ports @@ -38,8 +38,8 @@ resource "aws_security_group_rule" "sgr_content_connector_to_server_tcp" { from_port = 4646 to_port = 4648 protocol = "tcp" - source_security_group_id = "${var.sg_id_content_connector_dc}" - security_group_id = "${var.sg_id_nomad_server}" + source_security_group_id = var.sg_id_content_connector_dc + security_group_id = var.sg_id_nomad_server } # rule that grants TCP ingress access from backoffice data-center to nomad-server to on ports @@ -52,8 +52,8 @@ resource "aws_security_group_rule" "sgr_backoffice_to_server_tcp" { from_port = 4646 to_port = 4648 protocol = "tcp" - source_security_group_id = "${var.sg_id_backoffice_dc}" - security_group_id = "${var.sg_id_nomad_server}" + source_security_group_id = var.sg_id_backoffice_dc + security_group_id = var.sg_id_nomad_server } # rule that grants UDP ingress access from public-services data-center to nomad-server to on ports @@ -64,8 +64,8 @@ resource "aws_security_group_rule" "sgr_public_services_to_server_udp" { from_port = 4648 to_port = 4648 protocol = "udp" - source_security_group_id = "${var.sg_id_public_services_dc}" - security_group_id = "${var.sg_id_nomad_server}" + source_security_group_id = var.sg_id_public_services_dc + security_group_id = var.sg_id_nomad_server } # rule that grants UDP ingress access from private-services data-center to nomad-server to on ports @@ -76,8 +76,8 @@ resource "aws_security_group_rule" "sgr_private_services_to_server_udp" { from_port = 4648 to_port = 4648 protocol = "udp" - source_security_group_id = "${var.sg_id_private_services_dc}" - security_group_id = "${var.sg_id_nomad_server}" + source_security_group_id = var.sg_id_private_services_dc + security_group_id = var.sg_id_nomad_server } # rule that grants UDP ingress access from content-connector data-center to nomad-server to on ports @@ -88,8 +88,8 @@ resource "aws_security_group_rule" "sgr_content_connector_to_server_udp" { from_port = 4648 to_port = 4648 protocol = "udp" - source_security_group_id = "${var.sg_id_content_connector_dc}" - security_group_id = "${var.sg_id_nomad_server}" + source_security_group_id = var.sg_id_content_connector_dc + security_group_id = var.sg_id_nomad_server } # rule that grants UDP ingress access from backoffice data-center to nomad-server to on ports @@ -100,6 +100,7 @@ resource "aws_security_group_rule" "sgr_backoffice_to_server_udp" { from_port = 4648 to_port = 4648 protocol = "udp" - source_security_group_id = "${var.sg_id_backoffice_dc}" - security_group_id = "${var.sg_id_nomad_server}" + source_security_group_id = var.sg_id_backoffice_dc + security_group_id = var.sg_id_nomad_server } + diff --git a/modules/sgrules/sg_nomad_server_consul.tf b/modules/sgrules/sg_nomad_server_consul.tf index 3ffa1dd..f94ca60 100644 --- a/modules/sgrules/sg_nomad_server_consul.tf +++ b/modules/sgrules/sg_nomad_server_consul.tf @@ -16,8 +16,8 @@ resource "aws_security_group_rule" "sgr_consul_to_nomad_server_tcp" { from_port = 8300 to_port = 8302 protocol = "tcp" - source_security_group_id = "${var.sg_id_consul}" - security_group_id = "${var.sg_id_nomad_server}" + source_security_group_id = var.sg_id_consul + security_group_id = var.sg_id_nomad_server } # rule granting access from consul to nomad server on ports @@ -29,6 +29,7 @@ resource "aws_security_group_rule" "sgr_consul_to_nomad_server_udp" { from_port = 8301 to_port = 8302 protocol = "udp" - source_security_group_id = "${var.sg_id_consul}" - security_group_id = "${var.sg_id_nomad_server}" + source_security_group_id = var.sg_id_consul + security_group_id = var.sg_id_nomad_server } + diff --git a/modules/sgrules/sg_nomad_server_ui_alb.tf b/modules/sgrules/sg_nomad_server_ui_alb.tf index c2af1ef..9e8b3bc 100644 --- a/modules/sgrules/sg_nomad_server_ui_alb.tf +++ b/modules/sgrules/sg_nomad_server_ui_alb.tf @@ -6,6 +6,7 @@ resource "aws_security_group_rule" "sgr_ui_alb_to_nomad_server_tcp" { from_port = 4646 to_port = 4646 protocol = "tcp" - source_security_group_id = "${var.sg_id_ui_alb_nomad}" - security_group_id = "${var.sg_id_nomad_server}" + source_security_group_id = var.sg_id_ui_alb_nomad + security_group_id = var.sg_id_nomad_server } + diff --git a/modules/sgrules/versions.tf b/modules/sgrules/versions.tf new file mode 100644 index 0000000..ac97c6a --- /dev/null +++ b/modules/sgrules/versions.tf @@ -0,0 +1,4 @@ + +terraform { + required_version = ">= 0.12" +} diff --git a/modules/ui-access/consul_ui_alb.tf b/modules/ui-access/consul_ui_alb.tf index ddee59e..9aa3bb1 100644 --- a/modules/ui-access/consul_ui_alb.tf +++ b/modules/ui-access/consul_ui_alb.tf @@ -3,64 +3,65 @@ resource "aws_alb" "alb_consul_ui" { name = "${var.stack_name}-consul-ui${var.unique_postfix}" internal = false - subnets = ["${var.subnet_ids}"] - security_groups = ["${aws_security_group.sg_ui_alb.id}"] + subnets = var.subnet_ids + security_groups = [aws_security_group.sg_ui_alb.id] - tags { + tags = { Name = "${var.stack_name}-consul-ui${var.unique_postfix}" } } resource "aws_autoscaling_attachment" "asg_attachment_consul_ui" { - autoscaling_group_name = "${var.consul_server_asg_name}" - alb_target_group_arn = "${aws_alb_target_group.tgr_consul_ui.arn}" + autoscaling_group_name = var.consul_server_asg_name + alb_target_group_arn = aws_alb_target_group.tgr_consul_ui.arn } resource "aws_alb_target_group" "tgr_consul_ui" { name_prefix = "consul" - port = "${var.consul_ui_port}" + port = var.consul_ui_port protocol = "HTTP" - vpc_id = "${var.vpc_id}" + vpc_id = var.vpc_id health_check { interval = 15 path = "/v1/status/leader" - port = "${var.consul_ui_port}" + port = var.consul_ui_port protocol = "HTTP" timeout = 3 healthy_threshold = 2 unhealthy_threshold = 2 } - tags { + tags = { Name = "${var.stack_name}-consul-ui${var.unique_postfix}" } } # HTTP listener, used when no https certificate is provided. resource "aws_alb_listener" "albl_http_consul_ui" { - count = "${var.ui_alb_use_https_listener? 0 : 1}" - load_balancer_arn = "${aws_alb.alb_consul_ui.arn}" + count = var.ui_alb_use_https_listener ? 0 : 1 + load_balancer_arn = aws_alb.alb_consul_ui.arn protocol = "HTTP" - port = "${local.listener_port}" + port = local.listener_port default_action { - target_group_arn = "${aws_alb_target_group.tgr_consul_ui.arn}" + target_group_arn = aws_alb_target_group.tgr_consul_ui.arn type = "forward" } } # HTTPS listener, used when a https certificate is provided. resource "aws_alb_listener" "albl_https_consul_ui" { - count = "${var.ui_alb_use_https_listener}" - load_balancer_arn = "${aws_alb.alb_consul_ui.arn}" + count = var.ui_alb_use_https_listener ? 1 : 0 + load_balancer_arn = aws_alb.alb_consul_ui.arn protocol = "HTTPS" - port = "${local.listener_port}" - certificate_arn = "${var.ui_alb_https_listener_cert_arn}" - ssl_policy = "${local.ssl_policy}" + port = local.listener_port + certificate_arn = var.ui_alb_https_listener_cert_arn + ssl_policy = local.ssl_policy default_action { - target_group_arn = "${aws_alb_target_group.tgr_consul_ui.arn}" + target_group_arn = aws_alb_target_group.tgr_consul_ui.arn type = "forward" } } + diff --git a/modules/ui-access/fabio_ui_alb.tf b/modules/ui-access/fabio_ui_alb.tf index 196b5dd..592a9f4 100644 --- a/modules/ui-access/fabio_ui_alb.tf +++ b/modules/ui-access/fabio_ui_alb.tf @@ -3,64 +3,65 @@ resource "aws_alb" "alb_fabio_ui" { name = "${var.stack_name}-fabio-ui${var.unique_postfix}" internal = false - subnets = ["${var.subnet_ids}"] - security_groups = ["${aws_security_group.sg_ui_alb.id}"] + subnets = var.subnet_ids + security_groups = [aws_security_group.sg_ui_alb.id] - tags { + tags = { Name = "${var.stack_name}-fabio-ui${var.unique_postfix}" } } resource "aws_autoscaling_attachment" "asg_attachment_fabio_ui" { - autoscaling_group_name = "${var.fabio_server_asg_name}" - alb_target_group_arn = "${aws_alb_target_group.tgr_fabio_ui.arn}" + autoscaling_group_name = var.fabio_server_asg_name + alb_target_group_arn = aws_alb_target_group.tgr_fabio_ui.arn } resource "aws_alb_target_group" "tgr_fabio_ui" { name_prefix = "fabio" - port = "${var.fabio_ui_port}" + port = var.fabio_ui_port protocol = "HTTP" - vpc_id = "${var.vpc_id}" + vpc_id = var.vpc_id health_check { interval = 15 path = "/health" - port = "${var.fabio_ui_port}" + port = var.fabio_ui_port protocol = "HTTP" timeout = 3 healthy_threshold = 2 unhealthy_threshold = 2 } - tags { + tags = { Name = "${var.stack_name}-fabio-ui${var.unique_postfix}" } } # HTTP listener, used when no https certificate is provided. resource "aws_alb_listener" "albl_http_fabio_ui" { - count = "${var.ui_alb_use_https_listener? 0 : 1}" - load_balancer_arn = "${aws_alb.alb_fabio_ui.arn}" + count = var.ui_alb_use_https_listener ? 0 : 1 + load_balancer_arn = aws_alb.alb_fabio_ui.arn protocol = "HTTP" - port = "${local.listener_port}" + port = local.listener_port default_action { - target_group_arn = "${aws_alb_target_group.tgr_fabio_ui.arn}" + target_group_arn = aws_alb_target_group.tgr_fabio_ui.arn type = "forward" } } # HTTPS listener, used when a https certificate is provided. resource "aws_alb_listener" "albl_https_fabio_ui" { - count = "${var.ui_alb_use_https_listener}" - load_balancer_arn = "${aws_alb.alb_fabio_ui.arn}" + count = var.ui_alb_use_https_listener ? 1 : 0 + load_balancer_arn = aws_alb.alb_fabio_ui.arn protocol = "HTTPS" - port = "${local.listener_port}" - certificate_arn = "${var.ui_alb_https_listener_cert_arn}" - ssl_policy = "${local.ssl_policy}" + port = local.listener_port + certificate_arn = var.ui_alb_https_listener_cert_arn + ssl_policy = local.ssl_policy default_action { - target_group_arn = "${aws_alb_target_group.tgr_fabio_ui.arn}" + target_group_arn = aws_alb_target_group.tgr_fabio_ui.arn type = "forward" } } + diff --git a/modules/ui-access/main.tf b/modules/ui-access/main.tf index 7d6b642..4f15414 100644 --- a/modules/ui-access/main.tf +++ b/modules/ui-access/main.tf @@ -1,5 +1,5 @@ locals { - listener_protocol = "${var.ui_alb_use_https_listener?"HTTPS":"HTTP"}" - listener_port = "${var.ui_alb_use_https_listener?"443":"80"}" + listener_protocol = var.ui_alb_use_https_listener ? "HTTPS" : "HTTP" + listener_port = var.ui_alb_use_https_listener ? "443" : "80" ssl_policy = "ELBSecurityPolicy-TLS-1-2-Ext-2018-06" -} +} \ No newline at end of file diff --git a/modules/ui-access/nomad_ui_alb.tf b/modules/ui-access/nomad_ui_alb.tf index b221381..010e4cd 100644 --- a/modules/ui-access/nomad_ui_alb.tf +++ b/modules/ui-access/nomad_ui_alb.tf @@ -3,64 +3,65 @@ resource "aws_alb" "alb_nomad_ui" { name = "${var.stack_name}-nomad-ui${var.unique_postfix}" internal = false - subnets = ["${var.subnet_ids}"] - security_groups = ["${aws_security_group.sg_ui_alb.id}"] + subnets = var.subnet_ids + security_groups = [aws_security_group.sg_ui_alb.id] - tags { + tags = { Name = "${var.stack_name}-nomad-ui${var.unique_postfix}" } } resource "aws_autoscaling_attachment" "asg_attachment_nomad_ui" { - autoscaling_group_name = "${var.nomad_server_asg_name}" - alb_target_group_arn = "${aws_alb_target_group.tgr_nomad_ui.arn}" + autoscaling_group_name = var.nomad_server_asg_name + alb_target_group_arn = aws_alb_target_group.tgr_nomad_ui.arn } resource "aws_alb_target_group" "tgr_nomad_ui" { name_prefix = "nomad" - port = "${var.nomad_ui_port}" + port = var.nomad_ui_port protocol = "HTTP" - vpc_id = "${var.vpc_id}" + vpc_id = var.vpc_id health_check { interval = 15 path = "/ui/jobs" - port = "${var.nomad_ui_port}" + port = var.nomad_ui_port protocol = "HTTP" timeout = 3 healthy_threshold = 2 unhealthy_threshold = 2 } - tags { + tags = { Name = "${var.stack_name}-nomad-ui${var.unique_postfix}" } } # HTTP listener, used when no https certificate is provided. resource "aws_alb_listener" "albl_http_nomad_ui" { - count = "${var.ui_alb_use_https_listener? 0 : 1}" - load_balancer_arn = "${aws_alb.alb_nomad_ui.arn}" + count = var.ui_alb_use_https_listener ? 0 : 1 + load_balancer_arn = aws_alb.alb_nomad_ui.arn protocol = "HTTP" - port = "${local.listener_port}" + port = local.listener_port default_action { - target_group_arn = "${aws_alb_target_group.tgr_nomad_ui.arn}" + target_group_arn = aws_alb_target_group.tgr_nomad_ui.arn type = "forward" } } # HTTPS listener, used when a https certificate is provided. resource "aws_alb_listener" "albl_https_nomad_ui" { - count = "${var.ui_alb_use_https_listener}" - load_balancer_arn = "${aws_alb.alb_nomad_ui.arn}" + count = var.ui_alb_use_https_listener ? 1 : 0 + load_balancer_arn = aws_alb.alb_nomad_ui.arn protocol = "HTTPS" - port = "${local.listener_port}" - certificate_arn = "${var.ui_alb_https_listener_cert_arn}" - ssl_policy = "${local.ssl_policy}" + port = local.listener_port + certificate_arn = var.ui_alb_https_listener_cert_arn + ssl_policy = local.ssl_policy default_action { - target_group_arn = "${aws_alb_target_group.tgr_nomad_ui.arn}" + target_group_arn = aws_alb_target_group.tgr_nomad_ui.arn type = "forward" } } + diff --git a/modules/ui-access/outputs.tf b/modules/ui-access/outputs.tf index c4b6797..d51664c 100644 --- a/modules/ui-access/outputs.tf +++ b/modules/ui-access/outputs.tf @@ -1,59 +1,60 @@ output "nomad_ui_alb_zone_id" { - value = "${aws_alb.alb_nomad_ui.zone_id}" + value = aws_alb.alb_nomad_ui.zone_id } output "nomad_ui_alb_sg_id" { - value = "${aws_security_group.sg_ui_alb.id}" + value = aws_security_group.sg_ui_alb.id } output "nomad_ui_alb_dns_name" { - value = "${aws_alb.alb_nomad_ui.dns_name}" + value = aws_alb.alb_nomad_ui.dns_name } output "nomad_ui_alb_https_targetgroup_arn" { - value = "${aws_alb_target_group.tgr_nomad_ui.arn}" + value = aws_alb_target_group.tgr_nomad_ui.arn } output "nomad_ui_alb_https_listener_arn" { - value = "${aws_alb_listener.albl_https_nomad_ui.*.arn}" + value = aws_alb_listener.albl_https_nomad_ui.*.arn } output "consul_ui_alb_zone_id" { - value = "${aws_alb.alb_consul_ui.zone_id}" + value = aws_alb.alb_consul_ui.zone_id } output "consul_ui_alb_sg_id" { - value = "${aws_security_group.sg_ui_alb.id}" + value = aws_security_group.sg_ui_alb.id } output "consul_ui_alb_dns_name" { - value = "${aws_alb.alb_consul_ui.dns_name}" + value = aws_alb.alb_consul_ui.dns_name } output "consul_ui_alb_https_targetgroup_arn" { - value = "${aws_alb_target_group.tgr_consul_ui.arn}" + value = aws_alb_target_group.tgr_consul_ui.arn } output "consul_ui_alb_https_listener_arn" { - value = "${aws_alb_listener.albl_https_consul_ui.*.arn}" + value = aws_alb_listener.albl_https_consul_ui.*.arn } output "fabio_ui_alb_zone_id" { - value = "${aws_alb.alb_fabio_ui.zone_id}" + value = aws_alb.alb_fabio_ui.zone_id } output "fabio_ui_alb_sg_id" { - value = "${aws_security_group.sg_ui_alb.id}" + value = aws_security_group.sg_ui_alb.id } output "fabio_ui_alb_dns_name" { - value = "${aws_alb.alb_fabio_ui.dns_name}" + value = aws_alb.alb_fabio_ui.dns_name } output "fabio_ui_alb_https_targetgroup_arn" { - value = "${aws_alb_target_group.tgr_fabio_ui.arn}" + value = aws_alb_target_group.tgr_fabio_ui.arn } output "fabio_ui_alb_https_listener_arn" { - value = "${aws_alb_listener.albl_https_fabio_ui.*.arn}" + value = aws_alb_listener.albl_https_fabio_ui.*.arn } + diff --git a/modules/ui-access/ui_alb_sg.tf b/modules/ui-access/ui_alb_sg.tf index b2fd677..8439f14 100644 --- a/modules/ui-access/ui_alb_sg.tf +++ b/modules/ui-access/ui_alb_sg.tf @@ -1,9 +1,9 @@ resource "aws_security_group" "sg_ui_alb" { - vpc_id = "${var.vpc_id}" + vpc_id = var.vpc_id name = "${var.stack_name}-ui-alb${var.unique_postfix}" description = "Security group that allows ingress access to uis in backoffice." - tags { + tags = { Name = "${var.stack_name}-ui-alb${var.unique_postfix}" } @@ -13,19 +13,24 @@ resource "aws_security_group" "sg_ui_alb" { } locals { - keys = "${keys(var.allowed_cidr_blocks_for_ui_alb)}" + keys = keys(var.allowed_cidr_blocks_for_ui_alb) } # INGRESS UI access rules resource "aws_security_group_rule" "sgr_alb_ig_ui" { - count = "${length(local.keys)}" - description = "${element(local.keys,count.index)}: UI - igress ${local.listener_port}" - type = "ingress" - from_port = "${local.listener_port}" - to_port = "${local.listener_port}" - protocol = "tcp" - cidr_blocks = ["${lookup(var.allowed_cidr_blocks_for_ui_alb,element(local.keys,count.index),"0.0.0.0/32")}"] - security_group_id = "${aws_security_group.sg_ui_alb.id}" + count = length(local.keys) + description = "${element(local.keys, count.index)}: UI - igress ${local.listener_port}" + type = "ingress" + from_port = local.listener_port + to_port = local.listener_port + protocol = "tcp" + + cidr_blocks = [lookup( + var.allowed_cidr_blocks_for_ui_alb, + element(local.keys, count.index), + "0.0.0.0/32", + )] + security_group_id = aws_security_group.sg_ui_alb.id } # EGRESS Grants access for all tcp @@ -37,5 +42,5 @@ resource "aws_security_group_rule" "sgr_alb_egAll_ui" { protocol = "tcp" cidr_blocks = ["0.0.0.0/0"] - security_group_id = "${aws_security_group.sg_ui_alb.id}" -} + security_group_id = aws_security_group.sg_ui_alb.id +} \ No newline at end of file diff --git a/modules/ui-access/vars.tf b/modules/ui-access/vars.tf index db5e666..0a46e0d 100644 --- a/modules/ui-access/vars.tf +++ b/modules/ui-access/vars.tf @@ -5,7 +5,7 @@ variable "vpc_id" { variable "subnet_ids" { description = "Ids of the subnets to deploy the alb's into." - type = "list" + type = list(string) } variable "nomad_server_asg_name" { @@ -53,7 +53,7 @@ variable "fabio_ui_port" { variable "allowed_cidr_blocks_for_ui_alb" { description = "Map for cidr blocks that should get access over alb. The format is name:cidr-block. I.e. 'my_cidr'='90.250.75.79/32'" - type = "map" + type = map(string) default = { "all" = "0.0.0.0/0" @@ -74,3 +74,4 @@ variable "ui_alb_use_https_listener" { description = "If true, the https endpoint for the ui-albs will be created instead of the http one. Precondition for this is that ui_alb_https_listener_cert_arn is set apropriately." default = false } + diff --git a/modules/ui-access/versions.tf b/modules/ui-access/versions.tf new file mode 100644 index 0000000..ac97c6a --- /dev/null +++ b/modules/ui-access/versions.tf @@ -0,0 +1,4 @@ + +terraform { + required_version = ">= 0.12" +} diff --git a/outputs.tf b/outputs.tf index 164b9aa..a224804 100644 --- a/outputs.tf +++ b/outputs.tf @@ -1,81 +1,81 @@ output "aws_region" { - value = "${var.aws_region}" + value = var.aws_region } output "nomad_servers_cluster_tag_key" { - value = "${module.nomad.nomad_servers_cluster_tag_key}" + value = module.nomad.nomad_servers_cluster_tag_key } output "nomad_servers_cluster_tag_value" { - value = "${module.nomad.nomad_servers_cluster_tag_value}" + value = module.nomad.nomad_servers_cluster_tag_value } output "num_nomad_servers" { - value = "${module.nomad.num_nomad_servers}" + value = module.nomad.num_nomad_servers } output "nomad_clients_public_services_cluster_tag_value" { - value = "${module.dc-public-services.cluster_tag_value}" + value = module.dc-public-services.cluster_tag_value } output "nomad_ui_alb_dns_name" { - value = "${module.ui-access.nomad_ui_alb_dns_name}" + value = module.ui-access.nomad_ui_alb_dns_name } output "nomad_ui_alb_https_targetgroup_arn" { - value = "${module.ui-access.nomad_ui_alb_https_targetgroup_arn}" + value = module.ui-access.nomad_ui_alb_https_targetgroup_arn } output "nomad_ui_alb_https_listener_arn" { - value = "${module.ui-access.nomad_ui_alb_https_listener_arn}" + value = module.ui-access.nomad_ui_alb_https_listener_arn } output "consul_ui_alb_dns_name" { - value = "${module.ui-access.consul_ui_alb_dns_name}" + value = module.ui-access.consul_ui_alb_dns_name } output "consul_ui_alb_https_targetgroup_arn" { - value = "${module.ui-access.consul_ui_alb_https_targetgroup_arn}" + value = module.ui-access.consul_ui_alb_https_targetgroup_arn } output "consul_ui_alb_https_listener_arn" { - value = "${module.ui-access.consul_ui_alb_https_listener_arn}" + value = module.ui-access.consul_ui_alb_https_listener_arn } output "fabio_ui_alb_dns_name" { - value = "${module.ui-access.fabio_ui_alb_dns_name}" + value = module.ui-access.fabio_ui_alb_dns_name } output "fabio_ui_alb_https_targetgroup_arn" { - value = "${module.ui-access.fabio_ui_alb_https_targetgroup_arn}" + value = module.ui-access.fabio_ui_alb_https_targetgroup_arn } output "fabio_ui_alb_https_listener_arn" { - value = "${module.ui-access.fabio_ui_alb_https_listener_arn}" + value = module.ui-access.fabio_ui_alb_https_listener_arn } output "nomad_ui_alb_zone_id" { - value = "${module.ui-access.nomad_ui_alb_zone_id}" + value = module.ui-access.nomad_ui_alb_zone_id } output "consul_ui_alb_zone_id" { - value = "${module.ui-access.consul_ui_alb_zone_id}" + value = module.ui-access.consul_ui_alb_zone_id } output "fabio_ui_alb_zone_id" { - value = "${module.ui-access.fabio_ui_alb_zone_id}" + value = module.ui-access.fabio_ui_alb_zone_id } output "vpc_id" { - value = "${var.vpc_id}" + value = var.vpc_id } output "ssh_key_name" { - value = "${var.ssh_key_name}" + value = var.ssh_key_name } output "cluster_prefix" { - value = "${module.dc-public-services.cluster_prefix}" + value = module.dc-public-services.cluster_prefix } output "dc-public-services_asg_name" { @@ -83,37 +83,38 @@ output "dc-public-services_asg_name" { } output "dc-public-services_sg_id" { - value = "${module.dc-public-services.sg_datacenter_id}" + value = module.dc-public-services.sg_datacenter_id } output "dc-public-services_alb_https_targetgroup_arn" { - value = "${module.dc-public-services.alb_https_targetgroup_arn}" + value = module.dc-public-services.alb_https_targetgroup_arn } output "dc-private-services_sg_id" { - value = "${module.dc-private-services.sg_datacenter_id}" + value = module.dc-private-services.sg_datacenter_id } output "dc-private-services_alb_https_targetgroup_arn" { - value = "${module.dc-private-services.alb_https_targetgroup_arn}" + value = module.dc-private-services.alb_https_targetgroup_arn } output "dc-backoffice_sg_id" { - value = "${module.dc-backoffice.sg_datacenter_id}" + value = module.dc-backoffice.sg_datacenter_id } output "dc-backoffice_alb_https_targetgroup_arn" { - value = "${module.dc-backoffice.alb_https_targetgroup_arn}" + value = module.dc-backoffice.alb_https_targetgroup_arn } output "consul_servers_sg_id" { - value = "${module.consul.security_group_id_consul_servers}" + value = module.consul.security_group_id_consul_servers } output "consul_servers_cluster_tag_key" { - value = "${module.consul.consul_servers_cluster_tag_key}" + value = module.consul.consul_servers_cluster_tag_key } output "consul_servers_cluster_tag_value" { - value = "${module.consul.consul_servers_cluster_tag_value}" + value = module.consul.consul_servers_cluster_tag_value } + diff --git a/vars.tf b/vars.tf index 2154a6c..f460a89 100644 --- a/vars.tf +++ b/vars.tf @@ -13,7 +13,7 @@ variable "vpc_id" { variable "alb_subnet_ids" { description = "Ids of the subnets to deploy the alb's into." - type = "list" + type = list(string) } #### [Nomad] Required Variables ################################################################### @@ -27,27 +27,27 @@ variable "nomad_ami_id_clients" { variable "nomad_clients_public_services_subnet_ids" { description = "Ids of the subnets to deploy the nomad client nodes providing the data-center public-services into." - type = "list" + type = list(string) } variable "nomad_clients_private_services_subnet_ids" { description = "Ids of the subnets to deploy the nomad client nodes providing the data-center private-services into." - type = "list" + type = list(string) } variable "nomad_clients_content_connector_subnet_ids" { description = "Ids of the subnets to deploy the nomad client nodes providing the data-center content-connector into." - type = "list" + type = list(string) } variable "nomad_clients_backoffice_subnet_ids" { description = "Ids of the subnets to deploy the nomad client nodes providing the data-center backoffice into." - type = "list" + type = list(string) } variable "nomad_server_subnet_ids" { description = "Ids of the subnets to deploy the nomad servers into." - type = "list" + type = list(string) } #### [Consul] Required Variables ################################################################## @@ -57,7 +57,7 @@ variable "consul_ami_id" { variable "consul_server_subnet_ids" { description = "Ids of the subnets to deploy the consul servers into." - type = "list" + type = list(string) } #### [General] Optional Variables ################################################################## @@ -88,13 +88,13 @@ variable "stack_name" { variable "allowed_ssh_cidr_blocks" { description = "A list of cidr block from which inbound ssh traffic should be allowed." - type = "list" + type = list(string) default = [] } variable "allowed_cidr_blocks_for_ui_alb" { description = "Map for cidr blocks that should get access over alb. The format is name:cidr-block. I.e. 'my_cidr'='90.250.75.79/32'" - type = "map" + type = map(string) default = { "all" = "0.0.0.0/0" @@ -124,7 +124,7 @@ variable "attach_backoffice_alb_listener" { #### [Nomad] Optional Variables ################################################################### variable "nomad_server_scaling_cfg" { description = "Scaling configuration for the nomad servers." - type = "map" + type = map(string) default = { "min" = 3 @@ -135,7 +135,7 @@ variable "nomad_server_scaling_cfg" { variable "nomad_private_services_dc_node_cfg" { description = "Node configuration for the nomad nodes of the private-services data center." - type = "map" + type = map(string) default = { "min" = 1 @@ -156,7 +156,7 @@ variable "nomad_private_services_dc_node_cfg" { # }] variable "ebs_block_devices_private_services_dc" { description = "List of ebs volume definitions for those ebs_volumes that should be added to the instances created with the EC2 launch-configurationd. Each element in the list is a map containing keys defined for ebs_block_device (see: https://www.terraform.io/docs/providers/aws/r/launch_configuration.html#ebs_block_device." - type = "list" + type = any default = [] } @@ -168,7 +168,7 @@ variable "ebs_block_devices_private_services_dc" { # Example: ["/dev/xvde:/mnt/map1","/dev/xvdf:/mnt/map2"] variable "device_to_mount_target_map_private_services_dc" { description = "List of device to mount target entries." - type = "list" + type = list(string) default = [] } @@ -184,13 +184,17 @@ variable "device_to_mount_target_map_private_services_dc" { # }] variable "additional_instance_tags_private_services_dc" { description = "List of tags to add to the private_services datacenter instances. The entries of the list are maps consiting of key, value and propagate at launch." - type = "list" - default = [] + type = list(object({ + key = string + value = string + propagate_at_launch = bool + })) + default = [] } variable "nomad_public_services_dc_node_cfg" { description = "Node configuration for the nomad nodes of the public-services data center." - type = "map" + type = map(string) default = { "min" = 1 @@ -211,7 +215,7 @@ variable "nomad_public_services_dc_node_cfg" { # }] variable "ebs_block_devices_public_services_dc" { description = "List of ebs volume definitions for those ebs_volumes that should be added to the instances of the public-services dc. Each element in the list is a map containing keys defined for ebs_block_device (see: https://www.terraform.io/docs/providers/aws/r/launch_configuration.html#ebs_block_device." - type = "list" + type = any default = [] } @@ -223,7 +227,7 @@ variable "ebs_block_devices_public_services_dc" { # Example: ["/dev/xvde:/mnt/map1","/dev/xvdf:/mnt/map2"] variable "device_to_mount_target_map_public_services_dc" { description = "List of device to mount target entries." - type = "list" + type = list(string) default = [] } @@ -239,13 +243,17 @@ variable "device_to_mount_target_map_public_services_dc" { # }] variable "additional_instance_tags_public_services_dc" { description = "List of tags to add to the public_services datacenter instances. The entries of the list are maps consiting of key, value and propagate at launch." - type = "list" - default = [] + type = list(object({ + key = string + value = string + propagate_at_launch = bool + })) + default = [] } variable "nomad_backoffice_dc_node_cfg" { description = "Node configuration for the nomad nodes of the backoffice data center." - type = "map" + type = map(string) default = { "min" = 1 @@ -266,7 +274,7 @@ variable "nomad_backoffice_dc_node_cfg" { # }] variable "ebs_block_devices_backoffice_dc" { description = "List of ebs volume definitions for those ebs_volumes that should be added to the instances of the backoffice dc. Each element in the list is a map containing keys defined for ebs_block_device (see: https://www.terraform.io/docs/providers/aws/r/launch_configuration.html#ebs_block_device." - type = "list" + type = any default = [] } @@ -278,7 +286,7 @@ variable "ebs_block_devices_backoffice_dc" { # Example: ["/dev/xvde:/mnt/map1","/dev/xvdf:/mnt/map2"] variable "device_to_mount_target_map_backoffice_dc" { description = "List of device to mount target entries." - type = "list" + type = list(string) default = [] } @@ -294,13 +302,17 @@ variable "device_to_mount_target_map_backoffice_dc" { # }] variable "additional_instance_tags_backoffice_dc" { description = "List of tags to add to the backoffice datacenter instances. The entries of the list are maps consiting of key, value and propagate at launch." - type = "list" - default = [] + type = list(object({ + key = string + value = string + propagate_at_launch = bool + })) + default = [] } variable "nomad_content_connector_dc_node_cfg" { description = "Node configuration for the nomad nodes of the content-connetor data center." - type = "map" + type = map(string) default = { "min" = 1 @@ -321,7 +333,7 @@ variable "nomad_content_connector_dc_node_cfg" { # }] variable "ebs_block_devices_content_connector_dc" { description = "List of ebs volume definitions for those ebs_volumes that should be added to the instances of the content-connector dc. Each element in the list is a map containing keys defined for ebs_block_device (see: https://www.terraform.io/docs/providers/aws/r/launch_configuration.html#ebs_block_device." - type = "list" + type = any default = [] } @@ -333,7 +345,7 @@ variable "ebs_block_devices_content_connector_dc" { # Example: ["/dev/xvde:/mnt/map1","/dev/xvdf:/mnt/map2"] variable "device_to_mount_target_map_content_connector_dc" { description = "List of device to mount target entries." - type = "list" + type = list(string) default = [] } @@ -349,8 +361,12 @@ variable "device_to_mount_target_map_content_connector_dc" { # }] variable "additional_instance_tags_content_connector_dc" { description = "List of tags to add to the content_connector datacenter instances. The entries of the list are maps consiting of key, value and propagate at launch." - type = "list" - default = [] + type = list(object({ + key = string + value = string + propagate_at_launch = bool + })) + default = [] } variable "efs_dns_name" { @@ -376,6 +392,7 @@ variable "consul_instance_type" { variable "ecr_repositories" { description = "List of names for the ECR repositories to be created. Nomad will use them to get docker images from it in the job files." - type = "list" + type = list(string) default = [] } + diff --git a/versions.tf b/versions.tf new file mode 100644 index 0000000..ac97c6a --- /dev/null +++ b/versions.tf @@ -0,0 +1,4 @@ + +terraform { + required_version = ">= 0.12" +}