Skip to content

Commit

Permalink
terraform-aws-multi-az-subnets (#1)
Browse files Browse the repository at this point in the history
* Initial commit

* Update `README`

* Rename tag to `AZ`

* Update `README`

* Update `README`

* Update `README`

* Add `locals`

* Add `enabled` flag

* Add NAT Gateway per AZ

* Update `README`

* Add Map of AZ names to NAT Gateway IDs

* Update `README`

* Update `README`

* Use `var.availability_zones` and `var.az_ngw_ids` in private subnets

* Update private subnets

* terraform fmt

* Set `max_subnets` to 6

* Use `var.vpc_id`

* Add `var.az_ngw_count`

* Add examples

* Update `README`
  • Loading branch information
aknysh authored Nov 9, 2017
1 parent a1a6a80 commit b2793ef
Show file tree
Hide file tree
Showing 25 changed files with 847 additions and 1 deletion.
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Compiled files
*.tfstate
*.tfstate.backup

# Module directory
.terraform
.idea
*.iml
16 changes: 16 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
addons:
apt:
packages:
- git
- make
- curl

install:
- make init

script:
- make terraform:install
- make terraform:get-plugins
- make terraform:get-modules
- make terraform:lint
- make terraform:validate
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@
same "printed page" as the copyright notice for easier
identification within third-party archives.

Copyright {yyyy} {name of copyright owner}
Copyright 2017 Cloud Posse, LLC

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down
6 changes: 6 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
SHELL := /bin/bash

-include $(shell curl -sSL -o .build-harness "https://git.io/build-harness"; echo .build-harness)

lint:
$(SELF) terraform:install terraform:get-modules terraform:get-plugins terraform:lint terraform:validate
179 changes: 179 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
# terraform-aws-multi-az-subnets [![Build Status](https://travis-ci.org/cloudposse/terraform-aws-multi-az-subnets.svg)](https://travis-ci.org/cloudposse/terraform-aws-multi-az-subnets)

Terraform module for multi-AZ [`subnets`](http://docs.aws.amazon.com/AmazonVPC/latest/UserGuide/VPC_Subnets.html) provisioning.

The module creates private or public subnets in the provided Availability Zones.

The public subnets are routed to the Internet Gateway specified by `var.igw_id`.

`nat_gateway_enabled` flag controls the creation of NAT Gateways in public subnets.

The private subnets are routed to the NAT Gateways provided in the `var.az_ngw_ids` map.


## Usage

```hcl
module "vpc" {
source = "git::https://github.com/cloudposse/terraform-aws-vpc.git?ref=master"
namespace = "${var.namespace}"
name = "vpc"
stage = "${var.stage}"
cidr_block = "${var.cidr_block}"
}
locals {
public_cidr_block = "${cidrsubnet(module.vpc.vpc_cidr_block, 1, 0)}"
private_cidr_block = "${cidrsubnet(module.vpc.vpc_cidr_block, 1, 1)}"
}
module "public_subnets" {
source = "git::https://github.com/cloudposse/terraform-aws-multi-az-subnets.git?ref=master"
namespace = "${var.namespace}"
stage = "${var.stage}"
name = "${var.name}"
availability_zones = ["us-east-1a", "us-east-1b", "us-east-1c"]
vpc_id = "${module.vpc.vpc_id}"
cidr_block = "${local.public_cidr_block}"
type = "public"
igw_id = "${module.vpc.igw_id}"
nat_gateway_enabled = "true"
}
module "private_subnets" {
source = "git::https://github.com/cloudposse/terraform-aws-multi-az-subnets.git?ref=master"
namespace = "${var.namespace}"
stage = "${var.stage}"
name = "${var.name}"
availability_zones = ["us-east-1a", "us-east-1b", "us-east-1c"]
vpc_id = "${module.vpc.vpc_id}"
cidr_block = "${local.private_cidr_block}"
type = "private"
# Map of AZ names to NAT Gateway IDs that was created in "public_subnets" module
az_ngw_ids = "${module.public_subnets.az_ngw_ids}"
# Need to explicitly provide the count since Terraform currently can't use dynamic count on computed resources from different modules
# https://github.com/hashicorp/terraform/issues/10857
# https://github.com/hashicorp/terraform/issues/12125
# https://github.com/hashicorp/terraform/issues/4149
az_ngw_count = 3
}
```


# Inputs

| Name | Default | Description | Required |
|:------------------------------|:---------------------:|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:--------:|
| `namespace` | `` | Namespace (_e.g._ `cp` or `cloudposse`) | Yes |
| `stage` | `` | Stage (_e.g._ `prod`, `dev`, `staging`) | Yes |
| `name` | `` | Application or solution name (_e.g._ `myapp`) | Yes |
| `delimiter` | `-` | Delimiter to use between `name`, `namespace`, `stage`, `attributes` | No |
| `attributes` | `[]` | Additional attributes (_e.g._ `policy` or `role`) | No |
| `tags` | `{}` | Additional tags (_e.g._ `map("BusinessUnit","XYZ")` | No |
| `max_subnets` | `16` | Maximum number of subnets that can be created. This variable is used for CIDR blocks calculation. MUST be greater than the length of `availability_zones` list | Yes |
| `availability_zones` | [] | List of Availability Zones (e.g. `["us-east-1a", "us-east-1b", "us-east-1c"]`) | Yes |
| `type` | `private` | Type of subnets to create (`private` or `public`) | Yes |
| `vpc_id` | `` | VPC ID where subnets are created (_e.g._ `vpc-aceb2723`) | Yes |
| `cidr_block` | `` | Base CIDR block which is divided into subnet CIDR blocks (_e.g._ `10.0.0.0/24`) | No |
| `igw_id` | `` | Only for public subnets. Internet Gateway ID which is used as a default route when creating public subnets (_e.g._ `igw-9c26a123`) | Yes |
| `public_network_acl_id` | `` | ID of Network ACL which is added to the public subnets. If empty, a new ACL will be created | No |
| `private_network_acl_id` | `` | ID of Network ACL which is added to the private subnets. If empty, a new ACL will be created | No |
| `public_network_acl_egress` | see [variables.tf](https://github.com/cloudposse/terraform-aws-multi-az-subnets/blob/master/variables.tf) | Egress rules which are added to the new Public Network ACL | No |
| `public_network_acl_ingress` | see [variables.tf](https://github.com/cloudposse/terraform-aws-multi-az-subnets/blob/master/variables.tf) | Ingress rules which are added to the new Public Network ACL | No |
| `private_network_acl_egress` | see [variables.tf](https://github.com/cloudposse/terraform-aws-multi-az-subnets/blob/master/variables.tf) | Egress rules which are added to the new Private Network ACL | No |
| `private_network_acl_ingress` | see [variables.tf](https://github.com/cloudposse/terraform-aws-multi-az-subnets/blob/master/variables.tf) | Ingress rules which are added to the new Private Network ACL | No |
| `enabled` | `true` | Set to `false` to prevent the module from creating any resources | No |
| `nat_gateway_enabled` | `true` | Flag to enable/disable NAT Gateways creation in public subnets | No |
| `az_ngw_ids` | {} | Map of AZ names to NAT Gateway IDs which are used as default routes when creating private subnets. Only for private subnets | No |
| `az_ngw_count` | 0 | Count of items in the `az_ngw_ids` map. Needs to be explicitly provided since Terraform currently can't use dynamic count on computed resources from different modules. https://github.com/hashicorp/terraform/issues/10857 | No |


## Outputs

| Name | Description |
|:--------------------------|:---------------------------------------------------------------|
| az_subnet_ids | Map of AZ names to subnet IDs |
| az_route_table_ids | Map of AZ names to Route Table IDs |
| az_ngw_ids | Map of AZ names to NAT Gateway IDs (only for public subnets) |


Given the following configuration

```hcl
module "vpc" {
source = "git::https://github.com/cloudposse/terraform-aws-vpc.git?ref=master"
namespace = "${var.namespace}"
name = "vpc"
stage = "${var.stage}"
cidr_block = "${var.cidr_block}"
}
locals {
public_cidr_block = "${cidrsubnet(module.vpc.vpc_cidr_block, 1, 0)}"
private_cidr_block = "${cidrsubnet(module.vpc.vpc_cidr_block, 1, 1)}"
}
module "public_subnets" {
source = "git::https://github.com/cloudposse/terraform-aws-multi-az-subnets.git?ref=master"
namespace = "${var.namespace}"
stage = "${var.stage}"
name = "${var.name}"
availability_zones = ["us-east-1a", "us-east-1b", "us-east-1c"]
vpc_id = "${module.vpc.vpc_id}"
cidr_block = "${local.public_cidr_block}"
type = "public"
igw_id = "${module.vpc.igw_id}"
nat_gateway_enabled = "true"
}
module "private_subnets" {
source = "git::https://github.com/cloudposse/terraform-aws-multi-az-subnets.git?ref=master"
namespace = "${var.namespace}"
stage = "${var.stage}"
name = "${var.name}"
availability_zones = ["us-east-1a", "us-east-1b", "us-east-1c"]
vpc_id = "${module.vpc.vpc_id}"
cidr_block = "${local.private_cidr_block}"
type = "private"
az_ngw_ids = "${module.public_subnets.az_ngw_ids}"
az_ngw_count = 3
}
output "private_az_subnet_ids" {
value = "${module.private_subnets.az_subnet_ids}"
}
output "public_az_subnet_ids" {
value = "${module.public_subnets.az_subnet_ids}"
}
```

the output Maps of AZ names to subnet IDs look like these

```hcl
public_az_subnet_ids = {
us-east-1a = subnet-ea58d78e
us-east-1b = subnet-556ee131
us-east-1c = subnet-6f54db0b
}
private_az_subnet_ids = {
us-east-1a = subnet-376de253
us-east-1b = subnet-9e53dcfa
us-east-1c = subnet-a86fe0cc
}
```

and the created subnet IDs could be found by the AZ names using `map["key"]` or [`lookup(map, key, [default])`](https://www.terraform.io/docs/configuration/interpolation.html#lookup-map-key-default-),

for example:

`public_az_subnet_ids["us-east-1a"]`

`lookup(private_az_subnet_ids, "us-east-1b")`


## License

Apache 2 License. See [`LICENSE`](LICENSE) for full details.
2 changes: 2 additions & 0 deletions examples/only-private-subnets/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
*.tfstate
*.tfstate.backup
14 changes: 14 additions & 0 deletions examples/only-private-subnets/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
locals {
private_cidr_block = "${cidrsubnet(var.cidr_block, 1, 0)}"
}

module "private_subnets" {
source = "../../"
namespace = "${var.namespace}"
stage = "${var.stage}"
name = "${var.name}"
availability_zones = ["us-east-1a", "us-east-1b", "us-east-1c"]
vpc_id = "${var.vpc_id}"
cidr_block = "${local.private_cidr_block}"
type = "private"
}
11 changes: 11 additions & 0 deletions examples/only-private-subnets/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
output "private_az_subnet_ids" {
value = "${module.private_subnets.az_subnet_ids}"
}

output "private_az_ngw_ids" {
value = "${module.private_subnets.az_ngw_ids}"
}

output "private_az_route_table_ids" {
value = "${module.private_subnets.az_route_table_ids}"
}
24 changes: 24 additions & 0 deletions examples/only-private-subnets/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
variable "namespace" {
description = "Namespace (e.g. `cp` or `cloudposse`)"
type = "string"
}

variable "stage" {
description = "Stage (e.g. `prod`, `dev`, `staging`)"
type = "string"
}

variable "name" {
type = "string"
description = "Application or solution name"
}

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

variable "cidr_block" {
type = "string"
description = "Base CIDR block which is divided into subnet CIDR blocks (e.g. `10.0.0.0/16`)"
}
2 changes: 2 additions & 0 deletions examples/only-public-subnets/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
*.tfstate
*.tfstate.backup
16 changes: 16 additions & 0 deletions examples/only-public-subnets/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
locals {
public_cidr_block = "${cidrsubnet(var.cidr_block, 1, 0)}"
}

module "public_subnets" {
source = "../../"
namespace = "${var.namespace}"
stage = "${var.stage}"
name = "${var.name}"
availability_zones = ["us-east-1a", "us-east-1b", "us-east-1c"]
vpc_id = "${var.vpc_id}"
cidr_block = "${local.public_cidr_block}"
type = "public"
igw_id = "${var.igw_id}"
nat_gateway_enabled = "false"
}
11 changes: 11 additions & 0 deletions examples/only-public-subnets/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
output "public_az_subnet_ids" {
value = "${module.public_subnets.az_subnet_ids}"
}

output "public_az_ngw_ids" {
value = "${module.public_subnets.az_ngw_ids}"
}

output "public_az_route_table_ids" {
value = "${module.public_subnets.az_route_table_ids}"
}
30 changes: 30 additions & 0 deletions examples/only-public-subnets/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
variable "namespace" {
description = "Namespace (e.g. `cp` or `cloudposse`)"
type = "string"
}

variable "stage" {
description = "Stage (e.g. `prod`, `dev`, `staging`)"
type = "string"
}

variable "name" {
type = "string"
description = "Application or solution name"
}

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

variable "cidr_block" {
type = "string"
description = "Base CIDR block which is divided into subnet CIDR blocks (e.g. `10.0.0.0/16`)"
}

variable "igw_id" {
type = "string"
description = "Internet Gateway ID that is used as a default route when creating public subnets (e.g. `igw-9c26a123`)"
default = ""
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
*.tfstate
*.tfstate.backup
28 changes: 28 additions & 0 deletions examples/public-and-private-subnets-no-nat-gateways/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
locals {
public_cidr_block = "${cidrsubnet(var.cidr_block, 1, 0)}"
private_cidr_block = "${cidrsubnet(var.cidr_block, 1, 1)}"
}

module "public_subnets" {
source = "../../"
namespace = "${var.namespace}"
stage = "${var.stage}"
name = "${var.name}"
availability_zones = ["us-east-1a", "us-east-1b", "us-east-1c"]
vpc_id = "${var.vpc_id}"
cidr_block = "${local.public_cidr_block}"
type = "public"
igw_id = "${var.igw_id}"
nat_gateway_enabled = "false"
}

module "private_subnets" {
source = "../../"
namespace = "${var.namespace}"
stage = "${var.stage}"
name = "${var.name}"
availability_zones = ["us-east-1a", "us-east-1b", "us-east-1c"]
vpc_id = "${var.vpc_id}"
cidr_block = "${local.private_cidr_block}"
type = "private"
}
23 changes: 23 additions & 0 deletions examples/public-and-private-subnets-no-nat-gateways/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
output "private_az_subnet_ids" {
value = "${module.private_subnets.az_subnet_ids}"
}

output "public_az_subnet_ids" {
value = "${module.public_subnets.az_subnet_ids}"
}

output "private_az_ngw_ids" {
value = "${module.private_subnets.az_ngw_ids}"
}

output "public_az_ngw_ids" {
value = "${module.public_subnets.az_ngw_ids}"
}

output "private_az_route_table_ids" {
value = "${module.private_subnets.az_route_table_ids}"
}

output "public_az_route_table_ids" {
value = "${module.public_subnets.az_route_table_ids}"
}
Loading

0 comments on commit b2793ef

Please sign in to comment.