Define EC2 instances, security groups, and VPCs. Use data sources to reference existing infrastructure.
# Create a VPC
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
tags = { Name = "main-vpc" }
}
# Public subnet
resource "aws_subnet" "public" {
vpc_id = aws_vpc.main.id # reference another resource
cidr_block = "10.0.1.0/24"
availability_zone = "us-east-1a"
map_public_ip_on_launch = true
}
# Security group
resource "aws_security_group" "web" {
vpc_id = aws_vpc.main.id
ingress {
from_port = 80
to_port = 80
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"]
}
}data "aws_ami" "amazon_linux" {
most_recent = true
owners = ["amazon"]
filter {
name = "name"
values = ["al2023-ami-*-x86_64"]
}
}
resource "aws_instance" "web" {
ami = data.aws_ami.amazon_linux.id
instance_type = "t3.micro"
subnet_id = aws_subnet.public.id
vpc_security_group_ids = [aws_security_group.web.id]
user_data = <<-EOF
#!/bin/bash
yum install -y nginx
systemctl start nginx
EOF
tags = { Name = "web-server" }
}aws_vpc.main.id create implicit dependencies. Terraform builds a dependency graph and creates resources in the right order. The subnet waits for the VPC. The EC2 waits for the subnet. You don't have to specify the order.resource_type.name.attribute. Terraform infers dependency order.data.aws_ami.amazon_linux.id finds the latest Amazon Linux AMI.user_data runs shell commands when the instance first boots.depends_on for explicit dependencies when the implicit graph isn't enough.