AWS 중급 #2 EC2 운영: security group, key pair, SSM
#1 EC2와 VPC 기초에서 EC2 한 대를 띄우는 그림을 잡았습니다. 이번 글은 그 EC2를 다루는 방법을 정리합니다. 보안 규칙은 어떻게 디자인하고, 접속은 어떻게 하며, 같은 인스턴스를 여러 번 띄우려면 무엇을 굳혀야 하는지 짚습니다.
운영 EC2의 80% 일은 다음 셋입니다.
- Security Group으로 누가 들어올 수 있는지 제어
- 접속. 옛날엔 SSH + key pair, 요즘은 SSM Session Manager
- AMI로 골격을 굳혀 같은 인스턴스를 빠르게 재생성
이 셋을 한 줄에 꿰면 EC2 운영의 일상이 단순해집니다.
Security Group의 구조 #
**Security Group (SG)**은 인스턴스 (정확히는 ENI)에 붙는 stateful 방화벽입니다. 인스턴스 한 대에 SG를 여러 개 붙일 수 있고, SG 한 개를 여러 인스턴스가 공유할 수 있습니다.
Inbound vs Outbound #
SG의 규칙은 두 방향:
| Inbound | Outbound | |
|---|---|---|
| 누구를 제어 | 들어오는 트래픽 | 나가는 트래픽 |
| 기본값 | 모두 막음 | 모두 허용 |
| 자주 만짐 | ✅ | 거의 안 |
기본값을 기억하세요. Inbound는 기본 차단, Outbound는 기본 허용. 그래서 SG 작업의 99%는 Inbound 규칙 추가입니다.
규칙의 구조 #
Protocol Port Source Description
TCP 80 0.0.0.0/0 HTTP from anywhere
TCP 443 0.0.0.0/0 HTTPS from anywhere
TCP 22 198.51.100.10/32 SSH from my home IP각 규칙은 (프로토콜, 포트, 소스)의 조합. 소스 (Source) 항목에는 두 가지가 들어갈 수 있습니다:
- CIDR 블록.
0.0.0.0/0(모든 IP),10.0.0.0/16(VPC 내부),198.51.100.10/32(단일 IP) - 다른 SG의 ID.
sg-0abc...← 이게 진짜 강력합니다
SG를 SG로 가리키기 #
운영에서 핵심 패턴은 SG가 다른 SG를 가리키는 것.
ALB SG (sg-alb)
Inbound: TCP 443 from 0.0.0.0/0
App SG (sg-app)
Inbound: TCP 8080 from sg-alb ← IP가 아니라 SG 자체ALB의 IP가 바뀌어도 (실제로 ALB는 여러 IP를 동적으로 할당) SG가리키기는 자동으로 따라갑니다. 운영 인프라의 규칙 유지보수가 훨씬 단순해집니다.
자주 쓰는 SG 패턴 #
ALB SG (sg-alb)
in: 443 ← 0.0.0.0/0
out: all
App SG (sg-app)
in: 8080 ← sg-alb ← ALB만 들어올 수 있음
22 ← sg-bastion ← Bastion에서 SSH (옛날 방식)
out: all
DB SG (sg-db)
in: 5432 ← sg-app ← 앱 서버만 DB 접근
out: all (또는 닫기)
Bastion SG (sg-bastion)
in: 22 ← 198.51.100.10/32 ← 본인 IP만
out: all규칙이 **“SG → SG”**로 흐르는 게 핵심. IP가 아닙니다.
Outbound를 막는 경우 #
기본은 outbound 모두 허용이지만, 공격에 노출됐을 때 데이터 유출을 막기 위해 outbound도 좁히는 패턴이 있습니다. 보통 운영 환경의 DB / 내부 시스템부터 적용합니다.
App SG outbound:
TCP 5432 → sg-db ← DB만
TCP 443 → 0.0.0.0/0 ← 외부 API 호출용
TCP 53 → 0.0.0.0/0 ← DNS
UDP 53 → 0.0.0.0/0 ← DNSNACL: 또 다른 층 #
VPC의 두 번째 방화벽은 **NACL (Network Access Control List)**입니다. 서브넷 단위로 동작합니다.
| Security Group | NACL | |
|---|---|---|
| 적용 단위 | 인스턴스 (ENI) | 서브넷 |
| Stateful | ✅ | ❌ (응답도 명시 허용 필요) |
| 규칙 종류 | Allow only | Allow + Deny |
| 평가 순서 | 모든 규칙 | 번호순 (낮은 번호 먼저) |
| 일상에서 | 매일 만짐 | 거의 안 만짐 |
NACL은 자주 쓰지 않습니다. 기본 NACL이 모든 트래픽을 허용하고, SG가 충분히 세밀하기 때문입니다. NACL을 만지는 경우:
- 특정 IP 대역 차단 (Deny가 필요할 때. SG에는 Deny가 없음)
- 공격 받을 때 임시 차단
- 컴플라이언스 요구로 서브넷 단위 명시 차단
NACL의 stateless 함정 #
NACL은 stateless 라 응답 트래픽도 명시 허용해야 합니다.
Inbound Allow TCP 1024-65535 0.0.0.0/0 ← ephemeral port 응답
Outbound Allow TCP 80 0.0.0.0/01024-65535가 ephemeral port 영역입니다. 이걸 빠뜨리면 응답이 안 돌아옵니다. SG에선 stateful이라 자동인데, NACL은 명시가 필요합니다.
Key pair의 한계 #
옛날부터 EC2 SSH 접속은 key pair로 했습니다.
# 키 페어 만들기
aws ec2 create-key-pair --key-name my-key --query 'KeyMaterial' --output text > my-key.pem
chmod 400 my-key.pem
# 인스턴스 띄울 때 key 지정
aws ec2 run-instances --key-name my-key ...
# 접속
ssh -i my-key.pem ec2-user@<public-ip>EC2가 띄워질 때 인스턴스의 ~/.ssh/authorized_keys에 자동으로 키가 추가되어 SSH가 가능해집니다.
key pair의 한계 #
key pair 모델은 운영 규모가 커지면 깨집니다.
- 키 분실. 잃어버리면 다시 만들 수 없음. 인스턴스 재생성 또는 EBS 마운트 후 수동 추가
- 키 공유의 위험. 팀원에게 줘야 하는데 한 번 새면 회수 못 함
- 감사 어려움. 누가 언제 들어왔는지 별도 로깅 필요
- 인터넷에 22 포트 노출. 공격 면적
- MFA 안 됨. 키만 있으면 통과
EC2 Instance Connect #
콘솔이 만든 임시 SSH 키를 한 번만 쓰는 방식입니다. SG에 22 포트 허용은 여전히 필요합니다. 콘솔의 “Connect” 버튼이 이걸 씁니다.
SSM Session Manager: 키 없는 접속 #
**SSM (AWS Systems Manager)**의 Session Manager는 EC2 접속의 새 표준입니다. 22 포트도 안 열고, 키도 없이 EC2 안의 셸로 들어갑니다.
[내 컴퓨터] ──HTTPS──▶ [SSM Endpoint] ◀──HTTPS──[EC2 안의 SSM Agent]
│
▼
IAM 권한 확인EC2 안에서 도는 SSM Agent가 AWS API로 outbound 연결을 만들고, 그 채널을 통해 콘솔의 셸 입력이 흐릅니다. 방향이 반대 (EC2가 outbound) 라서 SG inbound 22 포트가 필요 없습니다.
Session Manager 셋업 #
- SSM Agent가 설치된 AMI. Amazon Linux 2023 / Ubuntu 최신은 기본 포함
- EC2의 IAM Role에
AmazonSSMManagedInstanceCore정책 - outbound 인터넷 또는 VPC Endpoint (Private 서브넷의 EC2도 SSM 가능)
aws ssm start-session --target i-0abc1234def567890
# 포트 포워딩도 가능
aws ssm start-session --target i-0abc... \
--document-name AWS-StartPortForwardingSession \
--parameters '{"portNumber":["80"],"localPortNumber":["8080"]}'key pair vs Session Manager #
| key pair (SSH) | Session Manager | |
|---|---|---|
| 22 포트 | 열어야 함 | 안 열어도 됨 |
| 키 관리 | 직접 | 없음 |
| 인증 | SSH 키 | IAM (MFA 가능) |
| 감사 로그 | 별도 | CloudTrail / S3 자동 |
| Private 서브넷 | Bastion 필요 | VPC Endpoint로 직접 |
| 포트 포워딩 | ssh -L | start-session로 가능 |
운영에서는 Session Manager가 거의 항상 정답입니다. 자세한 IAM 설정은 기초 #2, 보안은 기초 #6 참조.
CloudShell과 헷갈리지 마십시오. 기초 #5 CloudShell은 AWS 콘솔 안의 브라우저 터미널 (내 IAM 자격으로
aws cli를 쓰는 방식). Session Manager는 EC2 인스턴스 안의 셸입니다.
EC2의 메타데이터 서비스 (IMDS) #
EC2 안에서 자기 인스턴스의 정보 (인스턴스 ID, 리전, IAM 역할 자격증명 등)를 받는 서비스가 **IMDS (Instance Metadata Service)**입니다.
TOKEN=$(curl -X PUT http://169.254.169.254/latest/api/token \
-H "X-aws-ec2-metadata-token-ttl-seconds: 21600")
curl -H "X-aws-ec2-metadata-token: $TOKEN" \
http://169.254.169.254/latest/meta-data/instance-id169.254.169.254 라는 link-local 주소가 EC2 안에서만 응답하는 메타데이터 엔드포인트입니다. IAM Role의 임시 자격증명도 여기서 받습니다. aws cli가 EC2 안에서 자동으로 그 자격을 쓰는 이유입니다.
IMDSv1 vs IMDSv2 #
옛날엔 토큰 없이 GET으로 받았습니다 (IMDSv1). SSRF 공격으로 토큰을 빼가는 사고가 많아 IMDSv2로 바뀌었습니다. PUT으로 토큰 받고 그걸로 GET. 새 인스턴스는 IMDSv2만 활성화가 권장.
aws ec2 modify-instance-metadata-options \
--instance-id i-0abc... \
--http-tokens required \
--http-endpoint enabledAMI 만들기: 골격 굳히기 #
같은 셋업을 가진 인스턴스를 여러 번 빠르게 띄우려면 두 가지 방법이 있습니다.
- AMI 만들기. 현재 인스턴스를 스냅샷 떠서 새 AMI로
- User data + IaC. 빈 AMI로 띄우고 셋업 스크립트 자동 실행
AMI 만들기 #
콘솔에서 인스턴스 우클릭 → “이미지 생성”, 또는:
aws ec2 create-image \
--instance-id i-0abc... \
--name "my-app-2026-04-19" \
--description "Node 20 + nginx + my-app v1.2.3" \
--no-reboot # 옵션. 재부팅 없이 (디스크 일관성은 약간 떨어질 수 있음)만들어진 AMI는:
- 인스턴스의 EBS 스냅샷 + 메타데이터
- 그 AMI로 새 인스턴스 띄우면 같은 디스크 상태로 시작
- 리전 단위. 다른 리전에선
copy-image
User data: 부팅 스크립트 #
AMI 대신 빈 OS 이미지로 띄우고 부팅 스크립트로 셋업 하는 패턴. AMI보다 유연하고, 변경 추적도 쉽습니다.
#!/bin/bash
yum update -y
yum install -y nginx
systemctl enable --now nginx
# 앱 코드 받기
aws s3 cp s3://my-bucket/app.tar.gz /tmp/
tar -xzf /tmp/app.tar.gz -C /opt/myappUser data는 인스턴스 첫 부팅 때 1회 실행. 로그는 /var/log/cloud-init-output.log.
Golden AMI vs User data #
| Golden AMI | User data | |
|---|---|---|
| 부팅 속도 | 빠름 | 느림 (스크립트 실행 시간) |
| 변경 관리 | AMI 새로 빌드 | 스크립트 수정 |
| 재현성 | 매우 높음 | 외부 의존성 (yum repo, S3)가 변할 수 있음 |
| 방식 | ASG 빠른 스케일 / 안정적 | 개발 / 빠른 변경 |
운영에선 둘 다 같이 씁니다. 골든 AMI로 OS / 의존성을 굳히고, User data로 앱 버전만 끼워 넣는 식입니다.
Auto Scaling Group: 자동 복구 #
인스턴스가 죽으면 새로 띄우고 ALB에 자동 연결해 주는 기능이 **ASG (Auto Scaling Group)**입니다.
Launch Template (인스턴스 템플릿: AMI, 타입, SG, key, user data)
│
▼
┌─────────┐
│ ASG │ desired=2 min=2 max=10
└─────────┘
│
├─── EC2 (AZ a) ← health check 실패 → terminate + 새로 띄움
├─── EC2 (AZ b)
└─── EC2 (AZ b)기본 설정만:
- Launch Template. 어떤 EC2를 띄울지 정의 (AMI, 타입, SG, IAM, user data)
- Desired / Min / Max. 항상 유지할 개수, 최소, 최대
- Health Check. EC2 자체 (
EC2) 또는 ALB target group (ELB) 기준
자세한 ASG 설정보다는 고급 #1 ECS / Fargate가 더 매끄러운 대안입니다. ECS가 컨테이너 ASG를 흡수합니다.
자주 만나는 함정 #
1) “왜 ALB가 EC2에 도달 못 합니다?” #
체크리스트 (위에서 아래):
- ALB SG outbound가 EC2 SG inbound와 일치
- EC2 SG inbound에 ALB SG가 source로 들어 있음
- EC2의 OS 안 방화벽 (
firewalld,ufw)도 그 포트 허용 - ALB target group의 health check 경로가 200 응답
- EC2가 그 포트에서 listen 중 (
ss -tlnp)
대부분 1) 또는 2). SG 항목을 IP로 적었다면 SG 자체로 바꾸는 것이 운영 정답.
2) “키 없는데 EC2 안에 들어가야” #
- Session Manager가 켜졌으면 →
aws ssm start-session - 안 켜졌으면 → 인스턴스 정지 → EBS 분리 → 다른 EC2에 마운트 →
~/.ssh/authorized_keys수정 → 재연결 - 또는 EBS 스냅샷 떠서 새 키로 새 인스턴스 띄움
3) Outbound all 그대로 → 데이터 유출 #
EC2가 침해됐을 때 outbound가 다 열려 있으면 공격자가 임의 IP로 데이터를 보냅니다. DB 서버 / 내부 시스템은 outbound도 좁히는 게 베스트입니다.
4) NACL을 임의 차단으로 막다 응답이 안 옴 #
NACL stateless를 잊고 outbound만 허용 → inbound 응답이 막힘. 거의 항상 NACL은 기본값으로 두고 SG만 만지는 게 안전.
5) IMDSv1 그대로 #
오래된 AMI / 옛 셋업이 IMDSv1 인 채로 운영 중 → SSRF 공격 면. 모든 인스턴스에 --http-tokens required.
6) AMI가 너무 커서 부팅이 느려집니다 #
오래 운영한 인스턴스를 그대로 AMI로 떠서 5GB+ 가 됨. 부팅 시간이 늘어납니다. AMI 만들기 전에:
- 로그 / 캐시 / 임시 파일 정리 (
yum clean all등) cloud-init clean(다음 부팅에 다시 init 돌도록)- swap / journal 비우기
정리 #
이번 글에서 잡은 것:
- SG = 인스턴스 단위 stateful 방화벽. SG → SG 패턴이 IP보다 강력
- 기본값은 inbound 차단 + outbound 허용. Outbound 좁히기는 데이터 유출 방어
- NACL은 서브넷 단위 stateless. 거의 안 만짐. Stateless 라 응답 ephemeral port도 허용 필요
- key pair는 옛날 표준. 키 분실 / 공유 / 22 포트 노출이 한계
- SSM Session Manager가 새 표준. 22 포트도 키도 안 쓰고 IAM으로 인증, 감사 로그 자동
- IMDSv2 강제. SSRF 방어
- AMI로 골격 굳히기 + User data로 부팅 시 셋업, 보통 둘 다 사용
- ASG가 자동 복구. Launch Template + desired/min/max + health check
- 함정. ALB→EC2 5단계 점검, 키 없는 복구, outbound all, NACL stateless, IMDSv1, 큰 AMI
다음: S3 #
EC2의 기본은 정리됐습니다. 이제 EC2와 함께 자주 다루는 객체 스토리지로 넘어갑니다.
#3 S3: 정적 호스팅, presigned URL에서는 버킷의 모양, 정책과 public access block, 정적 사이트 호스팅, presigned URL 같은 일상 패턴을 정리하겠습니다.