terraform {
required_version = ">= 1.0"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
backend "s3" {
bucket = "my-terraform-state"
key = "prod/terraform.tfstate"
region = "us-east-1"
}
}
provider "aws" {
region = var.aws_region
}
# VPC
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
enable_dns_hostnames = true
enable_dns_support = true
tags = {
Name = "${var.project_name}-vpc"
Environment = var.environment
}
}
# Subnets
resource "aws_subnet" "public" {
count = 2
vpc_id = aws_vpc.main.id
cidr_block = "10.0.${count.index}.0/24"
availability_zone = data.aws_availability_zones.available.names[count.index]
map_public_ip_on_launch = true
tags = {
Name = "${var.project_name}-public-${count.index + 1}"
}
}
# Internet Gateway
resource "aws_internet_gateway" "main" {
vpc_id = aws_vpc.main.id
tags = {
Name = "${var.project_name}-igw"
}
}
# EC2 Instance
resource "aws_instance" "app" {
ami = var.ami_id
instance_type = var.instance_type
subnet_id = aws_subnet.public[0].id
vpc_security_group_ids = [aws_security_group.app.id]
user_data = file("${path.module}/user-data.sh")
tags = {
Name = "${var.project_name}-app"
Environment = var.environment
}
}
# Security Group
resource "aws_security_group" "app" {
name = "${var.project_name}-app-sg"
description = "Security group for application"
vpc_id = aws_vpc.main.id
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
ingress {
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = {
Name = "${var.project_name}-app-sg"
}
}
# RDS Database
resource "aws_db_instance" "postgres" {
identifier = "${var.project_name}-db"
engine = "postgres"
engine_version = "15.3"
instance_class = "db.t3.micro"
allocated_storage = 20
db_name = var.db_name
username = var.db_username
password = var.db_password
vpc_security_group_ids = [aws_security_group.db.id]
db_subnet_group_name = aws_db_subnet_group.main.name
skip_final_snapshot = true
tags = {
Name = "${var.project_name}-db"
}
}
# S3 Bucket
resource "aws_s3_bucket" "storage" {
bucket = "${var.project_name}-storage"
tags = {
Name = "${var.project_name}-storage"
Environment = var.environment
}
}
resource "aws_s3_bucket_public_access_block" "storage" {
bucket = aws_s3_bucket.storage.id
block_public_acls = true
block_public_policy = true
ignore_public_acls = true
restrict_public_buckets = true
}
variable "aws_region" {
description = "AWS region"
type = string
default = "us-east-1"
}
variable "project_name" {
description = "Project name"
type = string
}
variable "environment" {
description = "Environment (dev, staging, prod)"
type = string
}
variable "instance_type" {
description = "EC2 instance type"
type = string
default = "t2.micro"
}
variable "ami_id" {
description = "AMI ID"
type = string
}
variable "db_name" {
description = "Database name"
type = string
}
variable "db_username" {
description = "Database username"
type = string
sensitive = true
}
variable "db_password" {
description = "Database password"
type = string
sensitive = true
}
output "instance_public_ip" {
description = "Public IP of EC2 instance"
value = aws_instance.app.public_ip
}
output "database_endpoint" {
description = "Database endpoint"
value = aws_db_instance.postgres.endpoint
}
output "s3_bucket_name" {
description = "S3 bucket name"
value = aws_s3_bucket.storage.id
}
project_name = "myapp"
environment = "production"
aws_region = "us-east-1"
instance_type = "t2.micro"
ami_id = "ami-0c55b159cbfafe1f0"
db_name = "myappdb"
db_username = "admin"
# db_password should be set via environment variable: TF_VAR_db_password
# Initialize Terraform
terraform init
# Format code
terraform fmt
# Validate configuration
terraform validate
# Plan changes
terraform plan
# Apply changes
terraform apply
# Destroy infrastructure
terraform destroy
# Show current state
terraform show
# List resources
terraform state list
# Import existing resource
terraform import aws_instance.app i-1234567890abcdef0