/terraform-aws-defaults

Ben's Terraform AWS Defaults Module

Primary LanguageHCLMIT LicenseMIT


Logo

Ben's Terraform AWS Account Defaults Module

This is how I do it.

Explore the docs Β»

Report Bug . Request Feature

GitHub contributors GitHub issues GitHub pull requests GitHub workflow: Terratest GitHub workflow: Linting GitHub tag (with filter) OSSF-Scorecard Score GitHub License

About The Project

Ben's Terraform AWS Account Defaults Module. Configures various defaults and network for your AWS account. Non-optionally sets basic account-wide billing alerts to help avoid run-away costs.

Defaults

  • EC2 Serial Console Access ENABLED by Default
  • EBS Default KMS Key set to the AWS Managed KMS Key
  • EBS Encryption ENABLED by Default
  • ECS EC2 Provisioned Trunking DISABLED by Default
  • ECS Container Insights ENABLED by Default
  • IAM Allow Users to Change their own Password ENABLED
  • IAM Hard Password Expiry DISABLED
  • IAM Max Password Age 90 Days
  • IAM Min Password Length 32
  • IAM Password Reuse Prevention for the last 5 passwords
  • IAM Password Complexity lowercase, uppercase, numbers, symbols all required
  • VPC User-specified network
    • πŸ’ΈπŸš¨Possible configuration costs from NAT Gateways @ $32.85/nat/month. See more in the usage and cost sections below.
    • πŸ’Έ Note potential costs from IPv4 Addresses

Usage

The basic defaults are straight forward with variations on network configuration presenting various options. See the Costs section for the implications of network topology on cost.

module "context" {
  source    = "bendoerr-terraform-modules/context/null"
  version   = "xxx"
  namespace = "btm"
  role      = "production"
  region    = "us-east-1"
  project   = "defaults"
}

module "defaults" {
  source  = "bendoerr-terraform-modules/defaults/aws"
  version = "xxx"
  context = module.context.shared

  budget_monthly_limit = 10.00
  budget_alert_emails  = "alerts@example.com"
  iam_alias_postfix    = "core"

  network = {
    idr           = "10.10.0.0/16"
    enable_nat     = false
    one_nat        = false
    enable_private = false
    subnets = [
      {
        az      = "us-east-1a"
        public  = "10.10.1.0/24"
        private = ""
      },
    ]
  }
}

output "vpc_id" {
  value = module.defaults.vpc_id
}

output "vpc_public_subnet_ids" {
  value = module.defaults.vpc_public_subnet_ids
}

Example Network with Public Subnets Only

infracost

For cost, this is my default network configuration. Each ENI assigned within this subnet will have an associated IPv4 address attached to it as well. At the moment this is the most cost-effective solution as there is no charge for active IPv4 address. 🚨 However, starting in February 2024 active IPv4 addresses will incur a $0.005/hour charge.

network = {
  cidr           = "10.10.0.0/16"
  enable_nat     = false
  one_nat        = false
  enable_private = false
  subnets = [
    {
      az      = "us-east-1a"
      public  = "10.10.1.0/24"
      private = ""
    },
    {
      az      = "us-east-1b"
      public  = "10.10.2.0/24"
      private = ""
    },
    {
      az      = "us-east-1c"
      public  = "10.10.3.0/24"
      private = ""
    },
    {
      az      = "us-east-1d"
      public  = "10.10.4.0/24"
      private = ""
    },
    {
      az      = "us-east-1e"
      public  = "10.10.5.0/24"
      private = ""
    },
    {
      az      = "us-east-1f"
      public  = "10.10.6.0/24"
      private = ""
    },
  ]
}

At a base level this configuration incurs no cost. However, take note of future IPv4 active addresses beginning to cost mention above.

Important Data Transfer Costs to Keep in Mind: While the VPC at rest does not cost, be sure to estimate Data Transfer OUT from AWS to the Internet which is charged at $0.09/GB beyond the first 100GB/per customer for the first 10TB/month. Also note that IPv4 data transferred between Availability Zones within the same region cost $0.01/GB in each direction. IPv6 only incurs this cost if transferred to a different VPC.

