mirror of
https://github.com/lukaszraczylo/hello-world-tf.git
synced 2026-10-11 04:26:54 +00:00
Initial commit
This commit is contained in:
+26
@@ -0,0 +1,26 @@
|
||||
# Terraform
|
||||
.terraform/
|
||||
*.tfstate
|
||||
*.tfstate.*
|
||||
*.tfplan
|
||||
crash.log
|
||||
crash.*.log
|
||||
|
||||
# Variable files may contain secrets; commit only examples
|
||||
*.tfvars
|
||||
*.tfvars.json
|
||||
!*.tfvars.example
|
||||
|
||||
# Local overrides
|
||||
override.tf
|
||||
override.tf.json
|
||||
*_override.tf
|
||||
*_override.tf.json
|
||||
.terraformrc
|
||||
terraform.rc
|
||||
|
||||
# Superseded RTF originals
|
||||
*.rtf
|
||||
|
||||
# macOS
|
||||
.DS_Store
|
||||
Generated
+45
@@ -0,0 +1,45 @@
|
||||
# This file is maintained automatically by "terraform init".
|
||||
# Manual edits may be lost in future updates.
|
||||
|
||||
provider "registry.terraform.io/hashicorp/aws" {
|
||||
version = "5.100.0"
|
||||
constraints = "~> 5.0"
|
||||
hashes = [
|
||||
"h1:Ijt7pOlB7Tr7maGQIqtsLFbl7pSMIj06TVdkoSBcYOw=",
|
||||
"zh:054b8dd49f0549c9a7cc27d159e45327b7b65cf404da5e5a20da154b90b8a644",
|
||||
"zh:0b97bf8d5e03d15d83cc40b0530a1f84b459354939ba6f135a0086c20ebbe6b2",
|
||||
"zh:1589a2266af699cbd5d80737a0fe02e54ec9cf2ca54e7e00ac51c7359056f274",
|
||||
"zh:6330766f1d85f01ae6ea90d1b214b8b74cc8c1badc4696b165b36ddd4cc15f7b",
|
||||
"zh:7c8c2e30d8e55291b86fcb64bdf6c25489d538688545eb48fd74ad622e5d3862",
|
||||
"zh:99b1003bd9bd32ee323544da897148f46a527f622dc3971af63ea3e251596342",
|
||||
"zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425",
|
||||
"zh:9f8b909d3ec50ade83c8062290378b1ec553edef6a447c56dadc01a99f4eaa93",
|
||||
"zh:aaef921ff9aabaf8b1869a86d692ebd24fbd4e12c21205034bb679b9caf883a2",
|
||||
"zh:ac882313207aba00dd5a76dbd572a0ddc818bb9cbf5c9d61b28fe30efaec951e",
|
||||
"zh:bb64e8aff37becab373a1a0cc1080990785304141af42ed6aa3dd4913b000421",
|
||||
"zh:dfe495f6621df5540d9c92ad40b8067376350b005c637ea6efac5dc15028add4",
|
||||
"zh:f0ddf0eaf052766cfe09dea8200a946519f653c384ab4336e2a4a64fdd6310e9",
|
||||
"zh:f1b7e684f4c7ae1eed272b6de7d2049bb87a0275cb04dbb7cda6636f600699c9",
|
||||
"zh:ff461571e3f233699bf690db319dfe46aec75e58726636a0d97dd9ac6e32fb70",
|
||||
]
|
||||
}
|
||||
|
||||
provider "registry.terraform.io/hashicorp/random" {
|
||||
version = "3.9.0"
|
||||
hashes = [
|
||||
"h1:OO+IuvQJSPmWdN8AyyIEvPJbLvDQpgX/zbktoa9KsJE=",
|
||||
"zh:161ad0bd9a75768c82f53fb6e7172a9d8be2d4889b012645a34795031aaf1bf1",
|
||||
"zh:19dc9a5b17729725ccfc4f45b0500af0ee5bc6b6b160c7adb8f2bf617d2c80ea",
|
||||
"zh:269eda8fe42daa7974d5a34d166c3ba9defe80cde86c01e4dadcfdf2e1f05e5f",
|
||||
"zh:373f7c65566f8f2cc7f45d698654feb9d988996957e1266a69ca00c52d6d16d0",
|
||||
"zh:5599d16804c41c83009ec621b6d6b6f74e102f5827678a4750f8809055546b61",
|
||||
"zh:583be0440469a22bff70dcfa56593b01566860b29607437264adb51060cf46fc",
|
||||
"zh:5f211d8ec3f2e1f414870d9584bfe26e6995560ef81c748f8447a48164767398",
|
||||
"zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3",
|
||||
"zh:7b547fd16216761ef86efc3ed516ac5ac0c5c42b7c7eb24a08cef2d93f69ed5e",
|
||||
"zh:7e7c0679daf2a382151d05068c8c3f0dae6b7b7dccf818827b73dd08638df2ef",
|
||||
"zh:8089dec888a8038b9b4fb23b3df7e1057293dbc5b60b42cc47ff690d69d4b61b",
|
||||
"zh:c51f15a031edfd6f23ce8ced3446ca7f8d8d647e2499890d7d5d10d5016d7257",
|
||||
"zh:c94784f005708890dc6895afd53636ec00ec1e430b15d41e5aebfb1d4b39bd04",
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
# hello-world-tf
|
||||
|
||||
Minimal AWS network and storage baseline managed with Terraform. Creates a VPC with public and private subnets, an internet gateway, an optional NAT gateway, and a private S3 bucket. No compute resources.
|
||||
|
||||
## What it creates
|
||||
|
||||
- **VPC** — `10.0.0.0/16` by default, DNS support and hostnames enabled
|
||||
- **2 public subnets** (`10.0.1.0/24`, `10.0.2.0/24`) — auto-assign public IPs, routed to the internet gateway
|
||||
- **2 private subnets** (`10.0.10.0/24`, `10.0.20.0/24`) — own route table, no internet egress unless the NAT gateway is enabled
|
||||
- **Internet gateway** + public route table
|
||||
- **NAT gateway** (optional, off by default) — single NAT in the first public subnet with an Elastic IP; adds a default route for the private subnets
|
||||
- **S3 bucket** — `<project>-<env>-app-data-<random-suffix>`, versioning on by default, all public access blocked
|
||||
|
||||
All resources are tagged with `Project`, `Environment`, `ManagedBy`, and `CreatedBy` via provider `default_tags`, plus anything passed in `additional_tags`.
|
||||
|
||||
## Requirements
|
||||
|
||||
| Name | Version |
|
||||
|------|---------|
|
||||
| Terraform | >= 1.6.0 |
|
||||
| AWS provider | ~> 5.0 |
|
||||
| Random provider | ~> 3.6 |
|
||||
|
||||
AWS credentials must be available in the environment (profile, SSO, or environment variables).
|
||||
|
||||
## Usage
|
||||
|
||||
```sh
|
||||
terraform init
|
||||
terraform plan
|
||||
terraform apply
|
||||
```
|
||||
|
||||
State is local. Configure a remote backend before using this beyond experiments.
|
||||
|
||||
## Inputs
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
|------|------|---------|-------------|
|
||||
| `project_name` | string | `aether-test` | Resource name prefix; lowercase letters, numbers, hyphens only |
|
||||
| `environment` | string | `dev` | One of `dev`, `staging`, `prod` |
|
||||
| `aws_region` | string | `eu-west-2` | AWS region |
|
||||
| `vpc_cidr` | string | `10.0.0.0/16` | VPC CIDR block |
|
||||
| `public_subnet_cidrs` | list(string) | `["10.0.1.0/24", "10.0.2.0/24"]` | Public subnet CIDRs |
|
||||
| `private_subnet_cidrs` | list(string) | `["10.0.10.0/24", "10.0.20.0/24"]` | Private subnet CIDRs |
|
||||
| `enable_s3_versioning` | bool | `true` | Toggle S3 bucket versioning |
|
||||
| `create_nat_gateway` | bool | `false` | Create NAT gateway for private subnet egress |
|
||||
| `additional_tags` | map(string) | `{}` | Extra tags merged into all resources |
|
||||
|
||||
## Outputs
|
||||
|
||||
VPC ID and CIDR, subnet IDs and CIDRs, internet gateway ID, public and private route table IDs, NAT gateway ID (null when disabled), S3 bucket name/ARN/region, AWS account ID and region, and a `resource_summary` object.
|
||||
|
||||
## Cost notes
|
||||
|
||||
Everything here is free or near-free except the NAT gateway: enabling `create_nat_gateway` costs roughly $0.05/hour plus data processing charges in eu-west-2. The single-NAT layout is a deliberate simplification for dev use; production would run one NAT per availability zone.
|
||||
@@ -0,0 +1,217 @@
|
||||
########################################
|
||||
# Terraform Configuration
|
||||
########################################
|
||||
terraform {
|
||||
required_version = ">= 1.6.0"
|
||||
|
||||
required_providers {
|
||||
aws = {
|
||||
source = "hashicorp/aws"
|
||||
version = "~> 5.0"
|
||||
}
|
||||
random = {
|
||||
source = "hashicorp/random"
|
||||
version = "~> 3.6"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
########################################
|
||||
# Provider Configuration
|
||||
########################################
|
||||
provider "aws" {
|
||||
region = var.aws_region
|
||||
|
||||
default_tags {
|
||||
tags = merge(
|
||||
{
|
||||
Project = var.project_name
|
||||
Environment = var.environment
|
||||
ManagedBy = "Terraform"
|
||||
CreatedBy = "Aether"
|
||||
},
|
||||
var.additional_tags
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
########################################
|
||||
# VPC
|
||||
########################################
|
||||
resource "aws_vpc" "main" {
|
||||
cidr_block = var.vpc_cidr
|
||||
enable_dns_support = true
|
||||
enable_dns_hostnames = true
|
||||
|
||||
tags = {
|
||||
Name = "${var.project_name}-${var.environment}-vpc"
|
||||
}
|
||||
}
|
||||
|
||||
########################################
|
||||
# Public Subnets
|
||||
########################################
|
||||
resource "aws_subnet" "public" {
|
||||
count = length(var.public_subnet_cidrs)
|
||||
|
||||
vpc_id = aws_vpc.main.id
|
||||
cidr_block = var.public_subnet_cidrs[count.index]
|
||||
availability_zone = data.aws_availability_zones.available.names[count.index]
|
||||
map_public_ip_on_launch = true
|
||||
|
||||
tags = {
|
||||
Name = "${var.project_name}-${var.environment}-public-subnet-${count.index + 1}"
|
||||
Type = "public"
|
||||
}
|
||||
}
|
||||
|
||||
########################################
|
||||
# Private Subnets
|
||||
########################################
|
||||
resource "aws_subnet" "private" {
|
||||
count = length(var.private_subnet_cidrs)
|
||||
|
||||
vpc_id = aws_vpc.main.id
|
||||
cidr_block = var.private_subnet_cidrs[count.index]
|
||||
availability_zone = data.aws_availability_zones.available.names[count.index]
|
||||
|
||||
tags = {
|
||||
Name = "${var.project_name}-${var.environment}-private-subnet-${count.index + 1}"
|
||||
Type = "private"
|
||||
}
|
||||
}
|
||||
|
||||
########################################
|
||||
# Internet Gateway
|
||||
########################################
|
||||
resource "aws_internet_gateway" "main" {
|
||||
vpc_id = aws_vpc.main.id
|
||||
|
||||
tags = {
|
||||
Name = "${var.project_name}-${var.environment}-igw"
|
||||
}
|
||||
}
|
||||
|
||||
########################################
|
||||
# Public Route Table
|
||||
########################################
|
||||
resource "aws_route_table" "public" {
|
||||
vpc_id = aws_vpc.main.id
|
||||
|
||||
route {
|
||||
cidr_block = "0.0.0.0/0"
|
||||
gateway_id = aws_internet_gateway.main.id
|
||||
}
|
||||
|
||||
tags = {
|
||||
Name = "${var.project_name}-${var.environment}-public-rt"
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_route_table_association" "public" {
|
||||
count = length(aws_subnet.public)
|
||||
|
||||
subnet_id = aws_subnet.public[count.index].id
|
||||
route_table_id = aws_route_table.public.id
|
||||
}
|
||||
|
||||
########################################
|
||||
# NAT Gateway (optional)
|
||||
########################################
|
||||
resource "aws_eip" "nat" {
|
||||
count = var.create_nat_gateway ? 1 : 0
|
||||
|
||||
domain = "vpc"
|
||||
|
||||
tags = {
|
||||
Name = "${var.project_name}-${var.environment}-nat-eip"
|
||||
}
|
||||
|
||||
depends_on = [aws_internet_gateway.main]
|
||||
}
|
||||
|
||||
resource "aws_nat_gateway" "main" {
|
||||
count = var.create_nat_gateway ? 1 : 0
|
||||
|
||||
allocation_id = aws_eip.nat[0].id
|
||||
subnet_id = aws_subnet.public[0].id
|
||||
|
||||
tags = {
|
||||
Name = "${var.project_name}-${var.environment}-nat"
|
||||
}
|
||||
|
||||
depends_on = [aws_internet_gateway.main]
|
||||
}
|
||||
|
||||
########################################
|
||||
# Private Route Table
|
||||
########################################
|
||||
resource "aws_route_table" "private" {
|
||||
vpc_id = aws_vpc.main.id
|
||||
|
||||
tags = {
|
||||
Name = "${var.project_name}-${var.environment}-private-rt"
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_route" "private_nat" {
|
||||
count = var.create_nat_gateway ? 1 : 0
|
||||
|
||||
route_table_id = aws_route_table.private.id
|
||||
destination_cidr_block = "0.0.0.0/0"
|
||||
nat_gateway_id = aws_nat_gateway.main[0].id
|
||||
}
|
||||
|
||||
resource "aws_route_table_association" "private" {
|
||||
count = length(aws_subnet.private)
|
||||
|
||||
subnet_id = aws_subnet.private[count.index].id
|
||||
route_table_id = aws_route_table.private.id
|
||||
}
|
||||
|
||||
########################################
|
||||
# S3 Bucket for Application Data
|
||||
########################################
|
||||
resource "aws_s3_bucket" "app_data" {
|
||||
bucket = "${var.project_name}-${var.environment}-app-data-${random_id.bucket_suffix.hex}"
|
||||
|
||||
tags = {
|
||||
Name = "${var.project_name}-${var.environment}-app-data"
|
||||
Description = "Application data storage"
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_s3_bucket_versioning" "app_data" {
|
||||
bucket = aws_s3_bucket.app_data.id
|
||||
|
||||
versioning_configuration {
|
||||
status = var.enable_s3_versioning ? "Enabled" : "Disabled"
|
||||
}
|
||||
}
|
||||
|
||||
resource "aws_s3_bucket_public_access_block" "app_data" {
|
||||
bucket = aws_s3_bucket.app_data.id
|
||||
|
||||
block_public_acls = true
|
||||
block_public_policy = true
|
||||
ignore_public_acls = true
|
||||
restrict_public_buckets = true
|
||||
}
|
||||
|
||||
########################################
|
||||
# Random ID for unique bucket naming
|
||||
########################################
|
||||
resource "random_id" "bucket_suffix" {
|
||||
byte_length = 4
|
||||
}
|
||||
|
||||
########################################
|
||||
# Data Sources
|
||||
########################################
|
||||
data "aws_availability_zones" "available" {
|
||||
state = "available"
|
||||
}
|
||||
|
||||
data "aws_caller_identity" "current" {}
|
||||
|
||||
data "aws_region" "current" {}
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
########################################
|
||||
# VPC Outputs
|
||||
########################################
|
||||
output "vpc_id" {
|
||||
description = "ID of the VPC"
|
||||
value = aws_vpc.main.id
|
||||
}
|
||||
|
||||
output "vpc_cidr" {
|
||||
description = "CIDR block of the VPC"
|
||||
value = aws_vpc.main.cidr_block
|
||||
}
|
||||
|
||||
########################################
|
||||
# Subnet Outputs
|
||||
########################################
|
||||
output "public_subnet_ids" {
|
||||
description = "IDs of public subnets"
|
||||
value = aws_subnet.public[*].id
|
||||
}
|
||||
|
||||
output "private_subnet_ids" {
|
||||
description = "IDs of private subnets"
|
||||
value = aws_subnet.private[*].id
|
||||
}
|
||||
|
||||
output "public_subnet_cidrs" {
|
||||
description = "CIDR blocks of public subnets"
|
||||
value = aws_subnet.public[*].cidr_block
|
||||
}
|
||||
|
||||
output "private_subnet_cidrs" {
|
||||
description = "CIDR blocks of private subnets"
|
||||
value = aws_subnet.private[*].cidr_block
|
||||
}
|
||||
|
||||
########################################
|
||||
# Networking Outputs
|
||||
########################################
|
||||
output "internet_gateway_id" {
|
||||
description = "ID of the Internet Gateway"
|
||||
value = aws_internet_gateway.main.id
|
||||
}
|
||||
|
||||
output "public_route_table_id" {
|
||||
description = "ID of the public route table"
|
||||
value = aws_route_table.public.id
|
||||
}
|
||||
|
||||
output "private_route_table_id" {
|
||||
description = "ID of the private route table"
|
||||
value = aws_route_table.private.id
|
||||
}
|
||||
|
||||
output "nat_gateway_id" {
|
||||
description = "ID of the NAT Gateway (null if not created)"
|
||||
value = var.create_nat_gateway ? aws_nat_gateway.main[0].id : null
|
||||
}
|
||||
|
||||
########################################
|
||||
# S3 Outputs
|
||||
########################################
|
||||
output "s3_bucket_name" {
|
||||
description = "Name of the S3 bucket"
|
||||
value = aws_s3_bucket.app_data.id
|
||||
}
|
||||
|
||||
output "s3_bucket_arn" {
|
||||
description = "ARN of the S3 bucket"
|
||||
value = aws_s3_bucket.app_data.arn
|
||||
}
|
||||
|
||||
output "s3_bucket_region" {
|
||||
description = "Region of the S3 bucket"
|
||||
value = aws_s3_bucket.app_data.region
|
||||
}
|
||||
|
||||
########################################
|
||||
# AWS Account Information
|
||||
########################################
|
||||
output "aws_account_id" {
|
||||
description = "AWS Account ID"
|
||||
value = data.aws_caller_identity.current.account_id
|
||||
}
|
||||
|
||||
output "aws_region" {
|
||||
description = "AWS Region"
|
||||
value = data.aws_region.current.name
|
||||
}
|
||||
|
||||
########################################
|
||||
# Resource Summary
|
||||
########################################
|
||||
output "resource_summary" {
|
||||
description = "Summary of created resources"
|
||||
value = {
|
||||
vpc_created = true
|
||||
public_subnets_count = length(aws_subnet.public)
|
||||
private_subnets_count = length(aws_subnet.private)
|
||||
s3_bucket_created = true
|
||||
s3_versioning_enabled = var.enable_s3_versioning
|
||||
internet_gateway_created = true
|
||||
nat_gateway_created = var.create_nat_gateway
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
########################################
|
||||
# Project Configuration
|
||||
########################################
|
||||
variable "project_name" {
|
||||
type = string
|
||||
description = "Name of the project (used for resource naming)"
|
||||
default = "aether-test"
|
||||
|
||||
validation {
|
||||
condition = can(regex("^[a-z0-9-]+$", var.project_name))
|
||||
error_message = "Project name must contain only lowercase letters, numbers, and hyphens."
|
||||
}
|
||||
}
|
||||
|
||||
variable "environment" {
|
||||
type = string
|
||||
description = "Environment name (dev, staging, prod)"
|
||||
default = "dev"
|
||||
|
||||
validation {
|
||||
condition = contains(["dev", "staging", "prod"], var.environment)
|
||||
error_message = "Environment must be dev, staging, or prod."
|
||||
}
|
||||
}
|
||||
|
||||
########################################
|
||||
# AWS Configuration
|
||||
########################################
|
||||
variable "aws_region" {
|
||||
type = string
|
||||
description = "AWS region for resources"
|
||||
default = "eu-west-2"
|
||||
}
|
||||
|
||||
########################################
|
||||
# Network Configuration
|
||||
########################################
|
||||
variable "vpc_cidr" {
|
||||
type = string
|
||||
description = "CIDR block for the VPC"
|
||||
default = "10.0.0.0/16"
|
||||
|
||||
validation {
|
||||
condition = can(cidrhost(var.vpc_cidr, 0))
|
||||
error_message = "Must be a valid IPv4 CIDR block."
|
||||
}
|
||||
}
|
||||
|
||||
variable "public_subnet_cidrs" {
|
||||
type = list(string)
|
||||
description = "CIDR blocks for public subnets"
|
||||
default = ["10.0.1.0/24", "10.0.2.0/24"]
|
||||
}
|
||||
|
||||
variable "private_subnet_cidrs" {
|
||||
type = list(string)
|
||||
description = "CIDR blocks for private subnets"
|
||||
default = ["10.0.10.0/24", "10.0.20.0/24"]
|
||||
}
|
||||
|
||||
########################################
|
||||
# Feature Flags
|
||||
########################################
|
||||
variable "enable_s3_versioning" {
|
||||
type = bool
|
||||
description = "Enable versioning for S3 buckets"
|
||||
default = true
|
||||
}
|
||||
|
||||
variable "create_nat_gateway" {
|
||||
type = bool
|
||||
description = "Create NAT Gateway for private subnet internet access"
|
||||
default = false
|
||||
}
|
||||
|
||||
########################################
|
||||
# Tags
|
||||
########################################
|
||||
variable "additional_tags" {
|
||||
type = map(string)
|
||||
description = "Additional tags to apply to all resources"
|
||||
default = {}
|
||||
}
|
||||
Reference in New Issue
Block a user