보안 그룹 최적화 - 정답 및 해설
Step 1 정답: 현재 보안 그룹 규칙 확인
정답
웹 콘솔 풀이
- AWS 콘솔에 로그인합니다.
- 상단 검색창에
EC2를 입력하고 EC2 서비스를 선택합니다. - 왼쪽 메뉴에서 Instances를 클릭합니다.
- ShopEasy EC2 인스턴스를 선택(체크)합니다.
- 하단의 Security 탭을 클릭합니다.
- Security groups 항목에서 보안 그룹 이름(링크)을 클릭합니다.
- 보안 그룹 상세 페이지에서 Inbound rules 탭을 확인합니다.
확인해야 할 내용
| 타입 | 프로토콜 | 포트 | 소스 | 판단 |
|---|---|---|---|---|
| SSH | TCP | 22 | 0.0.0.0/0 | 변경 필요 |
| Custom TCP | TCP | 5000 | 0.0.0.0/0 | 정상 (API 서비스용) |
또한 Security Groups 메뉴(왼쪽 Network & Security 섹션)에서 직접 보안 그룹 목록을 확인할 수도 있습니다.
AWS CLI 풀이
# 방법 1: ShopEasy 관련 보안 그룹 조회
aws ec2 describe-security-groups \
--filters "Name=group-name,Values=ShopEasy*" \
--query "SecurityGroups[].{Name:GroupName,ID:GroupId,Rules:IpPermissions}" \
--output json
# 방법 2: EC2 인스턴스에 연결된 보안 그룹 확인
aws ec2 describe-instances \
--filters "Name=tag:Name,Values=ShopEasy*" \
--query "Reservations[].Instances[].{
ID:InstanceId,
Name:Tags[?Key=='Name'].Value|[0],
SG:SecurityGroups[].{Name:GroupName,ID:GroupId}
}" \
--output json
# 방법 3: 특정 보안 그룹의 인바운드 규칙 상세 확인
# (보안 그룹 ID를 위에서 확인한 값으로 변경)
aws ec2 describe-security-groups \
--group-ids sg-xxxxxxxxx \
--query "SecurityGroups[].IpPermissions[].{
Protocol:IpProtocol,
FromPort:FromPort,
ToPort:ToPort,
Source:IpRanges[].CidrIp,
SGSource:UserIdGroupPairs[].GroupId
}" \
--output table
예상 출력 (JSON)
[
{
"Name": "ShopEasy-EC2-SG",
"ID": "sg-0abc1234def56789",
"Rules": [
{
"FromPort": 22,
"IpProtocol": "tcp",
"IpRanges": [
{
"CidrIp": "0.0.0.0/0",
"Description": "SSH access"
}
],
"ToPort": 22
},
{
"FromPort": 5000,
"IpProtocol": "tcp",
"IpRanges": [
{
"CidrIp": "0.0.0.0/0",
"Description": "API server"
}
],
"ToPort": 5000
}
]
}
]
보안 점검의 첫 번째 단계는 현재 상태를 정확히 파악하는 것입니다. 보안 그룹 규칙을 확인할 때 다음을 체크합니다:
- 0.0.0.0/0이 소스인 규칙이 있는지 (전체 인터넷 허용)
- 각 규칙이 실제로 필요한 것인지 (사용하지 않는 포트가 열려 있지 않은지)
- 규칙에 설명(Description)이 있는지 (관리 용이성)
SSH(22)가 0.0.0.0/0으로 열려 있는 것은 AWS에서도 경고하는 대표적인 보안 문제입니다. AWS Trusted Advisor나 Security Hub에서도 이 문제를 자동으로 감지하고 알려줍니다.
Step 2 정답: SSH 접근을 내 IP로 제한
정답
웹 콘솔 풀이
- EC2 → 왼쪽 메뉴 Security Groups를 클릭합니다.
- ShopEasy EC2에 연결된 보안 그룹을 선택합니다.
- Inbound rules 탭을 클릭합니다.
- Edit inbound rules 버튼을 클릭합니다.
- SSH(포트 22) 규칙을 찾습니다.
- Source 항목의 드롭다운을 클릭하여 "Custom"을 "My IP"로 변경합니다.
- 자동으로 현재 공인 IP가
/32와 함께 입력됩니다. - 예:
203.0.113.50/32
- 자동으로 현재 공인 IP가
- Save rules를 클릭합니다.
- 변경된 규칙을 확인합니다:
- SSH (22): 소스가
내IP/32로 변경되었는지 확인 - Custom TCP (5000): 소스가
0.0.0.0/0으로 유지되어 있는지 확인
- SSH (22): 소스가
변경 후 SSH 접속 테스트
규칙 변경 후 반드시 SSH 접속이 정상 동작하는지 확인합니다:
# SSH 접속 테스트 (로컬 터미널에서)
ssh -i "ShopEasy-Key.pem" ec2-user@EC2_PUBLIC_IP
# 접속 성공 시: [ec2-user@ip-10-0-1-xxx ~]$ 프롬프트 표시
# 접속 실패 시: Connection timed out (IP가 다르거나, 보안 그룹 규칙이 잘못된 경우)
AWS CLI 풀이
# 1. EC2 보안 그룹 ID 확인
SG_ID=$(aws ec2 describe-instances \
--filters "Name=tag:Name,Values=ShopEasy*" \
--query "Reservations[].Instances[].SecurityGroups[0].GroupId" \
--output text)
echo "EC2 보안 그룹 ID: ${SG_ID}"
# 2. 기존 SSH 규칙 제거 (0.0.0.0/0)
aws ec2 revoke-security-group-ingress \
--group-id ${SG_ID} \
--protocol tcp \
--port 22 \
--cidr 0.0.0.0/0
echo "기존 SSH 규칙(0.0.0.0/0) 제거 완료"
# 3. 내 공인 IP 확인
MY_IP=$(curl -s https://checkip.amazonaws.com)
echo "내 공인 IP: ${MY_IP}"
# 4. 새 SSH 규칙 추가 (내 IP만 허용)
aws ec2 authorize-security-group-ingress \
--group-id ${SG_ID} \
--protocol tcp \
--port 22 \
--cidr ${MY_IP}/32
echo "새 SSH 규칙 추가 완료: ${MY_IP}/32"
# 5. 변경된 규칙 확인
echo ""
echo "=== 변경 후 인바운드 규칙 ==="
aws ec2 describe-security-groups \
--group-ids ${SG_ID} \
--query "SecurityGroups[].IpPermissions[].{
Protocol:IpProtocol,
FromPort:FromPort,
ToPort:ToPort,
Source:IpRanges[].CidrIp
}" \
--output table
SSH 접속 테스트
# EC2 퍼블릭 IP 확인
EC2_IP=$(aws ec2 describe-instances \
--filters "Name=tag:Name,Values=ShopEasy*" \
--query "Reservations[].Instances[].PublicIpAddress" \
--output text)
# SSH 접속 테스트
ssh -i "ShopEasy-Key.pem" -o ConnectTimeout=5 ec2-user@${EC2_IP}
# 접속 성공하면 보안 그룹 변경이 올바르게 적용된 것입니다
이 단계가 이번 챕터의 핵심입니다. SSH 접근을 내 IP로만 제한하면:
- 인터넷의 자동화된 봇이 SSH를 통해 침입을 시도할 수 없습니다
- 키 파일이 유출되더라도 다른 IP에서는 접속할 수 없습니다 (이중 방어)
- AWS Security Hub, Trusted Advisor의 SSH 관련 경고가 해소됩니다
CLI에서 주의할 점:
revoke-security-group-ingress: 기존 규칙을 제거합니다. 반드시 제거할 규칙의 조건(포트, 프로토콜, CIDR)을 정확히 지정해야 합니다.authorize-security-group-ingress: 새 규칙을 추가합니다.checkip.amazonaws.com: AWS가 제공하는 공인 IP 확인 서비스입니다.curl -s https://checkip.amazonaws.com으로 현재 공인 IP를 확인할 수 있습니다.
순서가 중요합니다! CLI에서는 기존 0.0.0.0/0 규칙을 먼저 제거(revoke)하고, 내 IP 규칙을 추가(authorize)합니다. 만약 순서를 바꾸면 잠시 SSH가 두 규칙(0.0.0.0/0과 내 IP)으로 중복 열리는 상태가 됩니다.
Step 3 정답: RDS 보안 그룹 확인
정답
웹 콘솔 풀이
- EC2 → 왼쪽 메뉴 Security Groups를 클릭합니다.
- RDS에 연결된 보안 그룹을 찾습니다.
- 보안 그룹 이름에 "RDS", "database", "db" 등이 포함된 것을 찾습니다.
- 또는 RDS 콘솔 → Databases → ShopEasy DB 클릭 → Connectivity & security 탭에서 VPC security groups를 확인합니다.
- RDS 보안 그룹을 선택하고 Inbound rules 탭을 확인합니다.
- 다음을 확인합니다:
- 타입: MySQL/Aurora
- 포트: 3306
- 소스:
sg-xxxxxxxxx(EC2 보안 그룹 ID) ← 이것이 올바른 설정!
만약 소스가 0.0.0.0/0이라면 (수정 방법)
- Edit inbound rules를 클릭합니다.
- MySQL/Aurora (3306) 규칙의 Source를 "Custom"으로 변경합니다.
- 검색창에 EC2 보안 그룹 ID(
sg-)를 입력하여 선택합니다. - Save rules를 클릭합니다.
AWS CLI 풀이
# 1. RDS 관련 보안 그룹 조회
aws ec2 describe-security-groups \
--filters "Name=group-name,Values=*RDS*" \
--query "SecurityGroups[].{
Name:GroupName,
ID:GroupId,
InboundRules:IpPermissions[].{
Port:FromPort,
Protocol:IpProtocol,
IPSource:IpRanges[].CidrIp,
SGSource:UserIdGroupPairs[].GroupId
}
}" \
--output json
# 2. RDS 인스턴스에서 보안 그룹 확인 (RDS 콘솔 경유)
aws rds describe-db-instances \
--query "DBInstances[?starts_with(DBInstanceIdentifier,'shopeasy')].{
DB:DBInstanceIdentifier,
SG:VpcSecurityGroups[].{
ID:VpcSecurityGroupId,
Status:Status
}
}" \
--output json
소스가 0.0.0.0/0인 경우 수정하기
# EC2 보안 그룹 ID 확인
EC2_SG_ID=$(aws ec2 describe-instances \
--filters "Name=tag:Name,Values=ShopEasy*" \
--query "Reservations[].Instances[].SecurityGroups[0].GroupId" \
--output text)
echo "EC2 보안 그룹 ID: ${EC2_SG_ID}"
# RDS 보안 그룹 ID 확인
RDS_SG_ID=$(aws ec2 describe-security-groups \
--filters "Name=group-name,Values=*RDS*" \
--query "SecurityGroups[0].GroupId" \
--output text)
echo "RDS 보안 그룹 ID: ${RDS_SG_ID}"
# 만약 0.0.0.0/0 규칙이 있다면 제거
aws ec2 revoke-security-group-ingress \
--group-id ${RDS_SG_ID} \
--protocol tcp \
--port 3306 \
--cidr 0.0.0.0/0
# EC2 보안 그룹을 소스로 추가
aws ec2 authorize-security-group-ingress \
--group-id ${RDS_SG_ID} \
--protocol tcp \
--port 3306 \
--source-group ${EC2_SG_ID}
echo "RDS 보안 그룹 수정 완료!"
# 변경 결과 확인
aws ec2 describe-security-groups \
--group-ids ${RDS_SG_ID} \
--query "SecurityGroups[].IpPermissions[]" \
--output json
RDS 보안 그룹에서 보안 그룹 ID를 소스로 사용하는 것은 AWS 보안 모범 사례입니다.
IP 주소 대신 보안 그룹 ID를 사용하는 장점:
- IP 변경에 강건: EC2 인스턴스를 중지/시작하면 퍼블릭 IP가 변경되지만(Elastic IP 미사용 시), 보안 그룹 ID는 변하지 않습니다. 프라이빗 서브넷의 프라이빗 IP도 변경될 수 있습니다.
- Auto Scaling 대응: 같은 보안 그룹에 속한 새 인스턴스가 추가되면 자동으로 접근이 허용됩니다.
- 관리 편의: IP를 일일이 관리하지 않아도 됩니다.
Chapter 03에서 올바르게 설정했다면 이미 EC2 보안 그룹 ID가 소스로 되어 있을 것입니다. 이 단계는 확인(검증)이 목적입니다. 만약 0.0.0.0/0으로 되어 있다면 즉시 수정해야 합니다.
Step 4 정답: 불필요한 아웃바운드 규칙 검토
정답
웹 콘솔 풀이
- EC2 → Security Groups → EC2 보안 그룹 선택
- Outbound rules 탭을 클릭합니다.
- 기본 아웃바운드 규칙을 확인합니다:
| 타입 | 프로토콜 | 포트 | 대상 |
|---|---|---|---|
| All traffic | All | All | 0.0.0.0/0 |
이 기본 규칙은 수정하지 않습니다. 현재 상태를 확인만 하면 됩니다.
아웃바운드로 나가는 트래픽 목록 (참고)
현재 EC2에서 외부로 나가는 트래픽:
| 대상 | 포트 | 용도 |
|---|---|---|
| RDS (프라이빗 서브넷) | 3306 | MySQL 데이터베이스 연결 |
| DynamoDB (AWS 엔드포인트) | 443 | 리뷰 데이터 CRUD |
| S3 (AWS 엔드포인트) | 443 | 리뷰 이미지 업로드/다운로드 |
| 인터넷 | 443, 80 | npm/yum 패키지 다운로드 |
AWS CLI 풀이
# EC2 보안 그룹 ID 확인
SG_ID=$(aws ec2 describe-instances \
--filters "Name=tag:Name,Values=ShopEasy*" \
--query "Reservations[].Instances[].SecurityGroups[0].GroupId" \
--output text)
# 아웃바운드 규칙 확인
echo "=== EC2 보안 그룹 아웃바운드 규칙 ==="
aws ec2 describe-security-groups \
--group-ids ${SG_ID} \
--query "SecurityGroups[].IpPermissionsEgress[].{
Protocol:IpProtocol,
FromPort:FromPort,
ToPort:ToPort,
Destination:IpRanges[].CidrIp
}" \
--output table
# 예상 출력:
# Protocol: -1 (All), FromPort: None, ToPort: None, Destination: 0.0.0.0/0
# 이것은 기본 아웃바운드 규칙 (모든 트래픽 허용)입니다
아웃바운드 규칙의 기본값은 "All traffic - 0.0.0.0/0"으로 모든 나가는 트래픽을 허용합니다. 이번 실습에서는 이 기본값을 유지합니다.
실무에서 아웃바운드를 제한하는 경우:
- PCI-DSS, HIPAA 등 보안 컴플라이언스 요구사항이 있는 경우
- 데이터 유출(Data Exfiltration)을 방지해야 하는 경우
- 특정 AWS 서비스(S3, DynamoDB 등)로만 통신을 제한해야 하는 경우
아웃바운드를 제한할 때 주의할 점:
- RDS 연결(3306), DynamoDB/S3 API 호출(443) 등 모든 필요한 포트를 허용해야 합니다
- 소프트웨어 업데이트(yum/npm)를 위한 HTTP(80)/HTTPS(443)도 필요합니다
- 하나라도 빠뜨리면 서비스가 중단됩니다
강사 참고: 아웃바운드 제한은 고급 주제입니다. 학생들에게 "지금은 확인만 하고, 실무에서는 필요에 따라 제한할 수 있다"고 안내하세요.
트러블슈팅 가이드
자주 발생하는 문제와 해결 방법
원인: 보안 그룹에 등록된 IP와 현재 공인 IP가 다릅니다. 카페, 학교, 회사 등 네트워크 환경이 바뀌면 공인 IP가 변경됩니다. 또한 같은 네트워크에서도 공유기가 재시작되면 IP가 바뀔 수 있습니다.
해결:
# 1. 현재 내 공인 IP 확인
curl -s https://checkip.amazonaws.com
# 예: 203.0.113.75
# 2. 보안 그룹에 등록된 IP 확인
SG_ID=$(aws ec2 describe-instances \
--filters "Name=tag:Name,Values=ShopEasy*" \
--query "Reservations[].Instances[].SecurityGroups[0].GroupId" \
--output text)
aws ec2 describe-security-groups \
--group-ids ${SG_ID} \
--query "SecurityGroups[].IpPermissions[?FromPort==\`22\`].IpRanges[].CidrIp" \
--output text
# 예: 203.0.113.50/32 <-- 이전 IP!
# 3. IP가 다르다면 규칙 업데이트
# 이전 IP 규칙 제거
aws ec2 revoke-security-group-ingress \
--group-id ${SG_ID} \
--protocol tcp \
--port 22 \
--cidr 203.0.113.50/32
# 새 IP 규칙 추가
MY_IP=$(curl -s https://checkip.amazonaws.com)
aws ec2 authorize-security-group-ingress \
--group-id ${SG_ID} \
--protocol tcp \
--port 22 \
--cidr ${MY_IP}/32
echo "SSH 규칙 업데이트 완료: ${MY_IP}/32"
또는 웹 콘솔에서 간단하게 수정할 수 있습니다:
- EC2 → Security Groups → EC2 보안 그룹 선택
- Inbound rules → Edit inbound rules
- SSH 규칙의 Source를 "My IP"로 다시 변경
- Save rules
원인: SSH 규칙을 변경할 때 실수로 포트 5000 규칙을 삭제하거나 변경했을 수 있습니다.
해결:
# 현재 인바운드 규칙 확인
SG_ID=$(aws ec2 describe-instances \
--filters "Name=tag:Name,Values=ShopEasy*" \
--query "Reservations[].Instances[].SecurityGroups[0].GroupId" \
--output text)
aws ec2 describe-security-groups \
--group-ids ${SG_ID} \
--query "SecurityGroups[].IpPermissions[].{
Port:FromPort,
Source:IpRanges[].CidrIp
}" \
--output table
# 포트 5000 규칙이 없다면 추가
aws ec2 authorize-security-group-ingress \
--group-id ${SG_ID} \
--protocol tcp \
--port 5000 \
--cidr 0.0.0.0/0
echo "포트 5000 인바운드 규칙 복원 완료"
Edit inbound rules 화면에서 SSH 규칙만 수정해야 합니다. 다른 규칙을 실수로 삭제하지 않도록 주의하세요. 실수로 규칙을 삭제한 경우, 위 CLI 명령어로 복원할 수 있습니다.
원인: RDS 보안 그룹의 소스를 변경할 때 EC2 보안 그룹 ID를 잘못 입력했거나, 규칙을 실수로 삭제했습니다.
해결:
# EC2 보안 그룹 ID 확인
EC2_SG_ID=$(aws ec2 describe-instances \
--filters "Name=tag:Name,Values=ShopEasy*" \
--query "Reservations[].Instances[].SecurityGroups[0].GroupId" \
--output text)
echo "EC2 보안 그룹: ${EC2_SG_ID}"
# RDS 보안 그룹 ID 확인
RDS_SG_ID=$(aws ec2 describe-security-groups \
--filters "Name=group-name,Values=*RDS*" \
--query "SecurityGroups[0].GroupId" \
--output text)
echo "RDS 보안 그룹: ${RDS_SG_ID}"
# RDS 보안 그룹에 EC2 보안 그룹 소스 규칙 추가
aws ec2 authorize-security-group-ingress \
--group-id ${RDS_SG_ID} \
--protocol tcp \
--port 3306 \
--source-group ${EC2_SG_ID}
echo "RDS 보안 그룹 규칙 복원 완료"
# EC2에서 RDS 연결 테스트
# (EC2에 SSH 접속 후)
# mysql -h RDS_ENDPOINT -u admin -p
해결: 여러 방법으로 확인할 수 있습니다.
# 방법 1: AWS 제공 서비스 (가장 권장)
curl -s https://checkip.amazonaws.com
# 방법 2: 다른 서비스
curl -s https://ifconfig.me
curl -s https://icanhazip.com
curl -s https://api.ipify.org
# 방법 3: AWS 콘솔에서 자동 입력
# Security Group 편집 시 Source를 "My IP"로 선택하면 자동으로 입력됩니다
AWS 콘솔에서 보안 그룹을 편집할 때 Source 드롭다운에서 "My IP"를 선택하면 IP를 직접 찾을 필요 없이 자동으로 입력됩니다. 이 방법을 가장 권장합니다.
원인: VPC에는 기본 보안 그룹(default)이 있습니다. ShopEasy EC2에 연결된 보안 그룹이 아닌 기본 보안 그룹을 수정한 경우입니다.
해결:
- 먼저 EC2 인스턴스에 연결된 정확한 보안 그룹 ID를 확인합니다.
- EC2 → Instances → ShopEasy 인스턴스 → Security 탭에서 보안 그룹 확인
- 해당 보안 그룹으로 이동하여 규칙을 수정합니다.
# EC2에 연결된 정확한 보안 그룹 확인
aws ec2 describe-instances \
--filters "Name=tag:Name,Values=ShopEasy*" \
--query "Reservations[].Instances[].{
Name:Tags[?Key=='Name'].Value|[0],
SecurityGroups:SecurityGroups[].{Name:GroupName,ID:GroupId}
}" \
--output json
각 학생의 보안 그룹이 올바르게 설정되었는지 다음을 확인하세요:
- EC2 보안 그룹 인바운드:
- SSH (22): 소스가 학생의 IP/32 (0.0.0.0/0이 아닌지 확인)
- Custom TCP (5000): 소스가 0.0.0.0/0 (서비스용)
- RDS 보안 그룹 인바운드:
- MySQL/Aurora (3306): 소스가 EC2 보안 그룹 ID (0.0.0.0/0이 아닌지 확인)
- EC2 보안 그룹 아웃바운드:
- All traffic: 0.0.0.0/0 (기본값 유지)
- SSH 접속 테스트: 변경 후 SSH 접속이 되는지 확인
- 서비스 테스트: S3 웹사이트에서 상품 조회, 리뷰 기능이 정상 동작하는지 확인
학생들에게 다음 보안 그룹 모범 사례를 안내하세요:
- 최소 권한 원칙: 필요한 포트만, 필요한 소스에서만 허용
- SSH는 절대 0.0.0.0/0 금지: 내 IP 또는 VPN/Bastion Host를 통해서만 접근
- 보안 그룹 ID를 소스로 활용: IP 대신 보안 그룹 참조로 유연하고 안전한 설정
- 설명(Description) 작성: 각 규칙에 설명을 추가하여 관리 용이성 확보
- 정기적인 검토: 사용하지 않는 규칙이 있는지 주기적으로 점검