Skip to content

Commit

Permalink
Merge pull request #3 from playgroundcloud/PX-39-nwk
Browse files Browse the repository at this point in the history
Px-39-nwk
  • Loading branch information
SebRosander authored Nov 11, 2020
2 parents 81cbbba + 219592b commit cbdcd80
Show file tree
Hide file tree
Showing 27 changed files with 1,445 additions and 2 deletions.
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* @isasand @twiden @SebRosander @marcmodin
34 changes: 34 additions & 0 deletions .github/workflows/terraform-fmt.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: 'terraform-fmt'

on:
push:
branches-ignore:
- master
paths-ignore:
- '**.md'

defaults:
run:
shell: bash

jobs:
# Job that makes sure that ALL Terraform code is in a canonical format
terraform_fmt:
name: terraform fmt
runs-on: 'ubuntu-latest'
steps:
# Checkout the repository to the GitHub Actions runner
- name: Checkout
uses: actions/checkout@v2

# Install the latest version of Terraform CLI
- name: Setup Terraform
uses: hashicorp/setup-terraform@v1

# Initialize a new or existing Terraform working directory by creating initial files, downloading modules, etc.
- name: Terraform Init
run: terraform init

# Checks that ALL Terraform configuration files adhere to a canonical format
- name: Terraform Format
run: terraform fmt -check -recursive
43 changes: 43 additions & 0 deletions .github/workflows/terraform-validate.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
name: 'terraform-validate'

on:
push:
branches-ignore:
- master
paths-ignore:
- '**.md'

defaults:
run:
shell: bash

jobs:
# Job that makes sure that the syntax in the module is valid
terraform_validate:
name: terraform validate
runs-on: 'ubuntu-latest'
defaults:
run:
working-directory: ./
steps:
# Checkout the repository to the GitHub Actions runner
- name: Checkout
uses: actions/checkout@v2

# Install the latest version of Terraform CLI
- name: Setup Terraform
uses: hashicorp/setup-terraform@v1

# Create a provider.tf file to be able to validate module syntax.
# This is a issue which is tracked here: https://github.com/hashicorp/terraform/pull/24896
- name: Create provider.tf
run: |
printf 'provider "aws" { \n
region = "${{ secrets.AWS_DEFAULT_REGION }}" \n
}' > provider.tf
# Initialize a new or existing Terraform working directory by creating initial files, downloading modules, etc.
- name: Terraform Init
run: terraform init

- name: Terraform Validate
run: terraform validate
46 changes: 46 additions & 0 deletions .github/workflows/terratest.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
name: 'terratest'

on:
pull_request:
branches:
- master
paths-ignore:
- '**.md'

env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }}

jobs:
# Job that runs terratest and runs integration test on the infrastructure provisioned.
terratest:
name: terratest
runs-on: 'ubuntu-latest'
defaults:
run:
shell: bash
working-directory: test

steps:
# Checkout the repository to the GitHub Actions runner
- name: Checkout
uses: actions/checkout@v2

# Install the latest version of Terraform CLI
- name: Setup Terraform
uses: hashicorp/setup-terraform@v1
with:
terraform_wrapper: false

# Install and set up Golang
- name: Set Up Go
uses: actions/setup-go@v2

# Get all golang dependencies
- name: Get dependencies
run: go mod tidy

