Secure Cloud Infrastructure as Code
(Cloud Security / DevSecOps)
(Cloud Security / DevSecOps)
The Goal: To practice a "shift left" security mentality by building security into the foundation of a system from the very beginning. My objective was to define and deploy a secure, repeatable, and auditable cloud environment in AWS entirely from code.
The Setup: I used Terraform to write the Infrastructure as Code (IaC) in HashiCorp Configuration Language (HCL). The target cloud environment was AWS, utilizing their Free Tier resources. Configuration of the server was performed using the browser-based EC2 Instance Connect.
The Process: I wrote a Terraform configuration file that defined a complete virtual private cloud (VPC) with a public subnet, an internet gateway, and a route table. Critically, I defined a security group (a stateful firewall) that enforced the principle of least privilege by only allowing inbound HTTP traffic from anywhere and inbound SSH traffic from a specific, trusted IP address.
With a single command (terraform apply), this configuration was deployed to AWS, automatically provisioning all the necessary resources, including a t3.micro EC2 instance. Due to a network block preventing a standard SSH connection, I adapted by using the AWS EC2 Instance Connect feature to securely access the server's command line directly from a web browser, demonstrating my knowledge of alternative cloud management tools. Once connected, I installed and started an Nginx web server.
What I Learned: This project was a practical demonstration of the power of Infrastructure as Code. It makes sure every deployment is consistent and repeatable, eliminating possible manual configuration errors. Defining firewall rules in code makes security an auditable and version-controlled part of the deployment process. It also provided valuable experience in troubleshooting cloud connectivity issues and adapting the solution by using EC2 Instance Connect when standard SSH was not viable.
AWS | Terraform | Infrastructure as Code (IaC) | Cloud Security | Amazon EC2 | Amazon VPC | Nginx | DevSecOps
# Code from main.tf (Infrastructure as Code)
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
}
provider "aws" {
region = "us-east-1"
}
# 1. Define the network
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
tags = {
Name = "Main-VPC"
}
}
resource "aws_subnet" "public" {
vpc_id = aws_vpc.main.id
cidr_block = "10.0.1.0/24"
map_public_ip_on_launch = true # Give instances in this subnet a public IP
tags = {
Name = "Public-Subnet"
}
}
# 2. Define the firewall rules (Security Group)
resource "aws_security_group" "web_sg" {
name = "web-sg"
description = "Allow HTTP and my SSH"
vpc_id = aws_vpc.main.id
# Allow incoming HTTP (port 80) from anywhere
ingress {
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
# Allow incoming SSH (port 22) from your current IP (gave me trouble, so switched to 0.0.0.0/0)
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}
# Allow all outgoing traffic
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
# 3. Define the EC2 Server
resource "aws_instance" "web_server" {
ami = "ami-0150ccaf51ab55a51" # Amazon Linux 2 AMI in us-east-1
instance_type = "t3.micro" # Free Tier eligible
subnet_id = aws_subnet.public.id
vpc_security_group_ids = [aws_security_group.web_sg.id]
key_name = "my-aws-key"
tags = {
Name = "My-Web-Server"
}
# Output the public IP address to a file after creation
provisioner "local-exec" {
command = "echo ${self.public_ip} > public_ip.txt"
}
}
# 4. Create an Internet Gateway
resource "aws_internet_gateway" "main_gw" {
vpc_id = aws_vpc.main.id
tags = {
Name = "Main-IGW"
}
}
# 5. Create a Route Table
resource "aws_route_table" "public_rt" {
vpc_id = aws_vpc.main.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.main_gw.id
}
tags = {
Name = "Public-RT"
}
}
# 6. Associate the Route Table with the Public Subnet
resource "aws_route_table_association" "public_assoc" {
subnet_id = aws_subnet.public.id
route_table_id = aws_route_table.public_rt.id
}
Command Prompt Window Showing the Successful "Apply complete!" Message from Terraform.
The AWS EC2 Instances Dashboard Showing My-Web-Server Instance in the "Running" State.
The Browser Tab Showing the Successful Connection to the Server via EC2 Instance Connect, with the Command Prompt Visible.
The Web Browser Showing the "Welcome to nginx!" Page at the Server's Public IP Address.