Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 71 additions & 0 deletions aws-ec2-security-groups/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# AWS EC2 Security Groups Explained 🔐

**Understand how AWS controls inbound and outbound traffic to your EC2 instances.**
Visual, practical, and DevOps-ready.

---

## 🧠 Key Concepts

- Security Groups act as **instance-level firewalls**
- Network ACLs act at the **subnet level**
- SGs are **stateful**, NACLs are **stateless**
- Traffic rules control **inbound** (incoming) and **outbound** (outgoing) flows

---

## 📊 Inbound vs Outbound Rules

| Direction | Example | Purpose |
|------------|----------|----------|
| **Inbound** | Allow SSH (port 22) from your IP | Admin access |
| **Outbound** | Allow all | Internet updates |

---

## ⚙️ Best Practices

✅ Use least-privilege rules
✅ Avoid `0.0.0.0/0` where not required
✅ Group SGs by role (web, db, bastion)
✅ Review regularly

---

## 📈 Diagram

## 📊 1. Inbound & Outbound Traffic Flow
![Inbound & Outbound Traffic Flow](./images/AWS%20EC2%20Security%20Groups%20-%20AWS%20EC2%20Security%20Group%20Inbound%20%26%20Outbound%20Traffic%20Flow%20-%20the%20devops%20tooling.png)
> **Diagram 1:** Visualizing how inbound and outbound rules are applied in AWS Security Groups.
> Source: [TheDevOpsTooling.com](https://thedevopstooling.com/aws-ec2-security-groups-explained/)

---

## 🧱 2. Security Groups vs Network ACLs
![Security Groups vs NACLs](./images/AWS%20EC2%20Security%20Groups%20-%20AWS%20Security%20Groups%20vs%20NACLs%20Instance%20vs%20Subnet%20Level%20-%20the%20devops%20tooling.png)
> **Diagram 2:** Instance-level (SG) vs Subnet-level (NACL) filtering.

---

## 🧩 3. Security Group Traffic Evaluation
![Traffic Evaluation](./images/AWS%20EC2%20Security%20Groups%20-%20Security%20Group%20Traffic%20Evaluation%20-%20the%20devops%20tooling.png)
> **Diagram 3:** Rule evaluation flow for AWS Security Groups.

---

## 🏗️ 4. Three-Tier Architecture Example
![Layered Security Architecture](./images/AWS%20EC2%20Security%20Groups%20-%20Three-Tier%20AWS%20Architecture%20Security%20Groups%20as%20Layered%20Shields%20-%20the%20devops%20tooling.png)
> **Diagram 4:** Web, App, and DB layer Security Groups in a three-tier AWS design.

---

## 🔗 Reference

Full post: [AWS EC2 Security Groups Explained](https://thedevopstooling.com/aws-ec2-security-groups-explained/)
More guides at [TheDevOpsTooling.com](https://thedevopstooling.com)

---

### ✍️ Author
**Srikanth Chowdari** — Senior DevOps Engineer
Follow for more AWS & DevOps tutorials: [@thedevopstooling](https://github.com/thedevopstooling)
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
32 changes: 32 additions & 0 deletions aws-ec2-security-groups/terraform/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Terraform: AWS EC2 Security Groups (three-tier example)

This folder contains Terraform code to create security groups for a three-tier architecture:
- web-tier (public HTTP/HTTPS + SSH from bastion)
- app-tier (app port only from web-tier + SSH from bastion)
- database-tier (PostgreSQL only from app-tier; limited egress to S3 prefix list)
- bastion (SSH access from office CIDR)

## Usage

1. Create a `terraform.tfvars` with values for required variables:
```hcl
vpc_id = "vpc-0123456789abcdef"
office_cidr = "203.0.113.0/24"
private_subnet_cidr = "10.0.1.0/24"
s3_prefix_list_id = "pl-0abcd1234"
environment = "prod"
region = "us-east-1"

## Initialize & apply:

cd aws-ec2-security-groups/terraform
terraform init
terraform plan -out=tfplan
terraform apply tfplan

# Destroy (when needed):

terraform destroy


See theDevOpsTooling article: https://thedevopstooling.com/aws-ec2-security-groups-explained/
161 changes: 161 additions & 0 deletions aws-ec2-security-groups/terraform/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
}
required_version = ">= 1.4.0"
}

provider "aws" {
region = var.region
}

#
# Web Tier Security Group
#
resource "aws_security_group" "web_tier" {
name = "web-tier-sg"
description = "Security group for web tier - allows public HTTP/HTTPS"
vpc_id = var.vpc_id

ingress {
description = "HTTP from public internet"
from_port = 80
to_port = 80
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}

ingress {
description = "HTTPS from public internet"
from_port = 443
to_port = 443
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
}

ingress {
description = "SSH from bastion host"
from_port = 22
to_port = 22
protocol = "tcp"
security_groups = [aws_security_group.bastion.id]
}

egress {
description = "Allow all outbound"
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}

tags = {
Name = "web-tier-sg"
Environment = var.environment
ManagedBy = "Terraform"
}
}

#
# Application Tier Security Group
#
resource "aws_security_group" "app_tier" {
name = "app-tier-sg"
description = "Security group for application tier - only accessible from web tier"
vpc_id = var.vpc_id

ingress {
description = "Application port from web tier"
from_port = 8080
to_port = 8080
protocol = "tcp"
security_groups = [aws_security_group.web_tier.id]
}

ingress {
description = "SSH from bastion host"
from_port = 22
to_port = 22
protocol = "tcp"
security_groups = [aws_security_group.bastion.id]
}

egress {
description = "Allow all outbound"
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}

tags = {
Name = "app-tier-sg"
Environment = var.environment
ManagedBy = "Terraform"
}
}

#
# Database Tier Security Group
#
resource "aws_security_group" "database" {
name = "database-sg"
description = "Security group for database tier - only accessible from app tier"
vpc_id = var.vpc_id

ingress {
description = "PostgreSQL from application tier"
from_port = 5432
to_port = 5432
protocol = "tcp"
security_groups = [aws_security_group.app_tier.id]
}

egress {
description = "Allow HTTPS to S3 VPC endpoint for backups"
from_port = 443
to_port = 443
protocol = "tcp"
prefix_list_ids = [var.s3_prefix_list_id]
}

tags = {
Name = "database-sg"
Environment = var.environment
ManagedBy = "Terraform"
}
}

#
# Bastion Host Security Group
#
resource "aws_security_group" "bastion" {
name = "bastion-sg"
description = "Security group for bastion host - restricted SSH access"
vpc_id = var.vpc_id

ingress {
description = "SSH from office network"
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = [var.office_cidr]
}

egress {
description = "SSH to private subnets"
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = [var.private_subnet_cidr]
}

tags = {
Name = "bastion-sg"
Environment = var.environment
ManagedBy = "Terraform"
}
}
32 changes: 32 additions & 0 deletions aws-ec2-security-groups/terraform/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
variable "region" {
description = "AWS region"
type = string
default = "us-east-1"
}

variable "vpc_id" {
description = "VPC ID where Security Groups will be created"
type = string
}

variable "environment" {
description = "Environment name (dev, staging, prod)"
type = string
default = "dev"
}

variable "office_cidr" {
description = "CIDR block for office network"
type = string
}

variable "private_subnet_cidr" {
description = "CIDR block for private subnets"
type = string
}

variable "s3_prefix_list_id" {
description = "Prefix list ID for S3 VPC endpoint (for egress)"
type = string
default = null
}