아키텍처 케이스 · 1
EC2에 액세스 키를 심어 배포했다
시험에서 가장 자주 나오는 안티패턴이자, 실무에서 가장 자주 일어나는 사고입니다. 핵심은 "키를 어디에 숨길 것인가"가 아니라 애초에 회수해야 할 키를 만들지 않는 것입니다. 이 케이스는 장기 자격 증명이 어떻게 통제 불가능한 상태로 번지는지 경로를 추적하고, 세 가지 후보 설계를 비교해 IAM 역할로 넘어가는 판단을 정리합니다.
학습 목표
- 장기 액세스 키가 이미지·저장소·로그로 번지는 확산 경로를 설명할 수 있습니다.
- 키 정기 교체, 비밀 관리 서비스 조회, IAM 역할 세 후보를 회수 가능성 기준으로 비교할 수 있습니다.
- 인스턴스 프로파일을 붙이는 것만으로는 부족하고 기존 자격 증명 파일을 함께 제거해야 하는 이유를 설명할 수 있습니다.
- IMDSv2를 강제하고 홉 제한을 조정해 서버 측 요청 위조(SSRF)로 자격 증명이 새는 경로를 차단할 수 있습니다.
- 시험 문항에서 "액세스 키" 선택지를 소거하고 역할 기반 선택지를 고를 수 있습니다.
상황
사내 이미지 변환 서비스가 Amazon EC2 Auto Scaling 그룹에서 12대로 운영되고 있습니다.
각 인스턴스는 원본을 Amazon S3에서 읽고 변환 결과를 다른 버킷에 씁니다.
2년 전 첫 배포 때 담당자가 IAM 사용자를 하나 만들고 액세스 키를 발급해
AMI 안의 공유 자격 증명 파일(~/.aws/credentials)에 적어 두었습니다.
그 뒤로 배포는 이 AMI를 복제하는 방식으로 이어졌습니다.
문제는 그 IAM 사용자에게 AmazonS3FullAccess가 붙어 있고,
같은 키가 다음 네 곳에 동시에 존재한다는 점입니다.
- 현재 운영 중인 인스턴스 12대의 디스크
- Auto Scaling 그룹이 참조하는 AMI, 그리고 그 AMI를 복제해 만든 개발용 AMI 3개
- 사내 저장소에 커밋된 배포 스크립트의 환경 변수 예시 파일
- 2년 전 장애 대응 때 캡처해 사내 위키에 붙인 셸 출력
이번 주 AWS CloudTrail 이벤트에서 그 액세스 키 ID로
평소 쓰지 않는 리전의 s3:ListAllMyBuckets 호출이 관측되었습니다.
보안 담당자는 즉시 키를 비활성화하려 하지만,
키를 끄는 순간 운영 중인 12대의 변환 작업이 전부 실패한다는 것도 알고 있습니다.
요구사항과 제약
| 구분 | 내용 | 설계에 주는 함의 |
|---|---|---|
| 요구 1 | 유출된 자격 증명을 확실히 무효화할 수 있어야 한다 | 회수 지점이 한 곳으로 모여야 한다. 복사본이 여러 곳에 있으면 회수가 성립하지 않는다 |
| 요구 2 | 앞으로 같은 사고가 재발하지 않아야 한다 | 사람이 키를 옮기는 절차가 남아 있으면 재발한다. 절차 자체를 없애야 한다 |
| 요구 3 | 누가 무엇을 호출했는지 추적할 수 있어야 한다 | 공유 자격 증명 하나로는 주체를 구분할 수 없다 |
| 제약 1 | 애플리케이션 코드 변경을 최소화한다 | SDK의 기본 자격 증명 체인을 그대로 쓰는 방법이 유리하다 |
| 제약 2 | 전환 중 변환 작업이 중단되면 안 된다 | 키 비활성화가 전환의 첫 단계가 될 수 없다. 순서가 중요하다 |
| 제약 3 | 권한은 필요한 버킷과 동작으로 제한한다 | 전환하는 김에 AmazonS3FullAccess를 좁힌다 |
배경 개념은 2장 IAM과 자격 증명에 있습니다. 정책 평가 로직과 역할의 두 축(신뢰 정책과 권한 정책)을 먼저 확인하면 아래 비교가 훨씬 빨리 읽힙니다.
후보 설계안 비교
현장에서 실제로 제안되는 안은 넷입니다. 네 안 모두 "보안을 개선한다"고 주장하지만, 요구 1(확실한 무효화)을 통과하는 것은 하나뿐입니다.
| 항목 | A · 키 유지 + 정기 교체 자동화 | B · AWS Secrets Manager에 키 저장 후 조회 | C · IAM 역할 + 인스턴스 프로파일 | D · IAM Identity Center 도입 |
|---|---|---|---|---|
| 자격 증명 수명 | 교체 주기까지 유효한 장기 키 | 여전히 장기 키. 저장 위치만 바뀜 | 만료되는 임시 자격 증명 | 사람 세션은 임시. 기계 자격 증명은 그대로 |
| 유출 시 회수 | 불가 — 복사본을 셀 수 없다 | 부분 — 조회용 자격 증명이 또 필요하다 | 역할 신뢰 정책과 권한만 바꾸면 즉시 | 해당 없음 — 이 문제를 다루지 않는다 |
| 부트스트랩 문제 | 없음(이미 심어 둠) | 발생 — 비밀을 읽을 자격 증명을 다시 인스턴스에 줘야 한다 | 없음 — 인스턴스 메타데이터가 대신한다 | 해당 없음 |
| 코드 변경 | 없음 | 조회 코드 추가 필요 | 없음 — 기본 자격 증명 체인이 처리 | 없음 |
| 운영 부담 | 교체 파이프라인을 계속 유지해야 한다 | 비밀 관리와 조회 권한을 함께 관리 | 가장 낮음 — 교체를 AWS가 처리 | 사용자 수명주기 관리가 새로 생김 |
| 주체 추적 | 공유 키 하나 — 구분 불가 | 공유 키 하나 — 구분 불가 | 역할 세션 단위로 구분 | 사람 단위 구분(기계는 미해결) |
| 판정 | 오답 — 문제를 미룰 뿐 | 오답 — 이 시나리오에서는 과잉이자 미해결 | 선택 | 범위가 다름 — 별도로 추진 |
B안이 왜 정답이 아닌가
AWS Secrets Manager는 좋은 서비스이고 자동 교체까지 지원합니다. 그러나 이 시나리오에서는 부트스트랩 문제를 만듭니다. 인스턴스가 비밀을 읽으려면 그 자체로 자격 증명이 필요한데, 그 자격 증명을 인스턴스에 주는 올바른 방법이 결국 IAM 역할입니다. 역할을 붙일 수 있다면 처음부터 S3 권한을 역할에 주면 되고, 중간에 액세스 키를 둘 이유가 사라집니다.
Secrets Manager가 정답이 되는 자리는 따로 있습니다 — AWS가 발급하지 않는 자격 증명, 예를 들어 데이터베이스 사용자 비밀번호나 외부 서비스의 API 키입니다. 그 구분은 16장 보안 · 암호화 · 거버넌스에서 다룹니다.
선택과 근거
C안 — IAM 역할을 만들어 인스턴스 프로파일로 연결합니다. 근거는 세 가지입니다.
- 회수 지점이 한 곳으로 모입니다. 역할이 발급하는 자격 증명은 만료되므로, 역할의 권한 정책을 줄이거나 신뢰 정책을 끊으면 그 시점 이후 호출이 전부 막힙니다. 디스크에 흩어진 복사본을 찾아다닐 필요가 없습니다.
- 사람이 키를 옮기는 절차가 사라집니다. 재발 방지는 절차를 잘 지키게 만드는 것이 아니라 절차를 없애는 것으로 달성됩니다.
- 코드를 고치지 않습니다. AWS SDK와 AWS CLI의 기본 자격 증명 체인이 인스턴스 메타데이터를 조회하므로, 애플리케이션은 자격 증명을 명시적으로 다루지 않아도 됩니다.
전환 순서 — 순서를 틀리면 서비스가 멈춘다
제약 2(무중단) 때문에 순서가 설계의 일부입니다. 키 비활성화는 마지막이고, 자격 증명 파일 제거는 역할 연결 다음입니다.
| 순서 | 작업 | 무엇을 확인하고 다음으로 넘어가는가 |
|---|---|---|
| 1 | 필요한 버킷과 동작만 허용하는 권한 정책으로 역할을 만든다 | 정책 시뮬레이터나 스테이징에서 필요한 동작이 전부 허용되는지 |
| 2 | 인스턴스 프로파일을 만들어 역할을 넣고, 실행 중인 인스턴스에 연결한다 | 인스턴스 안에서 역할 자격 증명이 조회되는지 |
| 3 | AMI와 인스턴스에서 공유 자격 증명 파일과 환경 변수를 제거한다 | 호출 주체가 IAM 사용자가 아니라 수임한 역할로 바뀌었는지 |
| 4 | 시작 템플릿을 새 AMI로 갱신하고 인스턴스를 교체한다 | 새로 뜬 인스턴스가 키 없이 정상 동작하는지 |
| 5 | 액세스 키를 먼저 비활성화하고, 관측 기간을 둔 뒤 삭제한다 | 비활성화 후에도 실패한 호출이 없는지 CloudTrail로 확인 |
# 전환 전: IAM 사용자 ARN 이 나온다 (아직 파일의 키를 쓰고 있다)
# 전환 후: assumed-role 형태의 ARN 이 나와야 한다
aws sts get-caller-identity --query 'Arn' --output text
# arn:aws:sts::123456789012:assumed-role/ImageWorkerRole/i-0123456789abcdef0
역할과 인스턴스 프로파일 구성
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": { "Service": "ec2.amazonaws.com" },
"Action": "sts:AssumeRole"
}
]
}
aws iam create-role \
--role-name ImageWorkerRole \
--assume-role-policy-document file://trust-policy.json
aws iam put-role-policy \
--role-name ImageWorkerRole \
--policy-name ImageBucketAccess \
--policy-document file://permissions-policy.json
aws iam create-instance-profile \
--instance-profile-name ImageWorkerProfile
aws iam add-role-to-instance-profile \
--instance-profile-name ImageWorkerProfile \
--role-name ImageWorkerRole
# 실행 중인 인스턴스에 연결합니다. 재부팅은 필요하지 않습니다.
aws ec2 associate-iam-instance-profile \
--instance-id i-0123456789abcdef0 \
--iam-instance-profile Name=ImageWorkerProfile
권한 정책은 요구된 버킷과 동작만 남깁니다.
AmazonS3FullAccess를 그대로 옮겨 붙이면 사고 범위가 그대로 유지됩니다.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ReadSourceObjects",
"Effect": "Allow",
"Action": ["s3:GetObject"],
"Resource": "arn:aws:s3:::example-image-source/*"
},
{
"Sid": "WriteDerivedObjects",
"Effect": "Allow",
"Action": ["s3:PutObject"],
"Resource": "arn:aws:s3:::example-image-derived/*"
}
]
}
메타데이터 경로 잠그기 — IMDSv2 강제
역할로 바꾸면 자격 증명이 인스턴스 메타데이터 서비스(IMDS)를 통해 전달됩니다. 즉 메타데이터 엔드포인트가 새로운 회수 대상이 됩니다. 애플리케이션에 서버 측 요청 위조(SSRF) 취약점이 있으면 공격자가 애플리케이션을 시켜 메타데이터를 읽게 만들 수 있기 때문입니다.
IMDSv2는 먼저 PUT으로 세션 토큰을 받고,
그 토큰을 헤더에 실은 요청만 응답하는 방식입니다.
단순히 URL을 대신 호출하게 만드는 전형적인 SSRF로는 토큰 발급 단계를 통과할 수 없습니다.
여기에 홉 제한을 1로 두면 컨테이너처럼 한 단계 더 떨어진 곳에서의 접근도 막힙니다.
# 개별 인스턴스에 IMDSv2 를 강제합니다.
aws ec2 modify-instance-metadata-options \
--instance-id i-0123456789abcdef0 \
--http-tokens required \
--http-endpoint enabled \
--http-put-response-hop-limit 1
# 이후 시작되는 인스턴스의 계정 수준 기본값으로 IMDSv2 를 요구합니다.
aws ec2 modify-instance-metadata-defaults \
--http-tokens required
비용과 운영에 미치는 영향
이 전환은 아키텍처를 바꾸지 않으므로 컴퓨팅이나 스토리지 사용량은 그대로입니다. 달라지는 것은 운영 항목의 개수입니다.
| 항목 | 전환 전 | 전환 후 |
|---|---|---|
| 추가되는 과금 리소스 | 없음 | 없음 — 역할과 인스턴스 프로파일은 리소스를 새로 띄우지 않는다 |
| B안을 골랐다면 | — | 비밀 저장과 조회 API 호출이 새로운 과금 항목이 된다. 얻는 것 없이 항목만 늘어난다 |
| 정기 작업 | 키 교체, 배포 파이프라인 갱신, 교체 실패 대응 | 없음 — 자격 증명 교체를 AWS가 처리한다 |
| 사고 대응 시간 | 복사본 추적에 상한이 없다 | 역할 권한 변경 한 번으로 종료된다 |
| 감사 | 공유 키 하나 — 주체 구분 불가 | 역할 세션 이름으로 인스턴스까지 좁혀진다 |
예방 체크리스트
새 워크로드를 설계할 때와, 기존 워크로드를 점검할 때 각각 확인합니다. 체크 상태는 저장되지 않으므로 점검용으로만 씁니다.
설계할 때
점검할 때
# 계정의 모든 IAM 사용자에 대해 액세스 키와 생성 시각, 상태를 나열합니다.
for u in $(aws iam list-users --query 'Users[].UserName' --output text); do
aws iam list-access-keys --user-name "$u" \
--query 'AccessKeyMetadata[].[UserName,AccessKeyId,Status,CreateDate]' \
--output text
done
# 회수는 삭제가 아니라 비활성화부터 시작합니다.
aws iam update-access-key \
--user-name image-worker \
--access-key-id AKIAEXAMPLEEXAMPLE \
--status Inactive
관련 시험 포인트
| 문제문의 신호 | 고르는 것 | 소거하는 것 |
|---|---|---|
| EC2가 다른 AWS 서비스를 호출해야 한다 | IAM 역할 + 인스턴스 프로파일 | 액세스 키를 사용자 데이터·환경 변수·AMI에 넣는 안 |
| 교차 계정으로 접근해야 한다 | 대상 계정에 역할을 만들고 sts:AssumeRole |
대상 계정의 IAM 사용자 키를 발급해 전달하는 안 |
| 자격 증명을 주기적으로 교체해야 한다 | 가능하면 역할. 데이터베이스 비밀번호 등은 Secrets Manager | 자체 교체 스크립트를 만드는 안(운영 부담 한정어와 충돌) |
| SSRF로 메타데이터가 노출된다 | IMDSv2 필수화, 홉 제한 조정 | 메타데이터 엔드포인트를 보안 그룹으로 차단하는 안(링크 로컬 주소라 성립하지 않는다) |
| 모바일 앱이 AWS 리소스를 직접 호출해야 한다 | Amazon Cognito 자격 증명 풀로 임시 자격 증명 교환 | 앱에 액세스 키를 포함하는 안 |
한정어별 선호 선택지는 한정어 키워드 사전에, 헷갈리는 쌍은 함정 사전에 모여 있습니다.
이어서 볼 곳
- 2장 · IAM과 자격 증명 역할이 신뢰 정책과 권한 정책 두 축으로 이루어진다는 구조, 그리고 정책 평가 로직을 정면으로 다룹니다.
- 5장 · EC2와 컴퓨트 인스턴스 메타데이터와 IMDSv2의 동작, 사용자 데이터가 어디에 저장되는지 확인합니다.
- 케이스 4 · 퍼블릭 서브넷에 데이터베이스를 뒀다 자격 증명이 아니라 네트워크 경계에서 같은 종류의 노출이 어떻게 생기는지 비교해 봅니다.
- 케이스 10 · 규정 준수 감사에 대응하라 CloudTrail과 AWS Config로 이런 사고를 사후가 아니라 상시로 잡아내는 구성입니다.
- 보안 아키텍처 설계 (30%) 가중치가 가장 큰 도메인의 과제 진술 3개와 출제 포인트를 정리했습니다.
- 실습 11 · KMS 고객 관리형 키로 암호화 키 정책과 IAM 정책이 함께 작동하는 방식을 직접 만들어 확인합니다.
공식 문서 출처
- IAM 사용 설명서 — IAM 역할 — 역할이 신뢰 정책과 권한 정책으로 구성되고 임시 자격 증명을 발급한다는 정의
- IAM 사용 설명서 — EC2 인스턴스에서 실행되는 애플리케이션에 역할 사용 — 인스턴스 프로파일이 역할을 인스턴스에 전달하는 매개체라는 설명
- Amazon EC2 사용 설명서 — EC2용 IAM 역할 — 실행 중인 인스턴스에 인스턴스 프로파일을 연결·교체할 수 있다는 서술
- IAM 사용 설명서 — 액세스 키 관리 — 키의 비활성화와 삭제 구분, 사용 기록 확인 방법
- IAM 사용 설명서 — 보안 모범 사례 — 장기 자격 증명 대신 임시 자격 증명을 쓰라는 권고와 최소 권한 원칙
- Amazon EC2 사용 설명서 — 인스턴스 메타데이터 서비스 구성
— IMDSv2의 토큰 기반 2단계 요청과
HttpTokens설정 - Amazon EC2 사용 설명서 — 인스턴스 메타데이터 옵션
— 홉 제한(
HttpPutResponseHopLimit)의 의미와 계정 수준 기본값 - Amazon EC2 사용 설명서 — 인스턴스 메타데이터와 사용자 데이터 — 메타데이터 엔드포인트를 통해 역할 자격 증명이 전달된다는 설명
- IAM 사용 설명서 — 정책 평가 로직 — 명시적 거부가 모든 허용을 이긴다는 우선순위