Project: With Public Subnets Only
Module path: examples/complete

 Name  Monthly Qty  Unit  Monthly Cost

 OVERALL TOTAL                   $0.00
──────────────────────────────────
27 cloud resources were detected:
βˆ™ 0 were estimated
βˆ™ 25 were free, rerun with --show-skipped to see details
βˆ™ 2 are not supported yet, rerun with --show-skipped to see details

┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┓
┃ Project                                            ┃ Monthly cost ┃
┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━┫
┃ With Public Subnets Only                           ┃ $0.00        ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━┛

Example Network with Public & Private Subnets without NAT

If for some reason you would like private subnets without access to the internet this configuration can achieve that.

network = {
  cidr           = "10.10.0.0/16"
  enable_nat     = false
  one_nat        = false
  enable_private = true
  subnets = [
    {
      az      = "us-east-1a"
      public  = "10.10.1.0/24"
      private = "10.10.16.0/20"
    },
    {
      az      = "us-east-1b"
      public  = "10.10.2.0/24"
      private = "10.10.32.0/20"
    },
    {
      az      = "us-east-1c"
      public  = "10.10.3.0/24"
      private = "10.10.48.0/20"
    },
    {
      az      = "us-east-1d"
      public  = "10.10.4.0/24"
      private = "10.10.64.0/20"
    },
    {
      az      = "us-east-1e"
      public  = "10.10.5.0/24"
      private = "10.10.80.0/20"
    },
    {
      az      = "us-east-1f"
      public  = "10.10.6.0/24"
      private = "10.10.96.0/20"
    },
  ]
}

infracost

At a base level this configuration incurs no cost. However, take note of future IPv4 active addresses beginning to cost mention above.

Important Data Transfer Costs to Keep in Mind: While the VPC at rest does not cost, be sure to estimate Data Transfer OUT from AWS to the Internet which is charged at $0.09/GB beyond the first 100GB/per customer for the first 10TB/month. Also note that IPv4 data transferred between Availability Zones within the same region cost $0.01/GB in each direction. IPv6 only incurs this cost if transferred to a different VPC.

Project: With Public & Private Subnets no/NAT
Module path: examples/complete

 Name  Monthly Qty  Unit  Monthly Cost

 OVERALL TOTAL                   $0.00
──────────────────────────────────
40 cloud resources were detected:
βˆ™ 0 were estimated
βˆ™ 38 were free, rerun with --show-skipped to see details
βˆ™ 2 are not supported yet, rerun with --show-skipped to see details

┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┓
┃ Project                                            ┃ Monthly cost ┃
┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━┫
┃ With Public & Private Subnets no/NAT               ┃ $0.00        ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━┛

Example Network with Public & Private Subnets and a Single NAT

This is a good starter Public/Private network topology which will use a single NAT in the first availability zone for all subnets. If you are spreading your workload across multiple availability zones for fault tolerance note that in this configuration the NAT Gateway becomes a single point of failure for outbound traffic.

network = {
  cidr           = "10.10.0.0/16"
  enable_nat     = true
  one_nat        = true
  enable_private = true
  subnets = [
    {
      az      = "us-east-1a"
      public  = "10.10.1.0/24"
      private = "10.10.16.0/20"
    },
    {
      az      = "us-east-1b"
      public  = "10.10.2.0/24"
      private = "10.10.32.0/20"
    },
    {
      az      = "us-east-1c"
      public  = "10.10.3.0/24"
      private = "10.10.48.0/20"
    },
    {
      az      = "us-east-1d"
      public  = "10.10.4.0/24"
      private = "10.10.64.0/20"
    },
    {
      az      = "us-east-1e"
      public  = "10.10.5.0/24"
      private = "10.10.80.0/20"
    },
    {
      az      = "us-east-1f"
      public  = "10.10.6.0/24"
      private = "10.10.96.0/20"
    },
  ]
}

