Topic 2.2
Security Groups, Key Pairs & Session Manager
In one line
Security groups are stateful, allow-only firewalls attached to each instance; SSH key pairs are the traditional way in, and Systems Manager Session Manager is the modern way that needs no open port and no keys at all.
Think of it like this
A building's reception desk that only has a list of who may come IN. Once a visitor is let in, they can always walk back out the same way without being checked again — that's a STATEFUL firewall. A security group only lists what's allowed; anything not listed is refused.
Key ideas
- 01
A SECURITY GROUP (SG) is attached to an instance's network interface. Rules are ALLOW-only (no deny rules), and it's STATEFUL: if inbound traffic is allowed, the response is automatically allowed out, and vice versa. By default a new SG allows all outbound and no inbound.
- 02
The most powerful SG feature is referencing ANOTHER SECURITY GROUP as the source instead of an IP range: 'allow port 5432 from sg-app' means 'from any instance in the app tier', however many there are and whatever IPs they get. This is how you build tiers without tracking IP addresses.
- 03
NETWORK ACLs (Phase 3) are the other firewall layer — stateless, per-subnet, with allow AND deny rules. In practice most teams do nearly everything with security groups and leave NACLs at their defaults.
- 04
SSH with KEY PAIRS works, but requires port 22 open (ideally only from a bastion or VPN), distributing private keys to people, and removing them when people leave. Leaked keys and
0.0.0.0/0on port 22 are among the most common findings in any AWS security review. - 05
SESSION MANAGER (part of Systems Manager) gives you a shell through the SSM agent, which makes OUTBOUND calls to AWS — so NO inbound port needs to be open, no keys exist, access is controlled by IAM, and every session can be logged to S3/CloudWatch. For new setups it should be the default way to get onto an instance.
Code & diagrams
# Load balancer: public HTTPS in
aws ec2 authorize-security-group-ingress --group-id sg-alb \
--protocol tcp --port 443 --cidr 0.0.0.0/0
# App servers: only from the load balancer's SG
aws ec2 authorize-security-group-ingress --group-id sg-app \
--protocol tcp --port 8080 --source-group sg-alb
# Database: only from the app servers' SG
aws ec2 authorize-security-group-ingress --group-id sg-db \
--protocol tcp --port 5432 --source-group sg-app
# Audit: find any SG with SSH open to the world
aws ec2 describe-security-groups \
--filters Name=ip-permission.from-port,Values=22 Name=ip-permission.cidr,Values=0.0.0.0/0 \
--query 'SecurityGroups[].[GroupId,GroupName]' --output tableRequires the SSM agent (preinstalled on Amazon Linux) and AmazonSSMManagedInstanceCore on the instance role. No port 22.
aws ssm start-session --target i-0abc123def456
# Port-forward to a private database through the instance, still no open ports
aws ssm start-session --target i-0abc123def456 \
--document-name AWS-StartPortForwardingSessionToRemoteHost \
--parameters '{"host":["prod-db.xxxx.ap-south-1.rds.amazonaws.com"],"portNumber":["5432"],"localPortNumber":["15432"]}'Explain it without notes
Why do you not need an outbound rule on a database's security group for query results to reach the app server?
Why is 'allow 5432 from sg-app' better than 'allow 5432 from 10.0.1.0/24'?
Practice
A teammate can't connect to an instance via Session Manager. List three things to check.
Design security groups for: public ALB → app on 3000 → Redis on 6379 → nothing else. Write the ingress rules.
Trade-offs
- ↔
Session Manager removes open ports and key management and gives you audit logs, but it depends on the SSM agent and connectivity to SSM endpoints — in fully private subnets that means paying for VPC interface endpoints. A bastion host is simpler to reason about but is one more exposed machine to patch.
Done when you can
I can explain stateful vs stateless firewalls.
I build tiers by referencing security groups, not CIDRs.
I can audit for SSH open to 0.0.0.0/0.
I can open a shell and a port-forward through Session Manager.