# Run terratest
- name: Run Terratest
run: go test -timeout 90m
32 changes: 32 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Local .terraform directories
**/.terraform/*

# .tfstate files
*.tfstate
*.tfstate.*

# Crash log files
crash.log

# Ignore any .tfvars files that are generated automatically for each Terraform run. Most
# .tfvars files are managed as part of configuration and so should be included in
# version control.
#
# example.tfvars

# Ignore override files as they are usually used to override resources locally and so
# are not checked in
override.tf
override.tf.json
*_override.tf
*_override.tf.json

# Include override files you do wish to add to version control using negated pattern
#
# !example_override.tf

# Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan
*tfplan*

# IntelliJ IDEA
*.idea
171 changes: 169 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,169 @@
# terraform-aws-nwk
AWS Terraform Network module
![terratest](https://github.com/playgroundcloud/terraform-aws-nwk/workflows/terratest/badge.svg)
![terraform fmt](https://github.com/playgroundcloud/terraform-aws-nwk/workflows/terraform-fmt/badge.svg)
![terraform validate](https://github.com/playgroundcloud/terraform-aws-nwk/workflows/terraform-validate/badge.svg)

# Terraform AWS Network
This module delivers the standard VPC for a solution environment.

## Provisional Instructions
#### Minimal
```hcl
module "nwk" {
source = "[email protected]:playgroundcloud/terraform-aws-nwk.git?ref=vX.Y.Z"
name = "test"
vpc_cidr = "10.0.0.0/16"
subnets_byname = ["test", "test1", "test2"]
availability_zone = ["eu-north-1a"]
}
```
#### High Availability
```hcl
module "nwk" {
source = "[email protected]:playgroundcloud/terraform-aws-nwk.git?ref=vX.Y.Z"
name = "test"
vpc_cidr = "10.0.0.0/16"
subnets_byname = ["test", "test1", "test2"]
availability_zone = ["eu-north-1a","eu-north-1b","eu-north-1c"]
}
```

#### 2-tier Public / Private with High Availability
```hcl
module "nwk" {
source = "[email protected]:playgroundcloud/terraform-aws-nwk.git?ref=vX.Y.Z"
name = "test"
vpc_cidr = "10.0.0.0/16"
subnets_byname = ["Front-1", "Front-2", "Front-3", "Back-1", "Back-2", "Back-3"]
public_subnets = ["Front-1", "Front-2", "Front-3"]
availability_zone = ["eu-north-1a","eu-north-1b","eu-north-1c"]
}
```

#### 3-tier Public / Private with High Availability
```hcl
module "nwk" {
source = "[email protected]:playgroundcloud/terraform-aws-nwk.git?ref=vX.Y.Z"
name = "test"
vpc_cidr = "10.0.0.0/16"
subnets_byname = ["Front-1", "Front-2", "Front-3", "Back-1", "Back-2", "Back-3", "DB-1", "DB-2", "DB-3"]
public_subnets = ["Front-1", "Front-2", "Front-3"]
availability_zone = ["eu-north-1a","eu-north-1b","eu-north-1c"]
}
```

#### Subnet By Bits Read More Here: [Additional Notes](#additional-notes)
```hcl
module "nwk" {
source = "[email protected]:playgroundcloud/terraform-aws-nwk.git?ref=vX.Y.Z"
name = "test"
vpc_cidr = "10.0.0.0/16"
subnets_bybits = [{ name = "App", bits = 1, net = 1 }, { name = "Front", bits = 2, net = 1 }, { name = "DB", bits = 3, net = 1 }, { name = "Admin", bits = 3, net = 0 }]
availability_zone = ["eu-north-1a", "eu-north-1b", "eu-north-1c"]
}
```

#### Subnet By Cidr Read More Here: [Additional Notes](#additional-notes)
```hcl
module "nwk" {
source = "[email protected]:playgroundcloud/terraform-aws-nwk.git?ref=vX.Y.Z"
name = "test"
vpc_cidr = "10.0.0.0/16"
subnets_bycidr = [{ name = "App", cidr = "10.0.0.128/26" }, { name = "Front", cidr = "10.0.0.64/26" }, { name = "DB", cidr = "10.0.0.32/27" }, { name = "Admin", cidr = "10.0.0.0/27" }]
availability_zone = ["eu-north-1a", "eu-north-1b", "eu-north-1c"]
}
```

### Variables
* `name` | (Required) - String
Name to be used on all the resources as identifier

**VPC Variables:**
* `vpc_cidr` | (Required) - String
The CIDR block for the VPC.

* `instance_tenancy` | (Optional) - String
A tenancy option for instances launched into the VPC.
Each instance that you launch into a VPC has a tenancy attribute. This attribute has the following values:
`default` - Your instance runs on shared hardware.
`dedicated` - Your instance runs on single-tenant hardware.
`host` - Your instance runs on a Dedicated Host, which is an isolated server with configurations that you can control.
After you launch an instance, there are some limitations to changing its tenancy.
You cannot change the tenancy of an instance from `default` to `dedicated` or `host` after you've launched it.
You cannot change the tenancy of an instance from `dedicated` or `host` to `default` after you've launched it.
*Default: "default"*

* `vpc_tags` (Optional) - Map(string)
Additional tags for the VPC
*Default: {}*

**Subnet Variables**
You can read up on different subnet sizing under [Additional Notes](#additional-notes)
* `availability_zone` | (Required) - List(string)
The AZ for the subnet

* `subnet_bits` | (Optional) - Number
*Default: -1*

One of `subnets_byname`, `subnets_bybits` or `subnets_bycidr` must be used:
* `subnets_byname` | (Required/Optional) - List(string)
The name of the subnets you want to create. Each name will create a new subnet. The subnets will be divided into 8 equally-sized if `subnet_bits` isn't changed.
*Default: []*

* `subnets_bybits` | (Required/Optional) - List(object({name=string,bits=number,net=number}))
List of object to create your subnet. This will create subnet based on bits and net set by the user.
Please read more under [additional notes](#additional-notes).
*Default: []*

* `subnets_bycidr` | (Required/Optional) - List(object({name=string,cidr=string}))
List of object to create your subnet. This will create subnets based cidr set by the user.
Please read more under [additional notes](#additional-notes).
*Default: []*

* `public_subnets` | (Optional) - List(string)
The names of which subnets you want to set as public subnets.
*Default: []*

* `bastion_subnets` | (Optional) - List(string)
The name of the subnet which you want to host your bastion host within.
*Default: []*

**Internet Gateway**
* `internet_gateway_tags` | (Optional) - Map(string)
Additional tags for the Internet Gateway.
*Default: {}*

* `route_table_public_tags` | (Optional) - Map(string)
Additional tags for the Public Route Table.
*Default: {}*

### Additional Notes
#### Subnet Sizing
There are 3 ways of specifying subnets: `subnets_byname` - a simple list; `subnets_bybits` - a list of maps with names, network numbers and bits; and `subnets_bycidr` - specifying the exact CIDR. The two first construct the subnets relative to the CIDR of the VPC regarding both size and ip-segment. The third is hard-coded.

#### subnets_byname
If you just do `subnets_byname`, then the VPC will be divided into 8 equally-sized parts and subnet CIDRs will be allocated to that. You can use `subnet_bits` to set how many additional bits used for subnets - the default is 3, which gives 2^3 = 8 subnets.

#### subnets_bybits
Here you get more flexibility, the subnets don't have to be of the same size, but you have to do the puzzle yourself.

Let's say you want to use half the available space for application servers, 25% for frontend, and split the remains between database and admin hosts:
`subnets_bybits = [{name="App", bits=1, net=1},{name="Front", bits=2, net=1},{name="DB", bits=3, net=1},{name="Admin", bits=3, net=0}]`

#### subnets_bycidr
Here you specify the exact CIDR you want for each subnet, but you now need to do this specifically for each environment as they have different VPC CIDR's. Using the same layout as above, this could be.
`subnets_bycidr = [{name="App", cidr="10.0.0.128/26"},{name="Front", cidr="10.0.0.64/26"},{name="DB", cidr="10.0.0.32/27"},{name="Admin", cidr="10.0.0.0/27"}]`

#### Adding it up
Internally, maps are constructed to the subnets and their CIDR's and then the maps are merged to provide the actual map which is used to generate subnets from.
So, you can even combine the 3 methods if you want to. If you use the same names, then subnets defined by name will be overwritten by the two other methods, and subnets defined by bits will overwrite by subnets_bycidr.

#### Network numbers and bits
The diagram below tries to illustrate how additional subnet bits results in more subnets

![image](./picture/subnetsizes.PNG)

### Outputs
`vpc`

`subnets`

38 changes: 38 additions & 0 deletions internet_gateway.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Add internetgateway and routing on local.public_subnets
resource "aws_internet_gateway" "igw" {
count = local.public_subnets != {} || local.bastion_subnets != {} ? 1 : 0
vpc_id = aws_vpc.main.id
tags = merge(
{
"Name" = format("%s", var.name)
},
var.internet_gateway_tags
)
}

resource "aws_route_table" "igw" {
count = local.public_subnets != {} || local.bastion_subnets != {} ? 1 : 0
vpc_id = aws_vpc.main.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.igw[0].id
}
tags = merge(
{
"Name" = format("%s", var.name)
},
var.route_table_public_tags
)
}

resource "aws_route_table_association" "igw" {
for_each = local.public_subnets
route_table_id = aws_route_table.igw[0].id
subnet_id = aws_subnet.subnets[each.key].id
}

resource "aws_route_table_association" "igw_bastion" {
for_each = local.bastion_subnets
route_table_id = aws_route_table.igw[0].id
subnet_id = aws_subnet.subnets[each.key].id
}
11 changes: 11 additions & 0 deletions locals.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
locals {
subnetaddbits = var.subnet_bits == -1 ? 3 : var.subnet_bits
subnetmap = tomap(merge(
{ for subnet in var.subnets_byname : subnet => { cidr = cidrsubnet(var.vpc_cidr, local.subnetaddbits, index(var.subnets_byname, subnet)), az = element(var.availability_zone, index(var.subnets_byname, subnet)) } },
{ for subnet in var.subnets_bybits : subnet.name => { cidr = cidrsubnet(var.vpc_cidr, subnet.bits, subnet.net), az = element(var.availability_zone, index(var.subnets_bybits, subnet)) } },
{ for subnet in var.subnets_bycidr : subnet.name => { cidr = subnet.cidr, az = element(var.availability_zone, index(var.subnets_bycidr, subnet)) } },
))
public_subnets = { for net in keys(local.subnetmap) : net => net if contains(var.public_subnets, net) == true }
bastion_subnets = { for net in keys(local.subnetmap) : net => net if contains(var.bastion_subnets, net) == true }
non_public_subnets = { for net in keys(local.subnetmap) : net => net if contains(var.public_subnets, net) != true }
}
3 changes: 3 additions & 0 deletions main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
terraform {
required_version = "~> 0.13"
}
Loading

0 comments on commit cbdcd80

Please sign in to comment.