infracost

🚨Using a NAT Gateway costs about $32.85/month to exist. Additionally, NAT Gateway's charge $0.045/1 GB data processed. There is no charge between the NAT Gateway and resources in the same availability zone, however data transfers between the NAT Gateway and resources in different availability zones do incur standard EC2 data transfer charges.

This cost example assumes 50GB of processed data at the NAT and that 4/5ths of that data is being distributed to other availability zones.

Project: With Public & Private Subnets with one NAT
Module path: examples/complete

 Name                                                            Monthly Qty  Unit   Monthly Cost

 aws_data_transfer.my_region
 └─ Intra-region data transfer                                            80  GB            $0.80

 module.aws_defaults.module.vpc_default.aws_nat_gateway.this[0]
 β”œβ”€ NAT gateway                                                          730  hours        $32.85
 └─ Data processed                                                        50  GB            $2.25

 OVERALL TOTAL                                                                             $35.90
──────────────────────────────────
44 cloud resources were detected:
βˆ™ 2 were estimated, all of which include usage-based costs, see https://infracost.io/usage-file
βˆ™ 40 were free, rerun with --show-skipped to see details
βˆ™ 2 are not supported yet, rerun with --show-skipped to see details

┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┓
┃ Project                                            ┃ Monthly cost ┃
┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━┫
┃ With Public & Private Subnets with one NAT         ┃ $36          ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━┛

Example Network with Public & Private Subnets and a NAT per AZ

This is the more robust Public/Private topology that allows for failed regions to not take down NATing.

network = {
  cidr           = "10.10.0.0/16"
  enable_nat     = true
  one_nat        = false
  enable_private = true
  subnets = [
    {
      az      = "us-east-1a"
      public  = "10.10.1.0/24"
      private = "10.10.16.0/20"
    },
    {
      az      = "us-east-1b"
      public  = "10.10.2.0/24"
      private = "10.10.32.0/20"
    },
    {
      az      = "us-east-1c"
      public  = "10.10.3.0/24"
      private = "10.10.48.0/20"
    },
    {
      az      = "us-east-1d"
      public  = "10.10.4.0/24"
      private = "10.10.64.0/20"
    },
    {
      az      = "us-east-1e"
      public  = "10.10.5.0/24"
      private = "10.10.80.0/20"
    },
    {
      az      = "us-east-1f"
      public  = "10.10.6.0/24"
      private = "10.10.96.0/20"
    },
  ]
}

infracost

🚨Using a NAT Gateway costs about $32.85/month to exist. Additionally, NAT Gateway's charge $0.045/1 GB data processed. There is no charge between the NAT Gateway and resources in the same availability zone, however data transfers between the NAT Gateway and resources in different availability zones do incur standard EC2 data transfer charges.

This cost example assumes 50GB of processed data at the NAT without any need for inter-region data transfer.

Project: With Public & Private Subnets with NAT per AZ
Module path: examples/complete

 Name                                                            Monthly Qty  Unit   Monthly Cost

 module.aws_defaults.module.vpc_default.aws_nat_gateway.this[0]
 β”œβ”€ NAT gateway                                                          730  hours        $32.85
 └─ Data processed                                                        50  GB            $2.25

 module.aws_defaults.module.vpc_default.aws_nat_gateway.this[1]
 β”œβ”€ NAT gateway                                                          730  hours        $32.85
 └─ Data processed                                                        50  GB            $2.25

 module.aws_defaults.module.vpc_default.aws_nat_gateway.this[2]
 β”œβ”€ NAT gateway                                                          730  hours        $32.85
 └─ Data processed                                                        50  GB            $2.25

 module.aws_defaults.module.vpc_default.aws_nat_gateway.this[3]
 β”œβ”€ NAT gateway                                                          730  hours        $32.85
 └─ Data processed                                                        50  GB            $2.25

 module.aws_defaults.module.vpc_default.aws_nat_gateway.this[4]
 β”œβ”€ NAT gateway                                                          730  hours        $32.85
 └─ Data processed                                                        50  GB            $2.25

 module.aws_defaults.module.vpc_default.aws_nat_gateway.this[5]
 β”œβ”€ NAT gateway                                                          730  hours        $32.85
 └─ Data processed                                                        50  GB            $2.25

 OVERALL TOTAL                                                                            $210.60
