AWS 중급 #2 EC2 운영: security group, key pair, SSM

9 분 소요

#1 EC2와 VPC 기초에서 EC2 한 대를 띄우는 그림을 잡았습니다. 이번 글은 그 EC2를 다루는 방법을 정리합니다. 보안 규칙은 어떻게 디자인하고, 접속은 어떻게 하며, 같은 인스턴스를 여러 번 띄우려면 무엇을 굳혀야 하는지 짚습니다.

운영 EC2의 80% 일은 다음 셋입니다.

  1. Security Group으로 누가 들어올 수 있는지 제어
  2. 접속. 옛날엔 SSH + key pair, 요즘은 SSM Session Manager
  3. AMI로 골격을 굳혀 같은 인스턴스를 빠르게 재생성

이 셋을 한 줄에 꿰면 EC2 운영의 일상이 단순해집니다.

Security Group의 구조 #

**Security Group (SG)**은 인스턴스 (정확히는 ENI)에 붙는 stateful 방화벽입니다. 인스턴스 한 대에 SG를 여러 개 붙일 수 있고, SG 한 개를 여러 인스턴스가 공유할 수 있습니다.

Inbound vs Outbound #

SG의 규칙은 두 방향:

InboundOutbound
누구를 제어들어오는 트래픽나가는 트래픽
기본값모두 막음모두 허용
자주 만짐거의 안

기본값을 기억하세요. Inbound는 기본 차단, Outbound는 기본 허용. 그래서 SG 작업의 99%는 Inbound 규칙 추가입니다.

규칙의 구조 #

웹 서버 SG의 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 → 앱 EC2 패턴
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 패턴 #

3-tier 웹 앱 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 / 내부 시스템부터 적용합니다.

좁힌 outbound의 예
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             ← DNS

NACL: 또 다른 층 #

VPC의 두 번째 방화벽은 **NACL (Network Access Control List)**입니다. 서브넷 단위로 동작합니다.

Security GroupNACL
적용 단위인스턴스 (ENI)서브넷
Stateful❌ (응답도 명시 허용 필요)
규칙 종류Allow onlyAllow + Deny
평가 순서모든 규칙번호순 (낮은 번호 먼저)
일상에서매일 만짐거의 안 만짐

NACL은 자주 쓰지 않습니다. 기본 NACL이 모든 트래픽을 허용하고, SG가 충분히 세밀하기 때문입니다. NACL을 만지는 경우:

  • 특정 IP 대역 차단 (Deny가 필요할 때. SG에는 Deny가 없음)
  • 공격 받을 때 임시 차단
  • 컴플라이언스 요구로 서브넷 단위 명시 차단

NACL의 stateless 함정 #

NACL은 stateless 라 응답 트래픽도 명시 허용해야 합니다.

NACL 규칙 예: TCP 80 outbound가 응답을 받으려면
Inbound  Allow  TCP  1024-65535  0.0.0.0/0   ← ephemeral port 응답
Outbound Allow  TCP  80          0.0.0.0/0

1024-65535ephemeral port 영역입니다. 이걸 빠뜨리면 응답이 안 돌아옵니다. SG에선 stateful이라 자동인데, NACL은 명시가 필요합니다.

Key pair의 한계 #

옛날부터 EC2 SSH 접속은 key pair로 했습니다.

key pair 만들기 + SSH 접속
# 키 페어 만들기
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 안의 셸로 들어갑니다.

Session Manager의 흐름
[내 컴퓨터] ──HTTPS──▶ [SSM Endpoint] ◀──HTTPS──[EC2 안의 SSM Agent]
                   IAM 권한 확인

EC2 안에서 도는 SSM Agent가 AWS API로 outbound 연결을 만들고, 그 채널을 통해 콘솔의 셸 입력이 흐릅니다. 방향이 반대 (EC2가 outbound) 라서 SG inbound 22 포트가 필요 없습니다.

Session Manager 셋업 #

  1. SSM Agent가 설치된 AMI. Amazon Linux 2023 / Ubuntu 최신은 기본 포함
  2. EC2의 IAM RoleAmazonSSMManagedInstanceCore 정책
  3. outbound 인터넷 또는 VPC Endpoint (Private 서브넷의 EC2도 SSM 가능)
콘솔 대신 CLI로 접속
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 -Lstart-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)**입니다.

IMDSv2: 토큰 받고 메타데이터 조회
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-id

169.254.169.254 라는 link-local 주소가 EC2 안에서만 응답하는 메타데이터 엔드포인트입니다. IAM Role의 임시 자격증명도 여기서 받습니다. aws cli가 EC2 안에서 자동으로 그 자격을 쓰는 이유입니다.

IMDSv1 vs IMDSv2 #

옛날엔 토큰 없이 GET으로 받았습니다 (IMDSv1). SSRF 공격으로 토큰을 빼가는 사고가 많아 IMDSv2로 바뀌었습니다. PUT으로 토큰 받고 그걸로 GET. 새 인스턴스는 IMDSv2만 활성화가 권장.

IMDSv2 강제
aws ec2 modify-instance-metadata-options \
  --instance-id i-0abc... \
  --http-tokens required \
  --http-endpoint enabled

AMI 만들기: 골격 굳히기 #

같은 셋업을 가진 인스턴스를 여러 번 빠르게 띄우려면 두 가지 방법이 있습니다.

  1. AMI 만들기. 현재 인스턴스를 스냅샷 떠서 새 AMI로
  2. User data + IaC. 빈 AMI로 띄우고 셋업 스크립트 자동 실행

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보다 유연하고, 변경 추적도 쉽습니다.

User data 예: Amazon Linux 2023
#!/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/myapp

User data는 인스턴스 첫 부팅 때 1회 실행. 로그는 /var/log/cloud-init-output.log.

Golden AMI vs User data #

Golden AMIUser data
부팅 속도빠름느림 (스크립트 실행 시간)
변경 관리AMI 새로 빌드스크립트 수정
재현성매우 높음외부 의존성 (yum repo, S3)가 변할 수 있음
방식ASG 빠른 스케일 / 안정적개발 / 빠른 변경

운영에선 둘 다 같이 씁니다. 골든 AMI로 OS / 의존성을 굳히고, User data로 앱 버전만 끼워 넣는 식입니다.

Auto Scaling Group: 자동 복구 #

인스턴스가 죽으면 새로 띄우고 ALB에 자동 연결해 주는 기능이 **ASG (Auto Scaling Group)**입니다.

ASG의 구조
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에 도달 못 합니다?” #

체크리스트 (위에서 아래):

  1. ALB SG outbound가 EC2 SG inbound와 일치
  2. EC2 SG inbound에 ALB SG가 source로 들어 있음
  3. EC2의 OS 안 방화벽 (firewalld, ufw)도 그 포트 허용
  4. ALB target group의 health check 경로가 200 응답
  5. 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 같은 일상 패턴을 정리하겠습니다.

X