UPD: back ported changes from upstream. vpc-subnet-manual module now supports s3 flow log

This commit is contained in:
xpk 2024-10-22 08:21:45 +08:00
parent 227918fa3b
commit 49e3228776
Signed by: xpk
GPG Key ID: CD4FF6793F09AB86
4 changed files with 195 additions and 162 deletions

View File

@ -1,91 +1,108 @@
<!-- This readme file is generated with terraform-docs -->
# Overview
This module performs the following tasks:
- Create VPC, vpcflow log
- Create subnets in multiple AZ
- Create subnets in every AZ
- Create IGW, NGW
- Create s3 and ddb endpoints which are free
## Requirements
## Subnet addressing
| Name | Version |
|------|---------|
| terraform | >= 1.3.0 |
| aws | >= 5.0 |
Subnet cidrs needs to be specified manually
## Providers
| Name | Version |
|------|---------|
| aws | >= 5.0 |
| random | n/a |
## Modules
| Name | Source | Version |
|------|--------|---------|
| 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_flow_log.vpc-flowlog](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_route.private-routes](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route) | resource |
| [aws_route.public-routes](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route) | resource |
| [aws_route_table.private-route-table](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table) | resource |
| [aws_route_table.public-route-table](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table) | resource |
| [aws_route_table_association.private_route_association](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/route_table_association) | 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
## Inputs:
| Name | Description | Type | Default | Required |
|------|-------------|------|---------|:--------:|
| create-free-vpc-endpoints | Set true to deploy s3 and dynamodb endpoints, which are free | `bool` | `true` | no |
| create-nat-gateway | Set true to deploy NAT gateway | `bool` | `false` | no |
| enable-flow-log | Set true to deploy vpc flowlog | `bool` | `true` | no |
| log-group-class | Log group class for flowlog cloudwatch log group, which can be STANDARD or INFREQUENT\_ACCESS | `string` | `"STANDARD"` | no |
| num\_azs | By default, use 2 AZs for redundancy | `number` | `2` | no |
| private-subnet-cidrs | List of private subnet cidrs | `list(string)` | n/a | yes |
| public-subnet-cidrs | List of public subnet cidrs | `list(string)` | n/a | yes |
| resource-prefix | n/a | `any` | n/a | yes |
| secondary\_cidr\_blocks | Additional cidr blocks | `list(string)` | `[]` | no |
| vpc-cidr | CIDR of VPC to be created | `string` | n/a | yes |
| vpcflowlog-cwl-loggroup-key-arn | CWL log group encryption key arn | `string` | n/a | yes |
| vpcflowlog-retain-days | Days to retain flowlog | `number` | `90` | no |
|---------------------------------|---------------------------------------------------|---------------|---------|----------|
| 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 |
|------|-------------|
| private-route-table-id | n/a |
| private-subnet-ids | n/a |
| private\_subnets | n/a |
| public-route-table-id | n/a |
| public-subnet-ids | n/a |
| public\_subnets | n/a |
| route\_tables\_for\_gateway\_endpoints | n/a |
| secondary\_cidr\_blocks | n/a |
| vpc-cidr | n/a |
| vpc\_id | n/a |
## Outputs:
---
## Authorship
This module was developed by UPDATE_THIS.
| 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
}
```

View File

@ -1,3 +1,9 @@
data "aws_caller_identity" "this" {}
data "aws_availability_zones" "available-az" {
state = "available"
}
data "aws_default_tags" "this" {
lifecycle {
postcondition {
@ -7,36 +13,29 @@ data "aws_default_tags" "this" {
}
}
data "aws_caller_identity" "this" {}
data "aws_availability_zones" "available-az" {
state = "available"
}
locals {
no-az = 2 # hard-coding to 2AZ
vpc-cidr = var.vpc-cidr
enabled-az-names = slice(data.aws_availability_zones.available-az.names, 0, var.num_azs)
}
resource "aws_subnet" "private-subnets" {
count = length(var.private-subnet-cidrs)
vpc_id = aws_vpc.vpc.id
availability_zone = element(local.enabled-az-names, count.index)
availability_zone = element(data.aws_availability_zones.available-az.names, count.index % 2)
cidr_block = var.private-subnet-cidrs[count.index]
tags = {
Name = "${var.resource-prefix}-private-${split("-", element(local.enabled-az-names, count.index))[2]}-${count.index + 1}"
}
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(local.enabled-az-names, count.index)
availability_zone = element(data.aws_availability_zones.available-az.names, count.index % 2)
cidr_block = var.public-subnet-cidrs[count.index]
tags = {
Name = "${var.resource-prefix}-public-${split("-", element(local.enabled-az-names, count.index))[2]}-${count.index + 1}"
}
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" {
@ -133,21 +132,22 @@ resource "aws_route_table_association" "private_route_association" {
/*
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 = -1
protocol = "icmp"
self = true
from_port = 0
to_port = 0
from_port = -1
to_port = -1
description = "Allow traffic coming from this SG"
}
egress {
from_port = 0
protocol = -1
to_port = 0
from_port = -1
protocol = "icmp"
to_port = -1
self = true
description = "Allow traffic going to this SG"
}

View File

@ -1,45 +1,59 @@
variable "resource-prefix" {}
variable "resource-prefix" {
type = string
description = "Prefix of resource"
}
# VPC variables
variable "vpc-cidr" {
type = string
description = "CIDR of VPC to be created"
description = "VPC primary CIDR"
}
variable "private-subnet-cidrs" {
description = "List of private subnet cidrs"
type = list(string)
description = "Private subnet CIDRs"
}
variable "public-subnet-cidrs" {
description = "List of public subnet cidrs"
type = list(string)
description = "Public subnet CIDRs"
default = null
}
variable "create-nat-gateway" {
description = "Set true to deploy 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" {
description = "Set true to deploy vpc flowlog"
type = bool
default = true
}
variable "vpcflowlog-retain-days" {
description = "Days to retain flowlog"
type = number
default = 90
description = "Log retention period for CWlogs"
}
variable "vpcflowlog-cwl-loggroup-key-arn" {
description = "CWL log group encryption key arn"
type = string
description = "KMS key arn for cwlog encryption"
}
variable "create-free-vpc-endpoints" {
description = "Set true to deploy s3 and dynamodb endpoints, which are free"
type = bool
default = true
}
@ -49,15 +63,3 @@ variable "secondary_cidr_blocks" {
description = "Additional cidr blocks"
default = []
}
variable "num_azs" {
description = "By default, use 2 AZs for redundancy"
type = number
default = 2
}
variable "log-group-class" {
description = "Log group class for flowlog cloudwatch log group, which can be STANDARD or INFREQUENT_ACCESS"
type = string
default = "STANDARD"
}

View File

@ -1,6 +1,6 @@
resource "aws_flow_log" "vpc-flowlog" {
count = var.enable-flow-log ? 1 : 0
iam_role_arn = aws_iam_role.vpcflowlog-role.arn
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
@ -9,13 +9,22 @@ resource "aws_flow_log" "vpc-flowlog" {
}
}
resource "aws_cloudwatch_log_group" "vpcflowlog-loggroup" {
count = var.enable-flow-log ? 1 : 0
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"
}
}
name_prefix = "/aws/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
log_group_class = var.log-group-class
}
resource "random_id" "rid" {
@ -23,45 +32,50 @@ resource "random_id" "rid" {
}
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 = <<EOF
{
"Version": "2012-10-17",
"Statement": [
assume_role_policy = jsonencode(
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"Service": "vpc-flow-logs.amazonaws.com"
"Version" : "2012-10-17",
"Statement" : [
{
"Sid" : "",
"Effect" : "Allow",
"Principal" : {
"Service" : "vpc-flow-logs.amazonaws.com"
},
"Action": "sts:AssumeRole"
"Action" : "sts:AssumeRole"
}
]
}
EOF
}
)
}
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.id
role = aws_iam_role.vpcflowlog-role[0].id
policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
policy = jsonencode(
{
"Action": [
"Version" : "2012-10-17",
"Statement" : [
{
"Action" : [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents",
"logs:DescribeLogGroups",
"logs:DescribeLogStreams"
"logs:DescribeLogStreams",
"kms:Encrypt",
"kms:ReEncrypt",
"kms:Decrypt"
],
"Effect": "Allow",
"Resource": "*"
"Effect" : "Allow",
"Resource" : "*"
}
]
}
EOF
}
)
}