──────────────────────────────────
63 cloud resources were detected:
βˆ™ 6 were estimated, all of which include usage-based costs, see https://infracost.io/usage-file
βˆ™ 55 were free, rerun with --show-skipped to see details
βˆ™ 2 are not supported yet, rerun with --show-skipped to see details

┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┓
┃ Project                                            ┃ Monthly cost ┃
┣━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━┫
┃ With Public & Private Subnets with NAT per AZ      ┃ $211         ┃
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┻━━━━━━━━━━━━━━┛

Requirements

Name Version
terraform >= 0.13
aws ~> 5.0

Providers

Name Version
aws 5.31.0

Modules

Name Source Version
iam_account terraform-aws-modules/iam/aws//modules/iam-account 5.33.0
label_account_alias bendoerr-terraform-modules/label/null 0.4.1
label_monthly_total bendoerr-terraform-modules/label/null 0.4.1
label_network bendoerr-terraform-modules/label/null 0.4.1
vpc_default terraform-aws-modules/vpc/aws 5.4.0

Resources

Name Type
aws_budgets_budget.monthly_total resource
aws_ebs_default_kms_key.default resource
aws_ebs_encryption_by_default.default resource
aws_ec2_serial_console_access.default resource
aws_ecs_account_setting_default.awsvpc_trunking resource
aws_ecs_account_setting_default.container_insights resource
aws_kms_alias.ebs data source

Inputs

Name Description Type Default Required
budget_alert_emails n/a set(string) n/a yes
budget_monthly_limit n/a string n/a yes
context Shared Context from Ben's terraform-null-context
object({
attributes = list(string)
dns_namespace = string
environment = string
instance = string
instance_short = string
namespace = string
region = string
region_short = string
role = string
role_short = string
project = string
tags = map(string)
})
n/a yes
iam_alias_postfix n/a string n/a yes
network n/a
object({
cidr = string
enable_nat = bool
one_nat = bool
enable_private = bool
subnets = list(object({
az = string
public = string
private = string
}))
})
{
"cidr": "0.0.0.0/0",
"enable_nat": false,
"enable_private": false,
"one_nat": true,
"subnets": [
{
"az": "us-east-1a",
"private": "",
"public": "0.0.0.0/0"
}
]
}
no

Outputs

Name Description
aws_budgets_budget_monthly_total_account n/a
aws_budgets_budget_monthly_total_name n/a
vpc_azs n/a
vpc_id n/a
vpc_private_subnet_ids n/a
vpc_public_subnet_ids n/a

Roadmap

GitHub issues

See the open issues for a list of proposed features (and known issues).

Contributing

GitHub pull requests

Contributions are what make the open source community such an amazing place to be learn, inspire, and create. Any contributions you make are greatly appreciated.

  • If you have suggestions for adding or removing projects, feel free to open an issue to discuss it, or directly create a pull request after you edit the README.md file with necessary changes.
  • Please make sure you check your spelling and grammar.
  • Create individual PR for each suggestion.

Creating A Pull Request

  1. Fork the Project
  2. Create your Feature Branch (git checkout -b feature/AmazingFeature)
  3. Commit your Changes (git commit -m 'Add some AmazingFeature')
  4. Push to the Branch (git push origin feature/AmazingFeature)
  5. Open a Pull Request

License

GitHub License

Distributed under the MIT License. See LICENSE for more information.

Authors

GitHub contributors

  • Benjamin R. Doerr - Terraformer - Benjamin R. Doerr - Built Ben's Terraform Modules

Supported Versions

Only the latest tagged version is supported.

Reporting a Vulnerability

See SECURITY.md.

Acknowledgements