initial commit
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
This module performs the following tasks:
|
||||
|
||||
- Create VPC, vpcflow log
|
||||
- Create subnets in every AZ
|
||||
- Create IGW, NGW
|
||||
- Create s3 and ddb endpoints which are free
|
||||
|
||||
|
||||
## Requirements
|
||||
|
||||
| Name | Version |
|
||||
|------|---------|
|
||||
| terraform | >= 1.3.0 |
|
||||
| aws | >= 5.0 |
|
||||
|
||||
## Providers
|
||||
|
||||
| Name | Version |
|
||||
|------|---------|
|
||||
| aws | >= 5.0 |
|
||||
| random | n/a |
|
||||
|
||||
## Modules
|
||||
|
||||
| Name | Source | Version |
|
||||
|------|--------|---------|
|
||||
| private-route | ./modules/RouteTables | n/a |
|
||||
| private-route-multiaz | ./modules/RouteTables | n/a |
|
||||
| vpc-ep | ../vpc-endpoints | n/a |
|
||||
|
||||
## Resources
|
||||
|
||||
| Name | Type |
|
||||
|------|------|
|
||||
| [aws_cloudwatch_log_group.vpcflowlog-loggroup](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/cloudwatch_log_group) | resource |
|
||||
| [aws_default_security_group.default-sg](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/default_security_group) | resource |
|
||||
| [aws_eip.ngw-eip](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/eip) | resource |
|
||||
| [aws_eip.ngw-eip-multiaz](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/eip) | resource |
|
||||
| [aws_flow_log.vpc-flowlog](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/flow_log) | resource |
|
||||
| [aws_flow_log.vpc-flowlog-s3](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/flow_log) | resource |
|
||||
| [aws_iam_role.vpcflowlog-role](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role) | resource |
|
||||
| [aws_iam_role_policy.vpcflowlog-role-policy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/iam_role_policy) | resource |
|
||||
| [aws_internet_gateway.igw](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/internet_gateway) | resource |
|
||||
| [aws_nat_gateway.ngw](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/nat_gateway) | resource |
|
||||
| [aws_nat_gateway.ngw-multiaz](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/nat_gateway) | resource |
|
||||
| [aws_route.public-routes](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route) | resource |
|
||||
| [aws_route_table.public-route-table](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table) | resource |
|
||||
| [aws_route_table_association.public_route_association](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table_association) | resource |
|
||||
| [aws_subnet.private-subnets](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/subnet) | resource |
|
||||
| [aws_subnet.public-subnets](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/subnet) | resource |
|
||||
| [aws_vpc.vpc](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc) | resource |
|
||||
| [aws_vpc_ipv4_cidr_block_association.additional_cidr](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc_ipv4_cidr_block_association) | resource |
|
||||
| [random_id.rid](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/id) | resource |
|
||||
| [aws_availability_zones.available-az](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/availability_zones) | data source |
|
||||
| [aws_caller_identity.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/caller_identity) | data source |
|
||||
| [aws_default_tags.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/default_tags) | data source |
|
||||
|
||||
## Inputs
|
||||
|
||||
| Name | Description | Type | Default | Required |
|
||||
|------|-------------|------|---------|:--------:|
|
||||
| create-free-vpc-endpoints | Whether to deploy free VPC endpoints (s3 and dynamodb) | `bool` | `true` | no |
|
||||
| create-nat-gateway | Deploy NAT gateway for private subnets | `bool` | `false` | no |
|
||||
| enable-flow-log | Whether to enable VPC flowlog | `bool` | `true` | no |
|
||||
| flow-log-bucket-arn | Arn of S3 bucket to be used for flow logging | `string` | `null` | no |
|
||||
| flow-log-destination | Destination of flowlog. Valid destinations are s3 or cwlog | `string` | `null` | no |
|
||||
| multiaz-nat-gateway | Whether to deploy 1 NAT gateway for each AZ | `bool` | `false` | no |
|
||||
| private-subnet-cidrs | Private subnet CIDRs | `list(string)` | `[]` | no |
|
||||
| public-subnet-cidrs | Public subnet CIDRs | `list(string)` | `[]` | no |
|
||||
| resource-prefix | Prefix of resource | `string` | n/a | yes |
|
||||
| secondary\_cidr\_blocks | Additional cidr blocks | `list(string)` | `[]` | no |
|
||||
| vpc-cidr | VPC primary CIDR | `string` | n/a | yes |
|
||||
| vpcflowlog-cwl-loggroup-key-arn | KMS key arn for cwlog encryption | `string` | n/a | yes |
|
||||
| vpcflowlog-retain-days | Log retention period for CWlogs | `number` | `90` | no |
|
||||
|
||||
## Outputs
|
||||
|
||||
| Name | Description |
|
||||
|------|-------------|
|
||||
| private-subnet-details | Details of private subnets |
|
||||
| private-subnet-ids | List of private subnet id |
|
||||
| private\_subnets | Private subnet cidrs |
|
||||
| public-route-table-id | Public route table id |
|
||||
| public-subnet-details | Details of public subnets |
|
||||
| public-subnet-ids | List of public subnet id |
|
||||
| public\_subnets | Public subnet cidrs |
|
||||
| secondary\_cidr\_blocks | Secondary CIDR block |
|
||||
| vpc-cidr | VPC primary cidr |
|
||||
| vpc\_id | VPC id |
|
||||
|
||||
---
|
||||
## Authorship
|
||||
This module was developed by xpk.
|
||||
@@ -0,0 +1,12 @@
|
||||
module "vpc-subnets" {
|
||||
source = "../../modules/networking/vpc-subnet-manual"
|
||||
|
||||
resource-prefix = local.resource-prefix
|
||||
private-subnet-cidrs = ["172.17.0.0/24", "172.17.1.0/24"]
|
||||
public-subnet-cidrs = ["172.17.10.0/24", "172.17.11.0/24"]
|
||||
vpc-cidr = "172.17.0.0/16"
|
||||
enable-flow-log = false
|
||||
vpcflowlog-cwl-loggroup-key-arn = ""
|
||||
create-nat-gateway = true
|
||||
create-free-vpc-endpoints = true
|
||||
}
|
||||
@@ -0,0 +1,203 @@
|
||||
data "aws_caller_identity" "this" {}
|
||||
|
||||
data "aws_availability_zones" "available-az" {
|
||||
state = "available"
|
||||
}
|
||||
|
||||
data "aws_default_tags" "this" {
|
||||
lifecycle {
|
||||
postcondition {
|
||||
condition = length(self.tags) >= 1
|
||||
error_message = "Validation failed: Provider default_tags not set."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
locals {
|
||||
# no-az = 2 # hard-coding to 2AZ
|
||||
vpc-cidr = var.vpc-cidr
|
||||
}
|
||||
|
||||
resource "aws_subnet" "private-subnets" {
|
||||
count = length(var.private-subnet-cidrs)
|
||||
vpc_id = aws_vpc.vpc.id
|
||||
availability_zone = element(data.aws_availability_zones.available-az.names, count.index % 2)
|
||||
cidr_block = var.private-subnet-cidrs[count.index]
|
||||
tags = merge(data.aws_default_tags.this.tags, {
|
||||
Name = "${var.resource-prefix}-private-${split("-", element(data.aws_availability_zones.available-az.names, count.index))[2]}-${count.index + 1}"
|
||||
})
|
||||
}
|
||||
|
||||
resource "aws_subnet" "public-subnets" {
|
||||
count = length(var.public-subnet-cidrs)
|
||||
vpc_id = aws_vpc.vpc.id
|
||||
availability_zone = element(data.aws_availability_zones.available-az.names, count.index % 2)
|
||||
cidr_block = var.public-subnet-cidrs[count.index]
|
||||
tags = merge(data.aws_default_tags.this.tags, {
|
||||
Name = "${var.resource-prefix}-public-${split("-", element(data.aws_availability_zones.available-az.names, count.index))[2]}-${count.index + 1}"
|
||||
})
|
||||
}
|
||||
|
||||
resource "aws_vpc" "vpc" {
|
||||
cidr_block = var.vpc-cidr
|
||||
enable_dns_hostnames = true
|
||||
enable_dns_support = true
|
||||
|
||||
tags = {
|
||||
Name = "${var.resource-prefix}-vpc"
|
||||
}
|
||||
|
||||
lifecycle {
|
||||
create_before_destroy = true
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_vpc_ipv4_cidr_block_association" "additional_cidr" {
|
||||
for_each = toset(var.secondary_cidr_blocks)
|
||||
vpc_id = aws_vpc.vpc.id
|
||||
cidr_block = each.value
|
||||
}
|
||||
|
||||
resource "aws_internet_gateway" "igw" {
|
||||
count = length(var.public-subnet-cidrs) > 0 ? 1 : 0
|
||||
vpc_id = aws_vpc.vpc.id
|
||||
|
||||
tags = {
|
||||
Name = "${var.resource-prefix}-igw"
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_eip" "ngw-eip" {
|
||||
count = var.create-nat-gateway ? 1 : 0
|
||||
domain = "vpc"
|
||||
depends_on = [aws_internet_gateway.igw]
|
||||
}
|
||||
|
||||
resource "aws_nat_gateway" "ngw" {
|
||||
count = var.create-nat-gateway && !var.multiaz-nat-gateway ? 1 : 0
|
||||
allocation_id = aws_eip.ngw-eip[0].id
|
||||
subnet_id = aws_subnet.public-subnets[0].id
|
||||
|
||||
tags = {
|
||||
Name = "${var.resource-prefix}-ngw"
|
||||
}
|
||||
depends_on = [aws_internet_gateway.igw]
|
||||
}
|
||||
|
||||
resource "aws_eip" "ngw-eip-multiaz" {
|
||||
count = var.multiaz-nat-gateway ? length(distinct(aws_subnet.private-subnets.*.availability_zone)) : 0
|
||||
domain = "vpc"
|
||||
depends_on = [aws_internet_gateway.igw]
|
||||
}
|
||||
|
||||
resource "aws_nat_gateway" "ngw-multiaz" {
|
||||
count = var.multiaz-nat-gateway ? length(aws_eip.ngw-eip-multiaz) : 0
|
||||
allocation_id = aws_eip.ngw-eip-multiaz[count.index].id
|
||||
subnet_id = aws_subnet.public-subnets[count.index].id
|
||||
tags = {
|
||||
Name = "${var.resource-prefix}-ngw-${count.index + 1}"
|
||||
}
|
||||
depends_on = [aws_internet_gateway.igw]
|
||||
}
|
||||
|
||||
resource "aws_route_table" "public-route-table" {
|
||||
count = length(var.public-subnet-cidrs) > 0 ? 1 : 0
|
||||
vpc_id = aws_vpc.vpc.id
|
||||
tags = {
|
||||
Name = "${var.resource-prefix}-public"
|
||||
}
|
||||
}
|
||||
|
||||
module "private-route" {
|
||||
source = "./modules/RouteTables"
|
||||
count = var.create-nat-gateway && !var.multiaz-nat-gateway ? length(aws_subnet.private-subnets) : 0
|
||||
ngw-id = aws_nat_gateway.ngw[0].id
|
||||
resource-prefix = var.resource-prefix
|
||||
subnet-id = aws_subnet.private-subnets[count.index].id
|
||||
vpc-id = aws_vpc.vpc.id
|
||||
}
|
||||
|
||||
module "private-route-multiaz" {
|
||||
source = "./modules/RouteTables"
|
||||
count = var.multiaz-nat-gateway ? length(aws_subnet.private-subnets) : 0
|
||||
ngw-id = aws_nat_gateway.ngw-multiaz[count.index].id
|
||||
resource-prefix = var.resource-prefix
|
||||
subnet-id = aws_subnet.private-subnets[count.index].id
|
||||
vpc-id = aws_vpc.vpc.id
|
||||
}
|
||||
|
||||
|
||||
|
||||
# resource "aws_route_table" "private-route-table" {
|
||||
# count = length(var.private-subnet-cidrs) > 0 ? 1 : 0
|
||||
# vpc_id = aws_vpc.vpc.id
|
||||
# tags = {
|
||||
# Name = "${var.resource-prefix}-privateroutetable"
|
||||
# }
|
||||
# }
|
||||
|
||||
resource "aws_route" "public-routes" {
|
||||
count = length(var.public-subnet-cidrs) > 0 ? 1 : 0
|
||||
|
||||
destination_cidr_block = "0.0.0.0/0"
|
||||
gateway_id = aws_internet_gateway.igw[0].id
|
||||
route_table_id = aws_route_table.public-route-table[0].id
|
||||
}
|
||||
|
||||
# resource "aws_route" "private-routes" {
|
||||
# count = length(var.private-subnet-cidrs) > 0 && var.create-nat-gateway ? 1 : 0
|
||||
#
|
||||
# destination_cidr_block = "0.0.0.0/0"
|
||||
# nat_gateway_id = aws_nat_gateway.ngw[0].id
|
||||
# route_table_id = aws_route_table.private-route-table[0].id
|
||||
# }
|
||||
|
||||
resource "aws_route_table_association" "public_route_association" {
|
||||
count = length(aws_subnet.public-subnets)
|
||||
route_table_id = aws_route_table.public-route-table[0].id
|
||||
subnet_id = aws_subnet.public-subnets[count.index].id
|
||||
}
|
||||
|
||||
# resource "aws_route_table_association" "private_route_association" {
|
||||
# count = length(aws_subnet.private-subnets)
|
||||
# route_table_id = aws_route_table.private-route-table[0].id
|
||||
# subnet_id = aws_subnet.private-subnets[count.index].id
|
||||
# }
|
||||
|
||||
/*
|
||||
harden default security group. the default sg created by aws allows all egress.
|
||||
this resource limits ingress and egress from and to itself
|
||||
and allow icmp only
|
||||
*/
|
||||
|
||||
resource "aws_default_security_group" "default-sg" {
|
||||
vpc_id = aws_vpc.vpc.id
|
||||
ingress {
|
||||
protocol = "icmp"
|
||||
self = true
|
||||
from_port = -1
|
||||
to_port = -1
|
||||
description = "Allow traffic coming from this SG"
|
||||
}
|
||||
egress {
|
||||
from_port = -1
|
||||
protocol = "icmp"
|
||||
to_port = -1
|
||||
self = true
|
||||
description = "Allow traffic going to this SG"
|
||||
}
|
||||
tags = {
|
||||
Name = "${var.resource-prefix}-defaultsg"
|
||||
}
|
||||
}
|
||||
|
||||
# Enable gateway endpoints which are free
|
||||
module "vpc-ep" {
|
||||
count = var.create-free-vpc-endpoints ? 1 : 0
|
||||
source = "../vpc-endpoints"
|
||||
|
||||
gateway-ep-services = ["s3", "dynamodb"]
|
||||
interface-ep-services = []
|
||||
resource-prefix = var.resource-prefix
|
||||
vpc-id = aws_vpc.vpc.id
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<!-- This readme file is generated with terraform-docs -->
|
||||
## Requirements
|
||||
|
||||
No requirements.
|
||||
|
||||
## Providers
|
||||
|
||||
| Name | Version |
|
||||
|------|---------|
|
||||
| aws | n/a |
|
||||
|
||||
## Modules
|
||||
|
||||
No modules.
|
||||
|
||||
## Resources
|
||||
|
||||
| Name | Type |
|
||||
|------|------|
|
||||
| [aws_route.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route) | resource |
|
||||
| [aws_route_table.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table) | resource |
|
||||
| [aws_route_table_association.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table_association) | resource |
|
||||
|
||||
## Inputs
|
||||
|
||||
| Name | Description | Type | Default | Required |
|
||||
|------|-------------|------|---------|:--------:|
|
||||
| ngw-id | NAT Gateway ID | `string` | n/a | yes |
|
||||
| resource-prefix | Resource prefix | `string` | n/a | yes |
|
||||
| subnet-id | Subnet ID | `string` | n/a | yes |
|
||||
| vpc-id | VPC ID | `string` | n/a | yes |
|
||||
|
||||
## Outputs
|
||||
|
||||
No outputs.
|
||||
|
||||
---
|
||||
## Authorship
|
||||
This module was developed by xpk.
|
||||
@@ -0,0 +1,17 @@
|
||||
resource "aws_route_table" "this" {
|
||||
vpc_id = var.vpc-id
|
||||
tags = {
|
||||
Name = "${var.resource-prefix}-private"
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_route" "this" {
|
||||
destination_cidr_block = "0.0.0.0/0"
|
||||
nat_gateway_id = var.ngw-id
|
||||
route_table_id = aws_route_table.this.id
|
||||
}
|
||||
|
||||
resource "aws_route_table_association" "this" {
|
||||
route_table_id = aws_route_table.this.id
|
||||
subnet_id = var.subnet-id
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
variable vpc-id {
|
||||
type = string
|
||||
description = "VPC ID"
|
||||
}
|
||||
|
||||
variable ngw-id {
|
||||
type = string
|
||||
description = "NAT Gateway ID"
|
||||
}
|
||||
|
||||
variable subnet-id {
|
||||
type = string
|
||||
description = "Subnet ID"
|
||||
}
|
||||
|
||||
variable resource-prefix {
|
||||
type = string
|
||||
description = "Resource prefix"
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
output "vpc_id" {
|
||||
description = "VPC id"
|
||||
value = aws_vpc.vpc.id
|
||||
}
|
||||
|
||||
output "vpc-cidr" {
|
||||
description = "VPC primary cidr"
|
||||
value = aws_vpc.vpc.cidr_block
|
||||
}
|
||||
|
||||
output "public_subnets" {
|
||||
description = "Public subnet cidrs"
|
||||
value = aws_subnet.public-subnets.*.cidr_block
|
||||
}
|
||||
|
||||
output "private_subnets" {
|
||||
description = "Private subnet cidrs"
|
||||
value = aws_subnet.private-subnets.*.cidr_block
|
||||
}
|
||||
|
||||
output "public-subnet-ids" {
|
||||
description = "List of public subnet id"
|
||||
value = aws_subnet.public-subnets.*.id
|
||||
}
|
||||
|
||||
output "private-subnet-ids" {
|
||||
description = "List of private subnet id"
|
||||
value = aws_subnet.private-subnets.*.id
|
||||
}
|
||||
|
||||
# output "private-route-table-id" {
|
||||
# value = aws_route_table.private-route-table.*.id
|
||||
# }
|
||||
|
||||
output "public-route-table-id" {
|
||||
description = "Public route table id"
|
||||
value = aws_route_table.public-route-table.*.id
|
||||
}
|
||||
|
||||
# output "route_tables_for_gateway_endpoints" {
|
||||
# value = concat(aws_route_table.public-route-table.*.id, aws_route_table.private-route-table.*.id)
|
||||
# }
|
||||
|
||||
output "secondary_cidr_blocks" {
|
||||
description = "Secondary CIDR block"
|
||||
value = var.secondary_cidr_blocks
|
||||
}
|
||||
|
||||
output "public-subnet-details" {
|
||||
description = "Details of public subnets"
|
||||
value = [
|
||||
for k, v in aws_subnet.public-subnets : {
|
||||
cidr = v.cidr_block,
|
||||
az = v.availability_zone,
|
||||
name = v.tags["Name"]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
output "private-subnet-details" {
|
||||
description = "Details of private subnets"
|
||||
value = [
|
||||
for k, v in aws_subnet.public-subnets : {
|
||||
cidr = v.cidr_block,
|
||||
az = v.availability_zone,
|
||||
name = v.tags["Name"]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
variable "resource-prefix" {
|
||||
type = string
|
||||
description = "Prefix of resource"
|
||||
}
|
||||
|
||||
# VPC variables
|
||||
variable "vpc-cidr" {
|
||||
type = string
|
||||
description = "VPC primary CIDR"
|
||||
}
|
||||
|
||||
variable "private-subnet-cidrs" {
|
||||
type = list(string)
|
||||
description = "Private subnet CIDRs"
|
||||
default = []
|
||||
}
|
||||
|
||||
variable "public-subnet-cidrs" {
|
||||
type = list(string)
|
||||
description = "Public subnet CIDRs"
|
||||
default = []
|
||||
}
|
||||
|
||||
variable "create-nat-gateway" {
|
||||
description = "Deploy NAT gateway for private subnets"
|
||||
type = bool
|
||||
default = false
|
||||
}
|
||||
|
||||
variable "multiaz-nat-gateway" {
|
||||
type = bool
|
||||
description = "Whether to deploy 1 NAT gateway for each AZ"
|
||||
default = false
|
||||
}
|
||||
|
||||
variable "flow-log-destination" {
|
||||
type = string
|
||||
description = "Destination of flowlog. Valid destinations are s3 or cwlog"
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "flow-log-bucket-arn" {
|
||||
type = string
|
||||
default = null
|
||||
description = "Arn of S3 bucket to be used for flow logging"
|
||||
}
|
||||
|
||||
variable "enable-flow-log" {
|
||||
description = "Whether to enable VPC flowlog"
|
||||
type = bool
|
||||
default = true
|
||||
}
|
||||
|
||||
variable "vpcflowlog-retain-days" {
|
||||
type = number
|
||||
default = 90
|
||||
description = "Log retention period for CWlogs"
|
||||
}
|
||||
|
||||
variable "vpcflowlog-cwl-loggroup-key-arn" {
|
||||
type = string
|
||||
description = "KMS key arn for cwlog encryption"
|
||||
}
|
||||
|
||||
variable "create-free-vpc-endpoints" {
|
||||
description = "Whether to deploy free VPC endpoints (s3 and dynamodb)"
|
||||
type = bool
|
||||
default = true
|
||||
}
|
||||
|
||||
variable "secondary_cidr_blocks" {
|
||||
type = list(string)
|
||||
description = "Additional cidr blocks"
|
||||
default = []
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
terraform {
|
||||
required_version = ">= 1.3.0"
|
||||
required_providers {
|
||||
aws = {
|
||||
source = "hashicorp/aws"
|
||||
version = ">= 5.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
resource "aws_flow_log" "vpc-flowlog" {
|
||||
count = var.enable-flow-log && var.flow-log-destination == "cwlog" ? 1 : 0
|
||||
iam_role_arn = aws_iam_role.vpcflowlog-role[0].arn
|
||||
log_destination = aws_cloudwatch_log_group.vpcflowlog-loggroup[0].arn
|
||||
traffic_type = "ALL"
|
||||
vpc_id = aws_vpc.vpc.id
|
||||
tags = {
|
||||
Name = "${var.resource-prefix}-vpcflowlog"
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_flow_log" "vpc-flowlog-s3" {
|
||||
count = var.enable-flow-log && var.flow-log-destination == "s3" ? 1 : 0
|
||||
log_destination_type = "s3"
|
||||
log_destination = var.flow-log-bucket-arn
|
||||
traffic_type = "ALL"
|
||||
vpc_id = aws_vpc.vpc.id
|
||||
tags = {
|
||||
Name = "${var.resource-prefix}-vpcflowlog"
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_cloudwatch_log_group" "vpcflowlog-loggroup" {
|
||||
count = var.enable-flow-log && var.flow-log-destination == "cwlog" ? 1 : 0
|
||||
name_prefix = "vpcflowlog/${aws_vpc.vpc.id}/"
|
||||
kms_key_id = var.vpcflowlog-cwl-loggroup-key-arn
|
||||
retention_in_days = var.vpcflowlog-retain-days
|
||||
}
|
||||
|
||||
resource "random_id" "rid" {
|
||||
byte_length = 2
|
||||
}
|
||||
|
||||
resource "aws_iam_role" "vpcflowlog-role" {
|
||||
count = var.enable-flow-log && var.flow-log-destination == "cwlog" ? 1 : 0
|
||||
name = "VpcFlowlogRole-${random_id.rid.dec}"
|
||||
path = "/service/"
|
||||
assume_role_policy = jsonencode(
|
||||
{
|
||||
"Version" : "2012-10-17",
|
||||
"Statement" : [
|
||||
{
|
||||
"Sid" : "",
|
||||
"Effect" : "Allow",
|
||||
"Principal" : {
|
||||
"Service" : "vpc-flow-logs.amazonaws.com"
|
||||
},
|
||||
"Action" : "sts:AssumeRole"
|
||||
}
|
||||
]
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
resource "aws_iam_role_policy" "vpcflowlog-role-policy" {
|
||||
count = var.enable-flow-log && var.flow-log-destination == "cwlog" ? 1 : 0
|
||||
name = "VpcFlowlogRole-${random_id.rid.dec}"
|
||||
role = aws_iam_role.vpcflowlog-role[0].id
|
||||
|
||||
policy = jsonencode(
|
||||
{
|
||||
"Version" : "2012-10-17",
|
||||
"Statement" : [
|
||||
{
|
||||
"Action" : [
|
||||
"logs:CreateLogGroup",
|
||||
"logs:CreateLogStream",
|
||||
"logs:PutLogEvents",
|
||||
"logs:DescribeLogGroups",
|
||||
"logs:DescribeLogStreams",
|
||||
"kms:Encrypt",
|
||||
"kms:ReEncrypt",
|
||||
"kms:Decrypt"
|
||||
],
|
||||
"Effect" : "Allow",
|
||||
"Resource" : "*"
|
||||
}
|
||||
]
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
# delete-default-vpc module
|
||||
This terraform module calls awscli to delete default vpc in specified region.
|
||||
|
||||
## Example of root module
|
||||
```terraform
|
||||
data "aws_regions" "current" {}
|
||||
|
||||
module delete-default-vpc {
|
||||
source = "git::https://xpk.headdesk.me/git/xpk/terraform.aws-baseline-infra//modules/networking/delete-default-vpcs"
|
||||
for_each = data.aws_regions.current.names
|
||||
region-name = each.value
|
||||
}
|
||||
```
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
#!/bin/bash
|
||||
|
||||
region=$1
|
||||
vpc=$(aws ec2 --region ${region} describe-vpcs --filter Name=isDefault,Values=true | jq -r .Vpcs[0].VpcId)
|
||||
if [ "${vpc}" = "null" ]; then
|
||||
echo "No default vpc found"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
aws ec2 --region ${region} describe-internet-gateways --filter Name=attachment.vpc-id,Values=${vpc} | jq -r '.InternetGateways[0].InternetGatewayId' | while read igw; do
|
||||
echo "Removing internet gateway ${igw}"
|
||||
aws ec2 --region ${region} detach-internet-gateway --internet-gateway-id ${igw} --vpc-id ${vpc}
|
||||
aws ec2 --region ${region} delete-internet-gateway --internet-gateway-id ${igw}
|
||||
done
|
||||
|
||||
aws ec2 --region ${region} describe-subnets --filters Name=vpc-id,Values=${vpc} | jq -r '.Subnets[].SubnetId' | while read subnet; do
|
||||
echo "Removing subnet ${subnet}"
|
||||
aws ec2 --region ${region} delete-subnet --subnet-id ${subnet}
|
||||
done
|
||||
|
||||
echo "Removing vpc ${vpc}"
|
||||
aws ec2 --region ${region} delete-vpc --vpc-id ${vpc}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
data aws_regions all-aws-regions {}
|
||||
|
||||
resource "null_resource" "shell" {
|
||||
for_each = data.aws_regions.all-aws-regions.names
|
||||
provisioner "local-exec" {
|
||||
command = "/bin/bash -c '${path.module}/exec.sh ${each.value}'"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
# nacl module
|
||||
This module takes in list(list(string)) and construct NACL using dynamic block.
|
||||
|
||||
Example code in root module
|
||||
```hcl
|
||||
module "nacl" {
|
||||
source = "../../modules/networking/nacl"
|
||||
|
||||
egress_rules = [
|
||||
["210", "-1", "0", "0", "10.29.0.0/16", "allow"],
|
||||
["220", "tcp", "443", "443", "10.35.32.0/22", "allow"],
|
||||
["230", "udp", "53", "53", "10.35.67.0/24", "allow"]
|
||||
]
|
||||
ingress_rules = [
|
||||
["310", "-1", "0", "0", "10.29.0.0/16", "allow"],
|
||||
["320", "tcp", "80", "81", "10.35.32.0/22", "allow"],
|
||||
["330", "udp", "53", "53", "10.35.67.0/24", "allow"]
|
||||
]
|
||||
subnet_ids = ["subnet-0927ba1b06ccfe6c5", "subnet-0551e96ffd016192a"]
|
||||
vpc_id = "vpc-01a10b033169f89a8"
|
||||
acl_name = "test-nacl"
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,32 @@
|
||||
|
||||
resource "aws_network_acl" "this" {
|
||||
vpc_id = var.vpc_id
|
||||
subnet_ids = var.subnet_ids
|
||||
tags = {
|
||||
Name = var.acl_name
|
||||
}
|
||||
dynamic "ingress" {
|
||||
for_each = var.ingress_rules
|
||||
content {
|
||||
rule_no = ingress.value[0]
|
||||
protocol = ingress.value[1]
|
||||
from_port = ingress.value[2]
|
||||
to_port = ingress.value[3]
|
||||
cidr_block = ingress.value[4]
|
||||
action = ingress.value[5]
|
||||
}
|
||||
}
|
||||
|
||||
dynamic "egress" {
|
||||
for_each = var.egress_rules
|
||||
content {
|
||||
rule_no = egress.value[0]
|
||||
protocol = egress.value[1]
|
||||
from_port = egress.value[2]
|
||||
to_port = egress.value[3]
|
||||
cidr_block = egress.value[4]
|
||||
action = egress.value[5]
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
terraform {
|
||||
required_version = "~> 1.3.0"
|
||||
required_providers {
|
||||
aws = {
|
||||
source = "hashicorp/aws"
|
||||
version = ">= 4.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
variable vpc_id {
|
||||
type = string
|
||||
}
|
||||
|
||||
variable subnet_ids {
|
||||
type = list(string)
|
||||
}
|
||||
|
||||
variable ingress_rules {
|
||||
type = list(list(string))
|
||||
}
|
||||
|
||||
variable egress_rules {
|
||||
type = list(list(string))
|
||||
}
|
||||
|
||||
variable acl_name {
|
||||
type = string
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
# r53-record-geo sub module
|
||||
Create route53 geolocation records
|
||||
|
||||
## Example
|
||||
```hcl
|
||||
module "r53-www" {
|
||||
source = "../../modules/networking/r53-record-geo"
|
||||
|
||||
record_name = "www"
|
||||
record_type = "A"
|
||||
record_values = ["192.168.33.10"]
|
||||
set_identifier = "Global web servers"
|
||||
record_type_locational = "A"
|
||||
record_values_locational = ["172.17.16.10"]
|
||||
set_identifier_locational = "China web servers"
|
||||
country_code = "CN"
|
||||
zone_id = aws_route53_zone.zone.zone_id
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,60 @@
|
||||
resource "aws_route53_record" "default" {
|
||||
zone_id = var.zone_id
|
||||
name = var.record_name
|
||||
type = var.record_type
|
||||
ttl = length(var.alias) > 0 ? null : var.record_ttl
|
||||
records = var.record_values
|
||||
set_identifier = var.set_identifier
|
||||
geolocation_routing_policy {
|
||||
country = "*"
|
||||
}
|
||||
dynamic "alias" {
|
||||
for_each = var.alias
|
||||
content {
|
||||
name = alias.value["name"]
|
||||
zone_id = alias.value["zone_id"]
|
||||
evaluate_target_health = alias.value["evaluate_target_health"]
|
||||
}
|
||||
}
|
||||
dynamic "weighted_routing_policy" {
|
||||
for_each = var.weighted_routing_policy
|
||||
content {
|
||||
weight = weighted_routing_policy.value["weight"]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_route53_record" "locational" {
|
||||
zone_id = var.zone_id
|
||||
name = var.record_name
|
||||
type = var.record_type_locational
|
||||
ttl = length(var.alias_locational) > 0 ? null : var.record_ttl_locational
|
||||
records = var.record_values_locational
|
||||
set_identifier = var.set_identifier_locational
|
||||
dynamic "alias" {
|
||||
for_each = var.alias_locational
|
||||
content {
|
||||
name = alias.value["name"]
|
||||
zone_id = alias.value["zone_id"]
|
||||
evaluate_target_health = alias.value["evaluate_target_health"]
|
||||
}
|
||||
}
|
||||
geolocation_routing_policy {
|
||||
country = var.country_code
|
||||
continent = var.continent_code
|
||||
}
|
||||
dynamic "alias" {
|
||||
for_each = var.alias_locational
|
||||
content {
|
||||
name = alias.value["name"]
|
||||
zone_id = alias.value["zone_id"]
|
||||
evaluate_target_health = alias.value["evaluate_target_health"]
|
||||
}
|
||||
}
|
||||
dynamic "weighted_routing_policy" {
|
||||
for_each = var.weighted_routing_policy_locational
|
||||
content {
|
||||
weight = weighted_routing_policy.value["weight"]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
variable "zone_id" {}
|
||||
variable "record_name" {}
|
||||
variable "record_type" {}
|
||||
variable "record_ttl" {
|
||||
type = number
|
||||
default = 900
|
||||
}
|
||||
variable "record_values" {
|
||||
type = list(string)
|
||||
}
|
||||
variable "set_identifier" {}
|
||||
variable "alias" {
|
||||
type = list(
|
||||
object({
|
||||
zone_id = string
|
||||
name = string
|
||||
evaluate_target_health = bool
|
||||
})
|
||||
)
|
||||
}
|
||||
variable "weighted_routing_policy" {
|
||||
type = list(
|
||||
object({
|
||||
weight = number
|
||||
})
|
||||
)
|
||||
default = []
|
||||
}
|
||||
variable "record_type_locational" {}
|
||||
variable "record_ttl_locational" {
|
||||
type = number
|
||||
default = 900
|
||||
}
|
||||
variable "record_values_locational" {
|
||||
type = list(string)
|
||||
}
|
||||
variable "set_identifier_locational" {}
|
||||
variable "country_code" {
|
||||
type = string
|
||||
default = null
|
||||
}
|
||||
variable "continent_code" {
|
||||
type = string
|
||||
default = null
|
||||
}
|
||||
variable "alias_locational" {
|
||||
type = list(
|
||||
object({
|
||||
zone_id = string
|
||||
name = string
|
||||
evaluate_target_health = bool
|
||||
})
|
||||
)
|
||||
}
|
||||
variable "weighted_routing_policy_locational" {
|
||||
type = list(
|
||||
object({
|
||||
weight = number
|
||||
})
|
||||
)
|
||||
default = []
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
# r53-record sub module
|
||||
Create route53 record
|
||||
|
||||
## Example
|
||||
```hcl
|
||||
module "r53-ftp" {
|
||||
source = "../../modules/networking/r53-record"
|
||||
|
||||
record_name = "ftp"
|
||||
record_type = "A"
|
||||
record_values = ["192.168.0.100"]
|
||||
zone_id = aws_route53_zone.zone.zone_id
|
||||
}
|
||||
|
||||
module "r53-www" {
|
||||
source = "../../modules/networking/r53-record"
|
||||
|
||||
record_name = "www"
|
||||
record_type = "A"
|
||||
record_values = null
|
||||
alias = [
|
||||
{
|
||||
zone_id = "Z2LIHJ7PKBEMWN"
|
||||
name = "vpce-07b8a9af30673995f-2n2ird8h.ssm.ap-east-1.vpce.amazonaws.com"
|
||||
evaluate_target_health = true
|
||||
}
|
||||
]
|
||||
zone_id = aws_route53_zone.zone.zone_id
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,22 @@
|
||||
resource "aws_route53_record" "this" {
|
||||
zone_id = var.zone_id
|
||||
name = var.record_name
|
||||
type = var.record_type
|
||||
ttl = length(var.alias) > 0 ? null : var.record_ttl
|
||||
records = var.record_values
|
||||
set_identifier = var.set_identifier
|
||||
dynamic "alias" {
|
||||
for_each = var.alias
|
||||
content {
|
||||
name = alias.value["name"]
|
||||
zone_id = alias.value["zone_id"]
|
||||
evaluate_target_health = alias.value["evaluate_target_health"]
|
||||
}
|
||||
}
|
||||
dynamic "weighted_routing_policy" {
|
||||
for_each = var.weighted_routing_policy
|
||||
content {
|
||||
weight = weighted_routing_policy.value["weight"]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
variable "zone_id" {}
|
||||
variable "record_name" {}
|
||||
variable "record_type" {}
|
||||
variable "record_ttl" {
|
||||
type = number
|
||||
default = 900
|
||||
}
|
||||
variable "record_values" {
|
||||
type = list(string)
|
||||
}
|
||||
variable "set_identifier" {
|
||||
type = string
|
||||
default = ""
|
||||
}
|
||||
variable "alias" {
|
||||
type = list(
|
||||
object({
|
||||
zone_id = string
|
||||
name = string
|
||||
evaluate_target_health = bool
|
||||
})
|
||||
)
|
||||
default = []
|
||||
}
|
||||
variable "weighted_routing_policy" {
|
||||
type = list(
|
||||
object({
|
||||
weight = number
|
||||
})
|
||||
)
|
||||
default = []
|
||||
}
|
||||
@@ -0,0 +1,275 @@
|
||||
# vpc-endpoints module
|
||||
This module deploys VPC endpoints.
|
||||
|
||||
Automatically, this module performs the following additional tasks
|
||||
- Create and attach security group which allows access from the same VPC
|
||||
- Associate endpoints with 1 subnet in each availability zone
|
||||
|
||||
# Inputs
|
||||
| Variable | Type | Required | Description |
|
||||
|-----------------------|--------------|----------|-------------------------------------------------|
|
||||
| voc-id | string | yes | ID of VPC to deploy endpoints to |
|
||||
| interface-ep-services | list(string) | yes | Interface endpoint names |
|
||||
| gateway-ep-services | list(string) | no | Gateway endpoint names |
|
||||
| resource-prefix | string | yes | Prefix that will be added to resource name tags |
|
||||
|
||||
|
||||
# Types of endpoints
|
||||
## Gateway endpoints
|
||||
At time of writing, AWS provides 2 gateway endpoints at no charge.
|
||||
* s3
|
||||
* dynamodb
|
||||
|
||||
For gateway endpoints, all route tables in the VPC will be updated with routes to the private links.
|
||||
|
||||
Full documentation: https://docs.aws.amazon.com/vpc/latest/privatelink/gateway-endpoints.html
|
||||
|
||||
## Interface endpoints
|
||||
Interface endpoints are placed in one subnet for every AZ. Security group is created automatically
|
||||
and allow access from the VPC's cidr, plus all additional CIDRs if applicable.
|
||||
|
||||
At time of writing, AWS provides 200+ interface endpoints:
|
||||
* access-analyzer
|
||||
* account
|
||||
* execute-api
|
||||
* appmesh
|
||||
* appmesh-envoy-management
|
||||
* apprunner
|
||||
* apprunner.requests
|
||||
* application-autoscaling
|
||||
* mgn
|
||||
* appstream.api
|
||||
* appstream.streaming
|
||||
* appsync-api
|
||||
* athena
|
||||
* auditmanager
|
||||
* rds
|
||||
* autoscaling-plans
|
||||
* backup
|
||||
* backup-gateway
|
||||
* batch
|
||||
* billingconductor
|
||||
* braket
|
||||
* cleanrooms
|
||||
* cloudcontrolapi
|
||||
* cloudcontrolapi-fips
|
||||
* clouddirectory
|
||||
* cloudformation
|
||||
* cloudhsmv2
|
||||
* cloudtrail
|
||||
* evidently
|
||||
* evidently-dataplane
|
||||
* monitoring
|
||||
* rum
|
||||
* rum-dataplane
|
||||
* synthetics
|
||||
* events
|
||||
* logs
|
||||
* codeartifact.api
|
||||
* codeartifact.repositories
|
||||
* codebuild
|
||||
* codebuild-fips
|
||||
* codecommit
|
||||
* codecommit-fips
|
||||
* git-codecommit
|
||||
* git-codecommit-fips
|
||||
* codedeploy
|
||||
* codedeploy-commands-secure
|
||||
* codeguru-profiler
|
||||
* codeguru-reviewer
|
||||
* codepipeline
|
||||
* codestar-connections.api
|
||||
* comprehend
|
||||
* comprehendmedical
|
||||
* config
|
||||
* app-integrations
|
||||
* cases
|
||||
* connect-campaigns
|
||||
* profile
|
||||
* voiceid
|
||||
* wisdom
|
||||
* dataexchange
|
||||
* dms
|
||||
* dms-fips
|
||||
* datasync
|
||||
* devops-guru
|
||||
* ds
|
||||
* ebs
|
||||
* ec2
|
||||
* autoscaling
|
||||
* imagebuilder
|
||||
* ecr.api
|
||||
* ecr.dkr
|
||||
* ecs
|
||||
* ecs-agent
|
||||
* ecs-telemetry
|
||||
* eks
|
||||
* elasticbeanstalk
|
||||
* elasticbeanstalk-health
|
||||
* drs
|
||||
* elasticfilesystem
|
||||
* elasticfilesystem-fips
|
||||
* elastic-inference.runtime
|
||||
* elasticloadbalancing
|
||||
* elasticache
|
||||
* elasticache-fips
|
||||
* elasticmapreduce
|
||||
* emr-containers
|
||||
* emr-serverless
|
||||
* events
|
||||
* fis
|
||||
* finspace
|
||||
* finspace-api
|
||||
* forecast
|
||||
* forecastquery
|
||||
* forecast-fips
|
||||
* forecastquery-fips
|
||||
* frauddetector
|
||||
* fsx
|
||||
* fsx-fips
|
||||
* glue
|
||||
* databrew
|
||||
* grafana
|
||||
* grafana-workspace
|
||||
* groundstation
|
||||
* guardduty-data
|
||||
* guardduty-data-fips
|
||||
* healthlake
|
||||
* identitystore
|
||||
* rolesanywhere
|
||||
* inspector2
|
||||
* iot.data
|
||||
* iot.fleethub.api
|
||||
* deviceadvisor.iot
|
||||
* iotwireless.api
|
||||
* lorawan.cups
|
||||
* lorawan.lns
|
||||
* iotfleetwise
|
||||
* greengrass
|
||||
* iotroborunner
|
||||
* iotsitewise.api
|
||||
* iotsitewise.data
|
||||
* iottwinmaker.api
|
||||
* iottwinmaker.data
|
||||
* kendra
|
||||
* kendra-ranking
|
||||
* kms
|
||||
* kms-fips
|
||||
* cassandra
|
||||
* cassandra-fips
|
||||
* kinesis-firehose
|
||||
* kinesis-streams
|
||||
* lakeformation
|
||||
* lambda
|
||||
* models-v2-lex
|
||||
* runtime-v2-lex
|
||||
* license-manager
|
||||
* license-manager-fips
|
||||
* lookoutequipment
|
||||
* lookoutmetrics
|
||||
* lookoutvision
|
||||
* macie2
|
||||
* m2
|
||||
* aps
|
||||
* aps-workspaces
|
||||
* airflow.api
|
||||
* airflow.env
|
||||
* airflow.ops
|
||||
* console
|
||||
* signin
|
||||
* memory-db
|
||||
* memorydb-fips
|
||||
* migrationhub-orchestrator
|
||||
* refactor-spaces
|
||||
* migrationhub-strategy
|
||||
* nimble
|
||||
* analytics-omics
|
||||
* control-storage-omics
|
||||
* storage-omics
|
||||
* tags-omics
|
||||
* workflows-omics
|
||||
* service-managed
|
||||
* panorama
|
||||
* payment-cryptography.controlplane
|
||||
* payment-cryptography.dataplane
|
||||
* personalize
|
||||
* personalize-events
|
||||
* personalize-runtime
|
||||
* pinpoint
|
||||
* pinpoint-sms-voice-v2
|
||||
* polly
|
||||
* private-networks
|
||||
* acm-pca
|
||||
* proton
|
||||
* qldb.session
|
||||
* rds
|
||||
* rds-data
|
||||
* redshift
|
||||
* redshift-fips
|
||||
* redshift-data
|
||||
* rekognition
|
||||
* rekognition-fips
|
||||
* streaming-rekognition
|
||||
* streaming-rekognition-fips
|
||||
* robomaker
|
||||
* s3
|
||||
* com.amazonaws.s3-global.accesspoint
|
||||
* s3-outposts
|
||||
* aws.sagemaker.region.notebook
|
||||
* aws.sagemaker.region.studio
|
||||
* sagemaker.api
|
||||
* sagemaker.featurestore-runtime
|
||||
* sagemaker.metrics
|
||||
* sagemaker.runtime
|
||||
* sagemaker.runtime-fips
|
||||
* secretsmanager
|
||||
* securityhub
|
||||
* sts
|
||||
* servicecatalog
|
||||
* servicecatalog-appregistry
|
||||
* email-smtp
|
||||
* simspaceweaver
|
||||
* snow-device-management
|
||||
* sns
|
||||
* sqs
|
||||
* swf
|
||||
* swf-fips
|
||||
* states
|
||||
* sync-states
|
||||
* storagegateway
|
||||
* ec2messages
|
||||
* ssm
|
||||
* ssm-contacts
|
||||
* ssm-incidents
|
||||
* ssmmessages
|
||||
* tnb
|
||||
* textract
|
||||
* textract-fips
|
||||
* transcribe
|
||||
* transcribestreaming
|
||||
* transcribe
|
||||
* transcribestreaming
|
||||
* transfer
|
||||
* transfer.server
|
||||
* translate
|
||||
* verifiedpermissions
|
||||
* vpc-lattice
|
||||
* workspaces
|
||||
* xray
|
||||
|
||||
|
||||
Full documentation: https://docs.aws.amazon.com/vpc/latest/privatelink/aws-services-privatelink-support.html
|
||||
|
||||
|
||||
## Example
|
||||
```hcl
|
||||
module "vpc-ep" {
|
||||
count = var.create-free-vpc-endpoints ? 1 : 0
|
||||
source = "../vpc-endpoints"
|
||||
|
||||
gateway-ep-services = ["s3", "dynamodb"]
|
||||
interface-ep-services = []
|
||||
resource-prefix = var.resource-prefix
|
||||
vpc-id = aws_vpc.vpc.id
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,102 @@
|
||||
data "aws_region" "this" {}
|
||||
data "aws_default_tags" "this" {
|
||||
lifecycle {
|
||||
postcondition {
|
||||
condition = length(self.tags) >= 1
|
||||
error_message = "Validation failed: Provider default_tags not set."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_vpc_endpoint" "vpc-interface-ep" {
|
||||
for_each = toset(var.interface-ep-services)
|
||||
vpc_id = data.aws_vpc.this-vpc.id
|
||||
service_name = "com.amazonaws.${data.aws_region.this.id}.${each.value}"
|
||||
vpc_endpoint_type = "Interface"
|
||||
|
||||
security_group_ids = [
|
||||
aws_security_group.vpc-ep-sg.id,
|
||||
]
|
||||
|
||||
# deploy to all subnets
|
||||
subnet_ids = local.one_subnet_in_each_az
|
||||
|
||||
private_dns_enabled = true
|
||||
tags = { "Name" : "${var.resource-prefix}-vpcep-${each.value}" }
|
||||
|
||||
lifecycle {
|
||||
precondition {
|
||||
condition = data.aws_vpc.this-vpc.enable_dns_support
|
||||
error_message = "enableDnsSupport needs to be turned on."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_vpc_endpoint" "vpc-gateway-ep" {
|
||||
for_each = toset(var.gateway-ep-services)
|
||||
vpc_id = data.aws_vpc.this-vpc.id
|
||||
service_name = "com.amazonaws.${data.aws_region.this.id}.${each.value}"
|
||||
vpc_endpoint_type = "Gateway"
|
||||
route_table_ids = data.aws_route_tables.this.ids
|
||||
tags = { "Name" : "${var.resource-prefix}-vpcep-${each.value}" }
|
||||
}
|
||||
|
||||
resource "random_id" "rid" {
|
||||
byte_length = 2
|
||||
}
|
||||
|
||||
resource "aws_security_group" "vpc-ep-sg" {
|
||||
name = "HttpsAccessToVpcEndpoints-${random_id.rid.dec}"
|
||||
description = "HttpsAccessToVpcEndpoints-${random_id.rid.dec}"
|
||||
vpc_id = data.aws_vpc.this-vpc.id
|
||||
|
||||
ingress {
|
||||
description = "TLS from VPC"
|
||||
from_port = 443
|
||||
to_port = 443
|
||||
protocol = "tcp"
|
||||
# cidr_blocks = [data.aws_vpc.this-vpc.cidr_block]
|
||||
cidr_blocks = data.aws_vpc.this-vpc.cidr_block_associations.*.cidr_block
|
||||
}
|
||||
|
||||
egress {
|
||||
from_port = 0
|
||||
to_port = 0
|
||||
protocol = "-1"
|
||||
cidr_blocks = ["0.0.0.0/0"]
|
||||
}
|
||||
|
||||
tags = { "Name" : "VpcEpAccess" }
|
||||
}
|
||||
|
||||
data "aws_vpc" "this-vpc" {
|
||||
id = var.vpc-id
|
||||
}
|
||||
|
||||
data "aws_availability_zones" "this" {
|
||||
state = "available"
|
||||
}
|
||||
|
||||
# find all subnets for this vpc in all availability zones
|
||||
data "aws_subnets" "subnets_and_az" {
|
||||
for_each = toset(data.aws_availability_zones.this.zone_ids)
|
||||
|
||||
filter {
|
||||
name = "vpc-id"
|
||||
values = [var.vpc-id]
|
||||
}
|
||||
|
||||
filter {
|
||||
name = "availability-zone-id"
|
||||
values = [each.value]
|
||||
}
|
||||
}
|
||||
|
||||
data "aws_route_tables" "this" {
|
||||
vpc_id = var.vpc-id
|
||||
}
|
||||
|
||||
locals {
|
||||
# pick first subnet in each AZ
|
||||
one_subnet_in_each_az = compact([for k, v in data.aws_subnets.subnets_and_az : try(element(v.ids, length(v.ids) - 1), "")])
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
# requires 1.3.0 for postcondition validation
|
||||
# https://learn.hashicorp.com/tutorials/terraform/custom-conditions
|
||||
terraform {
|
||||
required_version = ">= 1.3.0"
|
||||
required_providers {
|
||||
aws = {
|
||||
source = "hashicorp/aws"
|
||||
version = ">= 3.75.2"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
variable vpc-id {}
|
||||
variable interface-ep-services {
|
||||
type = list(string)
|
||||
description = "List of interface endpoint. E.g. dkr,lambda,kms,elasticloadbalancing,execute-api,ec2,ssm,secretsmanager,monitoring,guardduty-data"
|
||||
}
|
||||
variable gateway-ep-services {
|
||||
type = list(string)
|
||||
default = []
|
||||
description = "s3 and dynamodb gateway endpoints are free."
|
||||
}
|
||||
variable resource-prefix {}
|
||||
/*
|
||||
variable secondary_cidrs {
|
||||
type = list(string)
|
||||
description = "Additional cidr blocks"
|
||||
default = []
|
||||
}
|
||||
*/
|
||||
@@ -0,0 +1,52 @@
|
||||
# Overview
|
||||
This module performs the following tasks:
|
||||
|
||||
- Create VPC, vpcflow log
|
||||
- Create subnets in every AZ
|
||||
- Create IGW, NGW
|
||||
- Create s3 and ddb endpoints which are free
|
||||
|
||||
## Subnet addressing
|
||||
|
||||
Subnet cidrs needs to be specified manually
|
||||
|
||||
## Inputs:
|
||||
|
||||
| Name | Description | Type | Default | Required |
|
||||
|---------------------------------|---------------------------------------------------|---------------|---------|----------|
|
||||
| private-subnet-cidrs | private subnets | list | [] | yes |
|
||||
| public-subnet-cidrs | public subnets | list | [] | yes |
|
||||
| create-nat-gateway | whether to deploy NAT gateway for private subnets | bool | true | yes |
|
||||
| vpc-cidr | VPC cidr | string | none | yes |
|
||||
| enable-flowlog | whether to enable vpc flowlog | bool | true | yes |
|
||||
| vpcflowlog-retain-days | number of days to retain vpc cloudwatch log | number | 90 | yes |
|
||||
| vpcflowlog-cwl-loggroup-key-arn | kms key alias arn for log group encryption | string | none | yes |
|
||||
| secondary_cidr_blocks | Additional CIDR blocks to be associated with VPC | list(string) | none | no |
|
||||
| resource-prefix | Prefix of resource name | string | "" | yes |
|
||||
|
||||
|
||||
## Outputs:
|
||||
|
||||
| Name | Description | Type |
|
||||
|-----------------------|-------------------------|---------|
|
||||
| vpc_id | vpc id | string |
|
||||
| public_subnets | list of cidr blocks | list |
|
||||
| private_subnets | list of cidr blocks | list |
|
||||
| secondary_cidr_blocks | list of secondary cidrs | list |
|
||||
|
||||
## Example:
|
||||
|
||||
```hcl
|
||||
module "vpc-subnets" {
|
||||
source = "../../modules/networking/vpc-subnet-manual"
|
||||
|
||||
resource-prefix = local.resource-prefix
|
||||
private-subnet-cidrs = ["172.17.0.0/24", "172.17.1.0/24"]
|
||||
public-subnet-cidrs = ["172.17.10.0/24", "172.17.11.0/24"]
|
||||
vpc-cidr = "172.17.0.0/16"
|
||||
enable-flow-log = false
|
||||
vpcflowlog-cwl-loggroup-key-arn = ""
|
||||
create-nat-gateway = true
|
||||
create-free-vpc-endpoints = true
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,204 @@
|
||||
data "aws_caller_identity" "this" {
|
||||
provider = aws.NetworkDeployer
|
||||
}
|
||||
|
||||
data "aws_availability_zones" "available-az" {
|
||||
provider = aws.NetworkDeployer
|
||||
state = "available"
|
||||
}
|
||||
|
||||
data "aws_default_tags" "this" {
|
||||
lifecycle {
|
||||
postcondition {
|
||||
condition = length(self.tags) >= 1
|
||||
error_message = "Validation failed: Provider default_tags not set."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
locals {
|
||||
no-az = 2 # hard-coding to 2AZ
|
||||
vpc-cidr = var.vpc-cidr
|
||||
}
|
||||
|
||||
resource "aws_subnet" "private-subnets" {
|
||||
provider = aws.NetworkDeployer
|
||||
|
||||
count = length(var.private-subnet-cidrs)
|
||||
vpc_id = aws_vpc.vpc.id
|
||||
availability_zone = element(data.aws_availability_zones.available-az.names, count.index % 2)
|
||||
cidr_block = var.private-subnet-cidrs[count.index]
|
||||
tags = merge(data.aws_default_tags.this.tags, {
|
||||
Name = "${var.resource-prefix}-private-${split("-", element(data.aws_availability_zones.available-az.names, count.index))[2]}-${count.index + 1}"
|
||||
})
|
||||
}
|
||||
|
||||
resource "aws_subnet" "public-subnets" {
|
||||
provider = aws.NetworkDeployer
|
||||
|
||||
count = length(var.public-subnet-cidrs)
|
||||
vpc_id = aws_vpc.vpc.id
|
||||
availability_zone = element(data.aws_availability_zones.available-az.names, count.index % 2)
|
||||
cidr_block = var.public-subnet-cidrs[count.index]
|
||||
tags = merge(data.aws_default_tags.this.tags, {
|
||||
Name = "${var.resource-prefix}-public-${split("-", element(data.aws_availability_zones.available-az.names, count.index))[2]}-${count.index + 1}"
|
||||
})
|
||||
}
|
||||
|
||||
resource "aws_vpc" "vpc" {
|
||||
provider = aws.NetworkDeployer
|
||||
|
||||
cidr_block = var.vpc-cidr
|
||||
enable_dns_hostnames = true
|
||||
enable_dns_support = true
|
||||
|
||||
tags = {
|
||||
Name = "${var.resource-prefix}-vpc"
|
||||
}
|
||||
|
||||
lifecycle {
|
||||
create_before_destroy = true
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_vpc_ipv4_cidr_block_association" "additional_cidr" {
|
||||
provider = aws.NetworkDeployer
|
||||
|
||||
for_each = toset(var.secondary_cidr_blocks)
|
||||
vpc_id = aws_vpc.vpc.id
|
||||
cidr_block = each.value
|
||||
}
|
||||
|
||||
resource "aws_internet_gateway" "igw" {
|
||||
provider = aws.NetworkDeployer
|
||||
|
||||
count = length(var.public-subnet-cidrs) > 0 ? 1 : 0
|
||||
vpc_id = aws_vpc.vpc.id
|
||||
|
||||
tags = {
|
||||
Name = "${var.resource-prefix}-igw"
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_eip" "ngw-eip" {
|
||||
provider = aws.NetworkDeployer
|
||||
|
||||
count = var.create-nat-gateway ? 1 : 0
|
||||
# deprecated # vpc = true
|
||||
domain = "vpc"
|
||||
depends_on = [aws_internet_gateway.igw]
|
||||
}
|
||||
|
||||
resource "aws_nat_gateway" "ngw" {
|
||||
provider = aws.NetworkDeployer
|
||||
|
||||
count = var.create-nat-gateway ? 1 : 0
|
||||
allocation_id = aws_eip.ngw-eip[0].id
|
||||
subnet_id = aws_subnet.public-subnets[0].id
|
||||
|
||||
tags = {
|
||||
Name = "${var.resource-prefix}-ngw"
|
||||
}
|
||||
depends_on = [aws_internet_gateway.igw]
|
||||
}
|
||||
|
||||
resource "aws_route_table" "public-route-table" {
|
||||
provider = aws.NetworkDeployer
|
||||
|
||||
count = length(var.public-subnet-cidrs) > 0 ? 1 : 0
|
||||
vpc_id = aws_vpc.vpc.id
|
||||
tags = {
|
||||
Name = "${var.resource-prefix}-publicroutetable"
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_route_table" "private-route-table" {
|
||||
provider = aws.NetworkDeployer
|
||||
|
||||
count = length(var.private-subnet-cidrs) > 0 ? 1 : 0
|
||||
vpc_id = aws_vpc.vpc.id
|
||||
tags = {
|
||||
Name = "${var.resource-prefix}-privateroutetable"
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_route" "public-routes" {
|
||||
provider = aws.NetworkDeployer
|
||||
|
||||
count = length(var.public-subnet-cidrs) > 0 ? 1 : 0
|
||||
|
||||
destination_cidr_block = "0.0.0.0/0"
|
||||
gateway_id = aws_internet_gateway.igw[0].id
|
||||
route_table_id = aws_route_table.public-route-table[0].id
|
||||
}
|
||||
|
||||
resource "aws_route" "private-routes" {
|
||||
provider = aws.NetworkDeployer
|
||||
|
||||
count = length(var.private-subnet-cidrs) > 0 && var.create-nat-gateway ? 1 : 0
|
||||
|
||||
destination_cidr_block = "0.0.0.0/0"
|
||||
nat_gateway_id = aws_nat_gateway.ngw[0].id
|
||||
route_table_id = aws_route_table.private-route-table[0].id
|
||||
}
|
||||
|
||||
resource "aws_route_table_association" "public_route_association" {
|
||||
provider = aws.NetworkDeployer
|
||||
|
||||
count = length(aws_subnet.public-subnets)
|
||||
route_table_id = aws_route_table.public-route-table[0].id
|
||||
subnet_id = aws_subnet.public-subnets[count.index].id
|
||||
}
|
||||
|
||||
resource "aws_route_table_association" "private_route_association" {
|
||||
provider = aws.NetworkDeployer
|
||||
|
||||
count = length(aws_subnet.private-subnets)
|
||||
route_table_id = aws_route_table.private-route-table[0].id
|
||||
subnet_id = aws_subnet.private-subnets[count.index].id
|
||||
}
|
||||
|
||||
/*
|
||||
harden default security group. the default sg created by aws allows all egress.
|
||||
this resource limits ingress and egress from and to itself
|
||||
*/
|
||||
|
||||
resource "aws_default_security_group" "default-sg" {
|
||||
provider = aws.NetworkDeployer
|
||||
|
||||
vpc_id = aws_vpc.vpc.id
|
||||
ingress {
|
||||
protocol = -1
|
||||
self = true
|
||||
from_port = 0
|
||||
to_port = 0
|
||||
description = "Allow traffic coming from this SG"
|
||||
}
|
||||
egress {
|
||||
from_port = 0
|
||||
protocol = -1
|
||||
to_port = 0
|
||||
self = true
|
||||
description = "Allow traffic going to this SG"
|
||||
}
|
||||
tags = {
|
||||
Name = "${var.resource-prefix}-defaultsg"
|
||||
}
|
||||
}
|
||||
|
||||
# Enable gateway endpoints which are free
|
||||
|
||||
module "vpc-ep" {
|
||||
providers = {
|
||||
aws = aws.NetworkDeployer
|
||||
}
|
||||
|
||||
count = var.create-free-vpc-endpoints ? 1 : 0
|
||||
source = "../vpc-endpoints"
|
||||
|
||||
gateway-ep-services = ["s3", "dynamodb"]
|
||||
interface-ep-services = []
|
||||
resource-prefix = var.resource-prefix
|
||||
vpc-id = aws_vpc.vpc.id
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
output "vpc_id" {
|
||||
value = aws_vpc.vpc.id
|
||||
}
|
||||
|
||||
output "vpc-cidr" {
|
||||
value = aws_vpc.vpc.cidr_block
|
||||
}
|
||||
|
||||
output "public_subnets" {
|
||||
value = aws_subnet.public-subnets.*.cidr_block
|
||||
}
|
||||
|
||||
output "private_subnets" {
|
||||
value = aws_subnet.private-subnets.*.cidr_block
|
||||
}
|
||||
|
||||
output "public-subnet-ids" {
|
||||
value = aws_subnet.public-subnets.*.id
|
||||
}
|
||||
|
||||
output "private-subnet-ids" {
|
||||
value = aws_subnet.private-subnets.*.id
|
||||
}
|
||||
|
||||
output "private-route-table-id" {
|
||||
value = aws_route_table.private-route-table.*.id
|
||||
}
|
||||
|
||||
output "public-route-table-id" {
|
||||
value = aws_route_table.public-route-table.*.id
|
||||
}
|
||||
|
||||
output "route_tables_for_gateway_endpoints" {
|
||||
value = concat(aws_route_table.public-route-table.*.id, aws_route_table.private-route-table.*.id)
|
||||
}
|
||||
|
||||
output "secondary_cidr_blocks" {
|
||||
value = var.secondary_cidr_blocks
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
# requires 1.3.0 for postcondition validation
|
||||
# https://learn.hashicorp.com/tutorials/terraform/custom-conditions
|
||||
|
||||
# provider 5.0.0 or above is required by the domain attribute in aws_eip
|
||||
terraform {
|
||||
required_version = "~> 1.3.0"
|
||||
required_providers {
|
||||
aws = {
|
||||
source = "hashicorp/aws"
|
||||
version = ">= 5.0.0"
|
||||
configuration_aliases = [ aws.NetworkDeployer, aws.SecurityDeployer, aws.CommonDeployer ]
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
variable resource-prefix {}
|
||||
|
||||
# VPC variables
|
||||
variable "vpc-cidr" {}
|
||||
|
||||
variable "private-subnet-cidrs" {
|
||||
type = list(any)
|
||||
}
|
||||
|
||||
variable "public-subnet-cidrs" {
|
||||
type = list(any)
|
||||
}
|
||||
|
||||
variable "create-nat-gateway" {
|
||||
type = bool
|
||||
default = false
|
||||
}
|
||||
variable "enable-flow-log" {
|
||||
type = bool
|
||||
default = true
|
||||
}
|
||||
variable "vpcflowlog-retain-days" {
|
||||
type = number
|
||||
default = 90
|
||||
}
|
||||
variable "vpcflowlog-cwl-loggroup-key-arn" {}
|
||||
# variable "private-subnet-cidrs" {}
|
||||
# variable "public-subnet-cidrs" {}
|
||||
variable "create-free-vpc-endpoints" {
|
||||
type = bool
|
||||
default = true
|
||||
}
|
||||
variable "secondary_cidr_blocks" {
|
||||
type = list(string)
|
||||
description = "Additional cidr blocks"
|
||||
default = []
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
resource "aws_flow_log" "vpc-flowlog" {
|
||||
provider = aws.NetworkDeployer
|
||||
count = var.enable-flow-log ? 1 : 0
|
||||
iam_role_arn = aws_iam_role.vpcflowlog-role.arn
|
||||
log_destination = aws_cloudwatch_log_group.vpcflowlog-loggroup[0].arn
|
||||
traffic_type = "ALL"
|
||||
vpc_id = aws_vpc.vpc.id
|
||||
tags = {
|
||||
Name = "${var.resource-prefix}-vpcflowlog"
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_cloudwatch_log_group" "vpcflowlog-loggroup" {
|
||||
provider = aws.CommonDeployer
|
||||
count = var.enable-flow-log ? 1 : 0
|
||||
|
||||
name_prefix = "vpcflowlog/${aws_vpc.vpc.id}/"
|
||||
kms_key_id = var.vpcflowlog-cwl-loggroup-key-arn
|
||||
|
||||
retention_in_days = var.vpcflowlog-retain-days
|
||||
}
|
||||
|
||||
resource "random_id" "rid" {
|
||||
byte_length = 2
|
||||
}
|
||||
|
||||
resource "aws_iam_role" "vpcflowlog-role" {
|
||||
provider = aws.SecurityDeployer
|
||||
name = "VpcFlowlogRole-${random_id.rid.dec}"
|
||||
path = "/service/"
|
||||
assume_role_policy = <<EOF
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Sid": "",
|
||||
"Effect": "Allow",
|
||||
"Principal": {
|
||||
"Service": "vpc-flow-logs.amazonaws.com"
|
||||
},
|
||||
"Action": "sts:AssumeRole"
|
||||
}
|
||||
]
|
||||
}
|
||||
EOF
|
||||
}
|
||||
|
||||
resource "aws_iam_role_policy" "vpcflowlog-role-policy" {
|
||||
provider = aws.SecurityDeployer
|
||||
name = "VpcFlowlogRole-${random_id.rid.dec}"
|
||||
role = aws_iam_role.vpcflowlog-role.id
|
||||
|
||||
policy = <<EOF
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Action": [
|
||||
"logs:CreateLogGroup",
|
||||
"logs:CreateLogStream",
|
||||
"logs:PutLogEvents",
|
||||
"logs:DescribeLogGroups",
|
||||
"logs:DescribeLogStreams"
|
||||
],
|
||||
"Effect": "Allow",
|
||||
"Resource": "*"
|
||||
}
|
||||
]
|
||||
}
|
||||
EOF
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
# Overview
|
||||
This module performs the following tasks:
|
||||
|
||||
- Create VPC, vpcflow log
|
||||
- Create subnets in every AZ
|
||||
- Create IGW, NGW
|
||||
- Create s3 and ddb endpoints which are free
|
||||
- Additional CIDR, if any, will introduce a 10s wait before subnet creation
|
||||
|
||||
## Subnet addressing
|
||||
|
||||
Subnet cidrs needs to be specified manually
|
||||
|
||||
## Inputs:
|
||||
|
||||
| Name | Description | Type | Default | Required |
|
||||
|---------------------------------|---------------------------------------------------|---------------|---------|----------|
|
||||
| private-subnet-cidrs | private subnets | list | [] | yes |
|
||||
| public-subnet-cidrs | public subnets | list | [] | yes |
|
||||
| create-nat-gateway | whether to deploy NAT gateway for private subnets | bool | true | yes |
|
||||
| vpc-cidr | VPC cidr | string | none | yes |
|
||||
| enable-flowlog | whether to enable vpc flowlog | bool | true | yes |
|
||||
| vpcflowlog-retain-days | number of days to retain vpc cloudwatch log | number | 90 | yes |
|
||||
| vpcflowlog-cwl-loggroup-key-arn | kms key alias arn for log group encryption | string | none | yes |
|
||||
| secondary_cidr_blocks | Additional CIDR blocks to be associated with VPC | list(string) | none | no |
|
||||
| resource-prefix | Prefix of resource name | string | "" | yes |
|
||||
|
||||
|
||||
## Outputs:
|
||||
|
||||
| Name | Description | Type |
|
||||
|-----------------------|-------------------------|---------|
|
||||
| vpc_id | vpc id | string |
|
||||
| public_subnets | list of cidr blocks | list |
|
||||
| private_subnets | list of cidr blocks | list |
|
||||
| secondary_cidr_blocks | list of secondary cidrs | list |
|
||||
|
||||
## Using s3 bucket for flowlog
|
||||
Make sure the bucket policy allows access from delivery.logs. If the bucket is encrypted with CMK,
|
||||
make sure the key policy allows the aws service delivery.logs.amazonaws.com.
|
||||
|
||||
### Sample s3 bucket policy
|
||||
```json
|
||||
{
|
||||
"Id" : "policy01",
|
||||
"Version" : "2012-10-17",
|
||||
"Statement" : [
|
||||
{
|
||||
"Sid" : "AWSLogDeliveryWrite",
|
||||
"Effect" : "Allow",
|
||||
"Principal" : {
|
||||
"Service" : "delivery.logs.amazonaws.com"
|
||||
},
|
||||
"Action" : "s3:PutObject",
|
||||
"Resource" : "arn:aws:s3:::BUCKET_NAME/*"
|
||||
},
|
||||
{
|
||||
"Sid" : "AWSLogDeliveryCheck",
|
||||
"Effect" : "Allow",
|
||||
"Principal" : {
|
||||
"Service" : "delivery.logs.amazonaws.com"
|
||||
},
|
||||
"Action" : "s3:GetBucketAcl",
|
||||
"Resource" : "arn:aws:s3:::BUCKET_NAME"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Sample CMK policy
|
||||
```json
|
||||
{
|
||||
"Sid": "Allow AWS Service to use the key",
|
||||
"Effect": "Allow",
|
||||
"Principal": {
|
||||
"Service": [
|
||||
"delivery.logs.amazonaws.com",
|
||||
"cloudtrail.amazonaws.com",
|
||||
"s3.amazonaws.com"
|
||||
]
|
||||
},
|
||||
"Action": [
|
||||
"kms:Encrypt",
|
||||
"kms:Decrypt",
|
||||
"kms:ReEncrypt*",
|
||||
"kms:GenerateDataKey*",
|
||||
"kms:DescribeKey"
|
||||
],
|
||||
"Resource": "*"
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## Example:
|
||||
|
||||
```hcl
|
||||
module "vpc-subnets" {
|
||||
source = "../../modules/networking/vpc-subnet-manual"
|
||||
|
||||
resource-prefix = local.resource-prefix
|
||||
private-subnet-cidrs = ["172.17.0.0/24", "172.17.1.0/24"]
|
||||
public-subnet-cidrs = ["172.17.10.0/24", "172.17.11.0/24"]
|
||||
vpc-cidr = "172.17.0.0/16"
|
||||
enable-flow-log = false
|
||||
vpcflowlog-cwl-loggroup-key-arn = ""
|
||||
create-nat-gateway = true
|
||||
create-free-vpc-endpoints = true
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,179 @@
|
||||
data "aws_caller_identity" "this" {}
|
||||
|
||||
data "aws_availability_zones" "available-az" {
|
||||
state = "available"
|
||||
}
|
||||
|
||||
data "aws_default_tags" "this" {
|
||||
lifecycle {
|
||||
postcondition {
|
||||
condition = length(self.tags) >= 1
|
||||
error_message = "Validation failed: Provider default_tags not set."
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
locals {
|
||||
no-az = 2 # hard-coding to 2AZ
|
||||
vpc-cidr = var.vpc-cidr
|
||||
}
|
||||
|
||||
resource "aws_subnet" "private-subnets" {
|
||||
count = length(var.private-subnet-cidrs)
|
||||
vpc_id = aws_vpc.vpc.id
|
||||
availability_zone = element(data.aws_availability_zones.available-az.names, count.index % 2)
|
||||
cidr_block = var.private-subnet-cidrs[count.index]
|
||||
tags = merge(data.aws_default_tags.this.tags, {
|
||||
Name = "${var.resource-prefix}-private-${split("-", element(data.aws_availability_zones.available-az.names, count.index))[2]}-${count.index + 1}"
|
||||
TfInternal = try(time_sleep.wait-10s[0].triggers.slept, "na")
|
||||
})
|
||||
}
|
||||
|
||||
resource "aws_subnet" "public-subnets" {
|
||||
count = length(var.public-subnet-cidrs)
|
||||
vpc_id = aws_vpc.vpc.id
|
||||
availability_zone = element(data.aws_availability_zones.available-az.names, count.index % 2)
|
||||
cidr_block = var.public-subnet-cidrs[count.index]
|
||||
tags = merge(data.aws_default_tags.this.tags, {
|
||||
Name = "${var.resource-prefix}-public-${split("-", element(data.aws_availability_zones.available-az.names, count.index))[2]}-${count.index + 1}"
|
||||
TfInternal = try(time_sleep.wait-10s[0].triggers.slept, "na")
|
||||
})
|
||||
}
|
||||
|
||||
resource "aws_vpc" "vpc" {
|
||||
cidr_block = var.vpc-cidr
|
||||
enable_dns_hostnames = true
|
||||
enable_dns_support = true
|
||||
|
||||
tags = {
|
||||
Name = "${var.resource-prefix}-vpc"
|
||||
}
|
||||
|
||||
lifecycle {
|
||||
create_before_destroy = true
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_vpc_ipv4_cidr_block_association" "additional_cidr" {
|
||||
for_each = toset(var.secondary_cidr_blocks)
|
||||
vpc_id = aws_vpc.vpc.id
|
||||
cidr_block = each.value
|
||||
}
|
||||
|
||||
# Optionally wait for additional cidr association
|
||||
resource "time_sleep" "wait-10s" {
|
||||
depends_on = [aws_vpc_ipv4_cidr_block_association.additional_cidr]
|
||||
count = length(var.secondary_cidr_blocks)
|
||||
create_duration = "10s"
|
||||
triggers = {
|
||||
slept = length(aws_vpc_ipv4_cidr_block_association.additional_cidr)
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_internet_gateway" "igw" {
|
||||
count = length(var.public-subnet-cidrs) > 0 ? 1 : 0
|
||||
vpc_id = aws_vpc.vpc.id
|
||||
|
||||
tags = {
|
||||
Name = "${var.resource-prefix}-igw"
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_eip" "ngw-eip" {
|
||||
count = var.create-nat-gateway ? 1 : 0
|
||||
# deprecated # vpc = true
|
||||
domain = "vpc"
|
||||
depends_on = [aws_internet_gateway.igw]
|
||||
}
|
||||
|
||||
resource "aws_nat_gateway" "ngw" {
|
||||
count = var.create-nat-gateway ? 1 : 0
|
||||
allocation_id = aws_eip.ngw-eip[0].id
|
||||
subnet_id = aws_subnet.public-subnets[0].id
|
||||
|
||||
tags = {
|
||||
Name = "${var.resource-prefix}-ngw"
|
||||
}
|
||||
depends_on = [aws_internet_gateway.igw]
|
||||
}
|
||||
|
||||
resource "aws_route_table" "public-route-table" {
|
||||
count = length(var.public-subnet-cidrs) > 0 ? 1 : 0
|
||||
vpc_id = aws_vpc.vpc.id
|
||||
tags = {
|
||||
Name = "${var.resource-prefix}-publicroutetable"
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_route_table" "private-route-table" {
|
||||
count = length(var.private-subnet-cidrs) > 0 ? 1 : 0
|
||||
vpc_id = aws_vpc.vpc.id
|
||||
tags = {
|
||||
Name = "${var.resource-prefix}-privateroutetable"
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_route" "public-routes" {
|
||||
count = length(var.public-subnet-cidrs) > 0 ? 1 : 0
|
||||
|
||||
destination_cidr_block = "0.0.0.0/0"
|
||||
gateway_id = aws_internet_gateway.igw[0].id
|
||||
route_table_id = aws_route_table.public-route-table[0].id
|
||||
}
|
||||
|
||||
resource "aws_route" "private-routes" {
|
||||
count = length(var.private-subnet-cidrs) > 0 && var.create-nat-gateway ? 1 : 0
|
||||
|
||||
destination_cidr_block = "0.0.0.0/0"
|
||||
nat_gateway_id = aws_nat_gateway.ngw[0].id
|
||||
route_table_id = aws_route_table.private-route-table[0].id
|
||||
}
|
||||
|
||||
resource "aws_route_table_association" "public_route_association" {
|
||||
count = length(aws_subnet.public-subnets)
|
||||
route_table_id = aws_route_table.public-route-table[0].id
|
||||
subnet_id = aws_subnet.public-subnets[count.index].id
|
||||
}
|
||||
|
||||
resource "aws_route_table_association" "private_route_association" {
|
||||
count = length(aws_subnet.private-subnets)
|
||||
route_table_id = aws_route_table.private-route-table[0].id
|
||||
subnet_id = aws_subnet.private-subnets[count.index].id
|
||||
}
|
||||
|
||||
/*
|
||||
harden default security group. the default sg created by aws allows all egress.
|
||||
this resource limits ingress and egress from and to itself
|
||||
*/
|
||||
|
||||
resource "aws_default_security_group" "default-sg" {
|
||||
vpc_id = aws_vpc.vpc.id
|
||||
ingress {
|
||||
protocol = -1
|
||||
self = true
|
||||
from_port = 0
|
||||
to_port = 0
|
||||
description = "Allow traffic coming from this SG"
|
||||
}
|
||||
egress {
|
||||
from_port = 0
|
||||
protocol = -1
|
||||
to_port = 0
|
||||
self = true
|
||||
description = "Allow traffic going to this SG"
|
||||
}
|
||||
tags = {
|
||||
Name = "${var.resource-prefix}-defaultsg"
|
||||
}
|
||||
}
|
||||
|
||||
# Enable gateway endpoints which are free
|
||||
module "vpc-ep" {
|
||||
count = var.create-free-vpc-endpoints ? 1 : 0
|
||||
source = "../vpc-endpoints"
|
||||
|
||||
gateway-ep-services = ["s3", "dynamodb"]
|
||||
interface-ep-services = []
|
||||
resource-prefix = var.resource-prefix
|
||||
vpc-id = aws_vpc.vpc.id
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
output "vpc_id" {
|
||||
value = aws_vpc.vpc.id
|
||||
}
|
||||
|
||||
output "vpc-cidr" {
|
||||
value = aws_vpc.vpc.cidr_block
|
||||
}
|
||||
|
||||
output "public_subnets" {
|
||||
value = aws_subnet.public-subnets.*.cidr_block
|
||||
}
|
||||
|
||||
output "private_subnets" {
|
||||
value = aws_subnet.private-subnets.*.cidr_block
|
||||
}
|
||||
|
||||
output "public-subnet-ids" {
|
||||
value = aws_subnet.public-subnets.*.id
|
||||
}
|
||||
|
||||
output "private-subnet-ids" {
|
||||
value = aws_subnet.private-subnets.*.id
|
||||
}
|
||||
|
||||
output "private-route-table-id" {
|
||||
value = aws_route_table.private-route-table.*.id
|
||||
}
|
||||
|
||||
output "public-route-table-id" {
|
||||
value = aws_route_table.public-route-table.*.id
|
||||
}
|
||||
|
||||
output "route_tables_for_gateway_endpoints" {
|
||||
value = concat(aws_route_table.public-route-table.*.id, aws_route_table.private-route-table.*.id)
|
||||
}
|
||||
|
||||
output "secondary_cidr_blocks" {
|
||||
value = var.secondary_cidr_blocks
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
# requires 1.3.0 for postcondition validation
|
||||
# https://learn.hashicorp.com/tutorials/terraform/custom-conditions
|
||||
|
||||
# provider 5.0.0 or above is required by the domain attribute in aws_eip
|
||||
terraform {
|
||||
required_version = "~> 1.3.0"
|
||||
required_providers {
|
||||
aws = {
|
||||
source = "hashicorp/aws"
|
||||
version = ">= 5.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
variable "resource-prefix" {
|
||||
type = string
|
||||
description = "Prefix of resource"
|
||||
}
|
||||
|
||||
# VPC variables
|
||||
variable "vpc-cidr" {
|
||||
type = string
|
||||
description = "VPC primary CIDR"
|
||||
}
|
||||
|
||||
variable "private-subnet-cidrs" {
|
||||
type = list(string)
|
||||
description = "Private subnet CIDRs"
|
||||
}
|
||||
|
||||
variable "public-subnet-cidrs" {
|
||||
type = list(string)
|
||||
description = "Public subnet CIDRs"
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "create-nat-gateway" {
|
||||
type = bool
|
||||
default = false
|
||||
}
|
||||
|
||||
variable "flow-log-destination" {
|
||||
type = string
|
||||
description = "Destination of flowlog. Valid destinations are s3 or cwlog"
|
||||
default = null
|
||||
}
|
||||
|
||||
variable "flow-log-bucket-arn" {
|
||||
type = string
|
||||
default = null
|
||||
description = "Arn of S3 bucket to be used for flow logging"
|
||||
}
|
||||
|
||||
variable "enable-flow-log" {
|
||||
type = bool
|
||||
default = true
|
||||
}
|
||||
|
||||
variable "vpcflowlog-retain-days" {
|
||||
type = number
|
||||
default = 90
|
||||
description = "Log retention period for CWlogs"
|
||||
}
|
||||
|
||||
variable "vpcflowlog-cwl-loggroup-key-arn" {
|
||||
type = string
|
||||
description = "KMS key arn for cwlog encryption"
|
||||
}
|
||||
|
||||
variable "create-free-vpc-endpoints" {
|
||||
type = bool
|
||||
default = true
|
||||
}
|
||||
|
||||
variable "secondary_cidr_blocks" {
|
||||
type = list(string)
|
||||
description = "Additional cidr blocks"
|
||||
default = []
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
resource "aws_flow_log" "vpc-flowlog" {
|
||||
count = var.enable-flow-log && var.flow-log-destination == "cwlog" ? 1 : 0
|
||||
iam_role_arn = aws_iam_role.vpcflowlog-role[0].arn
|
||||
log_destination = aws_cloudwatch_log_group.vpcflowlog-loggroup[0].arn
|
||||
traffic_type = "ALL"
|
||||
vpc_id = aws_vpc.vpc.id
|
||||
tags = {
|
||||
Name = "${var.resource-prefix}-vpcflowlog"
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_flow_log" "vpc-flowlog-s3" {
|
||||
count = var.enable-flow-log && var.flow-log-destination == "s3" ? 1 : 0
|
||||
log_destination_type = "s3"
|
||||
log_destination = var.flow-log-bucket-arn
|
||||
traffic_type = "ALL"
|
||||
vpc_id = aws_vpc.vpc.id
|
||||
tags = {
|
||||
Name = "${var.resource-prefix}-vpcflowlog"
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_cloudwatch_log_group" "vpcflowlog-loggroup" {
|
||||
count = var.enable-flow-log && var.flow-log-destination == "cwlog" ? 1 : 0
|
||||
name_prefix = "vpcflowlog/${aws_vpc.vpc.id}/"
|
||||
kms_key_id = var.vpcflowlog-cwl-loggroup-key-arn
|
||||
retention_in_days = var.vpcflowlog-retain-days
|
||||
}
|
||||
|
||||
resource "random_id" "rid" {
|
||||
byte_length = 2
|
||||
}
|
||||
|
||||
resource "aws_iam_role" "vpcflowlog-role" {
|
||||
count = var.enable-flow-log && var.flow-log-destination == "cwlog" ? 1 : 0
|
||||
name = "VpcFlowlogRole-${random_id.rid.dec}"
|
||||
path = "/service/"
|
||||
assume_role_policy = jsonencode(
|
||||
{
|
||||
"Version" : "2012-10-17",
|
||||
"Statement" : [
|
||||
{
|
||||
"Sid" : "",
|
||||
"Effect" : "Allow",
|
||||
"Principal" : {
|
||||
"Service" : "vpc-flow-logs.amazonaws.com"
|
||||
},
|
||||
"Action" : "sts:AssumeRole"
|
||||
}
|
||||
]
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
resource "aws_iam_role_policy" "vpcflowlog-role-policy" {
|
||||
count = var.enable-flow-log && var.flow-log-destination == "cwlog" ? 1 : 0
|
||||
name = "VpcFlowlogRole-${random_id.rid.dec}"
|
||||
role = aws_iam_role.vpcflowlog-role[0].id
|
||||
|
||||
policy = jsonencode(
|
||||
{
|
||||
"Version" : "2012-10-17",
|
||||
"Statement" : [
|
||||
{
|
||||
"Action" : [
|
||||
"logs:CreateLogGroup",
|
||||
"logs:CreateLogStream",
|
||||
"logs:PutLogEvents",
|
||||
"logs:DescribeLogGroups",
|
||||
"logs:DescribeLogStreams",
|
||||
"kms:Encrypt",
|
||||
"kms:ReEncrypt",
|
||||
"kms:Decrypt"
|
||||
],
|
||||
"Effect" : "Allow",
|
||||
"Resource" : "*"
|
||||
}
|
||||
]
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
# Overview
|
||||
|
||||
This module performs the following tasks:
|
||||
|
||||
- Create VPC, vpcflow log
|
||||
- Create subnets in every AZ
|
||||
- Create IGW, NGW
|
||||
|
||||
## Subnet addressing
|
||||
|
||||
Subnet cidrs are calculated automatically. Due to the design of terraform's cidrsubnets, this module has limitations:
|
||||
|
||||
* supports 2, 4, 6, 8, or 12 subnets in total.
|
||||
* hard-coded to work with 2 AZs, regardless of number of AZs available in the region.
|
||||
|
||||
Based on the input variables, it will create subnet cidrs using the following function
|
||||
|
||||
| Private Subnets per az | Public Subnets per az | Function | Example if a /24 is used on VPC |
|
||||
|------------------------|-----------------------|------------------------------------------------------|---------------------------------|
|
||||
| 1 | 0 | cidrsubnets(local.vpc-cidr, 1,1) | 2 * /25 |
|
||||
| 1 | 1 | cidrsubnets(local.vpc-cidr, 2,2,2,2) | 4 * /26 |
|
||||
| 2 | 1 | cidrsubnets(local.vpc-cidr, 3,3,3,3,3,3) | 6 * /27 |
|
||||
| 2 | 2 | cidrsubnets(local.vpc-cidr, 3,3,3,3,3,3,3,3) | 8 * /27 |
|
||||
| 6 | 6 | cidrsubnets(local.vpc-cidr, 4,4,4,4,4,4,4,4,4,4,4,4) | 12 * /28 |
|
||||
|
||||
## Inputs:
|
||||
|
||||
| Name | Description | Type | Default | Required |
|
||||
| -------------------------------- | ------------------------------------------------- | ------ | ------- |:--------:|
|
||||
| application | name of application | string | none | yes |
|
||||
| environment | capacity of environment (prd/dev/lab) | string | none | yes |
|
||||
| customer-name | owner of aws resources | string | none | yes |
|
||||
| project | name of project | string | none | yes |
|
||||
| default-tags | tags to be added to resources | list | none | yes |
|
||||
| number-of-private-subnets-per-az | number of private subnets per az | number | 0 | yes |
|
||||
| number-of-public-subnets-per-az | number of public subnets per az | number | 0 | yes |
|
||||
| create-nat-gateway | whether to deploy NAT gateway for private subnets | bool | true | yes |
|
||||
| vpc-cidr | VPC cidr | string | none | yes |
|
||||
| enable-flowlog | whether to enable vpc flowlog | bool | true | yes |
|
||||
| vpcflowlog-retain-days | number of days to retain vpc cloudwatch log | number | 90 | yes |
|
||||
| aws-region-short | short name of aws region (e.g. apne1) | string | none | yes |
|
||||
| aws-region | aws region (e.g. ap-northeast-1) | string | none | yes |
|
||||
| vpcflowlog-cwl-loggroup-key-arn | kms key alias arn for log group encryption | string | none | yes |
|
||||
|
||||
## Outputs:
|
||||
|
||||
| Name | Description | Type |
|
||||
| --------------- | ------------------- | ------ |
|
||||
| vpc_id | vpc id | string |
|
||||
| public_subnets | list of cidr blocks | list |
|
||||
| private_subnets | list of cidr blocks | list |
|
||||
@@ -0,0 +1 @@
|
||||
data aws_caller_identity this {}
|
||||
@@ -0,0 +1,31 @@
|
||||
output vpc_id {
|
||||
value = aws_vpc.vpc.id
|
||||
}
|
||||
|
||||
output public_subnets {
|
||||
value = aws_subnet.public-subnets.*.cidr_block
|
||||
}
|
||||
|
||||
output private_subnets {
|
||||
value = aws_subnet.private-subnets.*.cidr_block
|
||||
}
|
||||
|
||||
output public-subnet-ids {
|
||||
value = aws_subnet.public-subnets.*.id
|
||||
}
|
||||
|
||||
output private-subnet-ids {
|
||||
value = aws_subnet.private-subnets.*.id
|
||||
}
|
||||
|
||||
output vpc-cidr {
|
||||
value = aws_vpc.vpc.cidr_block
|
||||
}
|
||||
|
||||
output private-rtb-id {
|
||||
value = try(aws_route_table.private-route-table[0].id, null)
|
||||
}
|
||||
|
||||
output public-rtb-id {
|
||||
value = try(aws_route_table.public-route-table[0].id, null)
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
variable "customer-name" {}
|
||||
variable "environment" {}
|
||||
variable "project" {}
|
||||
variable "application" {}
|
||||
# variable "default-tags" {}
|
||||
variable "aws-region" {}
|
||||
|
||||
locals {
|
||||
resource-prefix = "${var.environment}-${substr(var.aws-region, 0, 2)}-${var.customer-name}-${var.project}"
|
||||
}
|
||||
|
||||
# VPC variables
|
||||
variable "vpc-cidr" {}
|
||||
|
||||
variable number-of-public-subnets-per-az {
|
||||
type = number
|
||||
default = 0
|
||||
}
|
||||
variable number-of-private-subnets-per-az {
|
||||
type = number
|
||||
default = 0
|
||||
}
|
||||
|
||||
variable "create-nat-gateway" {
|
||||
type = bool
|
||||
default = false
|
||||
}
|
||||
variable "enable-flow-log" {
|
||||
type = bool
|
||||
default = true
|
||||
}
|
||||
variable "vpcflowlog-retain-days" {
|
||||
type = number
|
||||
default = 90
|
||||
}
|
||||
variable "vpcflowlog-cwl-loggroup-key-arn" {}
|
||||
# variable "private-subnet-cidrs" {}
|
||||
# variable "public-subnet-cidrs" {}
|
||||
variable "create-free-vpc-endpoints" {
|
||||
type = bool
|
||||
default = true
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
resource "aws_flow_log" "vpc-flowlog" {
|
||||
count = var.enable-flow-log ? 1 : 0
|
||||
iam_role_arn = aws_iam_role.vpcflowlog-role.arn
|
||||
log_destination = aws_cloudwatch_log_group.vpcflowlog-loggroup[0].arn
|
||||
traffic_type = "ALL"
|
||||
vpc_id = aws_vpc.vpc.id
|
||||
tags = {
|
||||
Name = "${local.resource-prefix}-vpcflowlog"
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_cloudwatch_log_group" "vpcflowlog-loggroup" {
|
||||
count = var.enable-flow-log ? 1 : 0
|
||||
|
||||
name_prefix = "vpcflowlog/${aws_vpc.vpc.id}/"
|
||||
kms_key_id = var.vpcflowlog-cwl-loggroup-key-arn
|
||||
|
||||
retention_in_days = var.vpcflowlog-retain-days
|
||||
}
|
||||
|
||||
resource "aws_iam_role" "vpcflowlog-role" {
|
||||
name = "${local.resource-prefix}-vpcflowlog"
|
||||
path = "/service/"
|
||||
assume_role_policy = <<EOF
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Sid": "",
|
||||
"Effect": "Allow",
|
||||
"Principal": {
|
||||
"Service": "vpc-flow-logs.amazonaws.com"
|
||||
},
|
||||
"Action": "sts:AssumeRole"
|
||||
}
|
||||
]
|
||||
}
|
||||
EOF
|
||||
}
|
||||
|
||||
resource "aws_iam_role_policy" "vpcflowlog-role-policy" {
|
||||
name = "${local.resource-prefix}-vpcflowlog"
|
||||
role = aws_iam_role.vpcflowlog-role.id
|
||||
|
||||
policy = <<EOF
|
||||
{
|
||||
"Version": "2012-10-17",
|
||||
"Statement": [
|
||||
{
|
||||
"Action": [
|
||||
"logs:CreateLogGroup",
|
||||
"logs:CreateLogStream",
|
||||
"logs:PutLogEvents",
|
||||
"logs:DescribeLogGroups",
|
||||
"logs:DescribeLogStreams"
|
||||
],
|
||||
"Effect": "Allow",
|
||||
"Resource": "*"
|
||||
}
|
||||
]
|
||||
}
|
||||
EOF
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
data "aws_availability_zones" "available-az" {
|
||||
state = "available"
|
||||
}
|
||||
|
||||
locals {
|
||||
// subnet_start = cidrsubnets(var.vpc-cidr, 1, 1) # divide vpc into 2
|
||||
# no-az = length(data.aws_availability_zones.available-az.id)
|
||||
no-az = 2 # hard-coding to 2AZ
|
||||
vpc-cidr = var.vpc-cidr
|
||||
total-no-subnets = local.no-az * (var.number-of-private-subnets-per-az + var.number-of-public-subnets-per-az)
|
||||
|
||||
# simple-divide = local.total-no-subnets >=8 ? cidrsubnets(local.vpc-cidr, 4,4,4,4,4,4,4,4) : local.total-no-subnets >=6 ? cidrsubnets(local.vpc-cidr, 3,3,3,3,3,3) : local.total-no-subnets >=4 ? cidrsubnets(local.vpc-cidr, 2,2,2,2) : local.total-no-subnets >=2 ? cidrsubnets(local.vpc-cidr, 1,1) : null
|
||||
simple-divide = local.total-no-subnets >= 12 ? cidrsubnets(local.vpc-cidr, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4) : local.total-no-subnets >= 8 ? cidrsubnets(local.vpc-cidr, 3, 3, 3, 3, 3, 3, 3, 3) : local.total-no-subnets >= 6 ? cidrsubnets(local.vpc-cidr, 3, 3, 3, 3, 3, 3) : local.total-no-subnets >= 4 ? cidrsubnets(local.vpc-cidr, 2, 2, 2, 2) : local.total-no-subnets >= 2 ? cidrsubnets(local.vpc-cidr, 1, 1) : null
|
||||
public-subnets = slice(local.simple-divide, 0, var.number-of-public-subnets-per-az * local.no-az)
|
||||
private-subnets = slice(local.simple-divide, var.number-of-public-subnets-per-az * local.no-az, local.total-no-subnets)
|
||||
}
|
||||
|
||||
resource "aws_subnet" "private-subnets" {
|
||||
count = length(local.private-subnets)
|
||||
# count = length(var.private-subnet-cidrs)
|
||||
# count = var.number-of-private-subnets-per-az * length(data.aws_availability_zones.available-az.names)
|
||||
vpc_id = aws_vpc.vpc.id
|
||||
availability_zone = element(data.aws_availability_zones.available-az.names, count.index)
|
||||
# cidr_block = cidrsubnet(local.subnet_start[0], 2, count.index)
|
||||
# cidr_block = var.private-subnet-cidrs[count.index]
|
||||
cidr_block = local.private-subnets[count.index]
|
||||
tags = {
|
||||
Name = "${local.resource-prefix}-private-${split("-", element(data.aws_availability_zones.available-az.names, count.index))[2]}-${count.index + 1}"
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_subnet" "public-subnets" {
|
||||
count = length(local.public-subnets)
|
||||
# count = length(var.public-subnet-cidrs)
|
||||
# count = var.number-of-public-subnets-per-az * length(data.aws_availability_zones.available-az.names)
|
||||
vpc_id = aws_vpc.vpc.id
|
||||
availability_zone = element(data.aws_availability_zones.available-az.names, count.index)
|
||||
# cidr_block = cidrsubnet(local.subnet_start[1], 2, count.index)
|
||||
# cidr_block = var.public-subnet-cidrs[count.index]
|
||||
cidr_block = local.public-subnets[count.index]
|
||||
tags = {
|
||||
Name = "${local.resource-prefix}-public-${split("-", element(data.aws_availability_zones.available-az.names, count.index))[2]}-${count.index + 1}"
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_vpc" "vpc" {
|
||||
cidr_block = var.vpc-cidr
|
||||
enable_dns_hostnames = true
|
||||
enable_dns_support = true
|
||||
|
||||
tags = {
|
||||
Name = "${local.resource-prefix}-vpc"
|
||||
}
|
||||
|
||||
lifecycle {
|
||||
create_before_destroy = true
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_internet_gateway" "igw" {
|
||||
count = var.number-of-public-subnets-per-az > 0 ? 1 : 0
|
||||
vpc_id = aws_vpc.vpc.id
|
||||
|
||||
tags = {
|
||||
Name = "${local.resource-prefix}-igw"
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_eip" "ngw-eip" {
|
||||
count = var.create-nat-gateway ? 1 : 0
|
||||
domain = "vpc"
|
||||
depends_on = [aws_internet_gateway.igw]
|
||||
}
|
||||
|
||||
resource "aws_nat_gateway" "ngw" {
|
||||
count = var.create-nat-gateway ? 1 : 0
|
||||
allocation_id = aws_eip.ngw-eip[0].id
|
||||
subnet_id = aws_subnet.public-subnets[0].id
|
||||
|
||||
tags = {
|
||||
Name = "${local.resource-prefix}-ngw"
|
||||
}
|
||||
|
||||
depends_on = [aws_internet_gateway.igw]
|
||||
}
|
||||
|
||||
resource "aws_route_table" "public-route-table" {
|
||||
count = var.number-of-public-subnets-per-az > 0 ? 1 : 0
|
||||
vpc_id = aws_vpc.vpc.id
|
||||
tags = {
|
||||
Name = "${local.resource-prefix}-public"
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_route_table" "private-route-table" {
|
||||
count = var.number-of-private-subnets-per-az > 0 ? 1 : 0
|
||||
vpc_id = aws_vpc.vpc.id
|
||||
tags = {
|
||||
Name = "${local.resource-prefix}-private"
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_route" "public-routes" {
|
||||
count = var.number-of-public-subnets-per-az > 0 ? 1 : 0
|
||||
|
||||
destination_cidr_block = "0.0.0.0/0"
|
||||
gateway_id = aws_internet_gateway.igw[0].id
|
||||
route_table_id = aws_route_table.public-route-table[0].id
|
||||
}
|
||||
|
||||
resource "aws_route" "private-routes" {
|
||||
count = var.number-of-private-subnets-per-az > 0 && var.create-nat-gateway ? 1 : 0
|
||||
|
||||
destination_cidr_block = "0.0.0.0/0"
|
||||
nat_gateway_id = aws_nat_gateway.ngw[0].id
|
||||
route_table_id = aws_route_table.private-route-table[0].id
|
||||
}
|
||||
|
||||
resource "aws_route_table_association" "public_route_association" {
|
||||
count = length(aws_subnet.public-subnets)
|
||||
route_table_id = aws_route_table.public-route-table[0].id
|
||||
subnet_id = aws_subnet.public-subnets[count.index].id
|
||||
}
|
||||
|
||||
resource "aws_route_table_association" "private_route_association" {
|
||||
count = length(aws_subnet.private-subnets)
|
||||
route_table_id = aws_route_table.private-route-table[0].id
|
||||
subnet_id = aws_subnet.private-subnets[count.index].id
|
||||
}
|
||||
|
||||
/*
|
||||
harden default security group. the default sg created by aws allows all egress.
|
||||
this resource limits ingress and egress from and to itself
|
||||
*/
|
||||
|
||||
resource "aws_default_security_group" "default-sg" {
|
||||
vpc_id = aws_vpc.vpc.id
|
||||
ingress {
|
||||
protocol = -1
|
||||
self = true
|
||||
from_port = 0
|
||||
to_port = 0
|
||||
description = "Allow traffic coming from this SG"
|
||||
}
|
||||
egress {
|
||||
from_port = 0
|
||||
protocol = -1
|
||||
to_port = 0
|
||||
self = true
|
||||
description = "Allow traffic going to this SG"
|
||||
}
|
||||
tags = {
|
||||
Name = "${local.resource-prefix}-defaultsg"
|
||||
}
|
||||
}
|
||||
|
||||
# Enable gateway endpoints which are free
|
||||
module "vpc-ep" {
|
||||
count = var.create-free-vpc-endpoints ? 1 : 0
|
||||
source = "../vpc-endpoints"
|
||||
|
||||
gateway-ep-services = ["s3", "dynamodb"]
|
||||
interface-ep-services = []
|
||||
resource-prefix = local.resource-prefix
|
||||
vpc-id = aws_vpc.vpc.id
|
||||
}
|
||||
Reference in New Issue
Block a user