권한(Day1)과 네트워크(Day2)로 "누가 접근하고 어디로 흐르는가"를 통제했다면, 오늘은 데이터와 모델 그 자체를 암호화로 보호한다. 암호화는 데이터가 어디 있느냐로 갈린다.
구분
저장 중 암호화 (at rest)
전송 중 암호화 (in transit)
보호 대상
디스크·스토리지에 "가만히 있는" 데이터
네트워크를 "이동 중인" 데이터
ML의 대표 자산
S3 학습 데이터, EBS/로컬 볼륨, 모델 아티팩트
S3↔컨테이너, 분산 학습 노드 간, 엔드포인트 호출
구현 수단
KMS 키 (SSE-KMS, VolumeKmsKeyId)
TLS/HTTPS, EnableInterContainerTrafficEncryption
막는 위협
디스크·스냅샷·버킷 유출
도청, 중간자
놓치기 쉬운 점
스토리지 권한과 별개로 키 사용 권한이 필요
노드 간 암호화는 기본이 아니라 명시 설정
[데이터 흐름과 암호화 지점]S3(at-rest, SSE-KMS) ──TLS──▶ 학습 컨테이너 │ EBS/로컬 볼륨 (at-rest, VolumeKmsKeyId) │ 노드 간 (in-transit, inter-container 암호화) ▼S3 모델 아티팩트(at-rest, OutputDataConfig KmsKeyId) ▼엔드포인트 볼륨(at-rest, EndpointConfig KmsKeyId) ──HTTPS──▶ 클라이언트
암호화는 "데이터가 멈춰 있을 때"와 "움직일 때" 둘 다 막아야 완전하다. 저장 중 암호화는 디스크를 누가 훔쳐가도 못 읽게 하고, 전송 중 암호화는 네트워크를 도청해도 못 읽게 한다. 규제(HIPAA, PCI 등)는 거의 항상 둘 다 요구한다. 시험에서 "at-rest만"이나 "in-transit만" 보기는 보통 불완전한 답이다.
AWS KMS는 암호화 키를 만들고 관리하는 서비스다. SageMaker의 거의 모든 암호화는 "어떤 KMS 키를 쓸지" 지정하는 방식으로 동작한다. 키는 두 종류고, 어느 쪽을 고르느냐가 갈림길이다.
항목
AWS 관리형 키 (aws/sagemaker 등)
고객 관리형 키 (CMK)
생성 주체
서비스가 계정 안에 자동 생성
내가 직접 생성·명명
키 정책 편집
불가
가능 — 누가 쓸 수 있는지 직접 통제
교차 계정 공유
불가
가능 (키 정책으로 다른 계정 허용)
비활성화·삭제
불가
가능 → crypto-shredding
감사
CloudTrail에 사용 기록
CloudTrail + 키 단위 접근 통제
고르는 순간
기본 암호화만 빠르게 필요할 때
규제·감사·교차 계정·키 통제가 요구될 때
CMK의 진짜 가치는 "키 정책으로 접근을 통제하고, 키를 끄면 데이터가 잠긴다"는 점이다. 데이터 자체를 지우지 않아도 키 접근만 끊으면 사실상 데이터를 못 읽게 만들 수 있다(crypto-shredding). 또 키 사용 내역이 CloudTrail에 남아 "누가 언제 이 데이터를 복호화했는가"를 감사할 수 있다. 이게 AWS 관리형 키 대비 CMK를 쓰는 핵심 이유다.
KMS는 큰 데이터를 직접 암호화하지 않는다(봉투 암호화). GenerateDataKey로 받은 일회용 데이터 키로 데이터를 암호화하고, 그 데이터 키는 KMS 키로 감싸 함께 보관한다. 읽을 때는 Decrypt로 데이터 키부터 푼다. 권한이 둘로 갈리는 이유다 — 쓸 때 kms:GenerateDataKey, 읽을 때 kms:Decrypt.
암호화된 S3 데이터를 학습이 읽으려면, 실행 역할이 KMS 키로 복호화할 권한(kms:Decrypt)이 있어야 한다. 그리고 암호화된 출력을 쓰려면 kms:GenerateDataKey가 필요하다. 이게 빠지면 "S3 권한은 줬는데 KMS 때문에 Access Denied"가 난다 — 자주 놓치는 함정이다.
학습 컨테이너 ──(1) 실행 역할로 s3:GetObject──▶ S3 객체 (SSE-KMS) │ (2) 객체에 붙은 "암호화된 데이터 키"를 풀어야 본문을 읽는다 ▼ KMS 키 문 A: IAM 정책 ── 실행 역할에 kms:Decrypt 가 붙어 있는가? 문 B: 키 정책 ── 이 키가 그 역할(또는 그 계정)을 허용하는가? → 둘 다 통과해야 성공. 하나라도 막히면 AccessDeniedException (KMS가 거부한 것)
KMS 접근은 "양쪽 문"을 통과해야 한다 — IAM 정책(역할에 kms 액션 허용)과 키 정책(키가 그 역할을 허용). 둘 중 하나만 있으면 거부된다. S3 권한은 멀쩡한데 암호화 데이터 읽기가 실패하면 거의 항상 KMS 권한 문제다. 시험에서 "S3는 줬는데 왜 안 되나"의 정답이 kms:Decrypt 누락인 경우가 많다.
⚠️ 함정: SSE-KMS는 객체를 읽고 쓸 때마다 KMS 호출이 일어난다. 학습 데이터가 작은 파일 수백만 개면 KMS 요청 요금·스로틀링이 실제 문제가 된다. 답은 암호화 해제가 아니라 S3 Bucket Keys 활성화(버킷 수준 키 재사용으로 KMS 호출 감소)와 파일 병합이다.
실행 역할에는 secretsmanager:GetSecretValue 권한(특정 시크릿 ARN으로 제한)과, 시크릿이 CMK로 암호화돼 있으면 그 키의 kms:Decrypt가 필요하다.
비밀을 하이퍼파라미터나 환경변수로 넘기는 것도 하드코딩만큼 위험하다. 하이퍼파라미터는 describe_training_job 응답에 그대로 드러나고, 로그에 찍히면 CloudWatch Logs에 평문으로 남는다. 비밀은 런타임에 API로 가져와 메모리에서만 쓴다.
Secrets Manager vs Parameter Store는 헷갈리기 쉬운 비교다. 핵심 차이는 "자동 회전"이다 — DB 비밀번호처럼 주기적 회전이 필요하면 Secrets Manager, 단순 설정값이나 토큰이면 Parameter Store(SecureString)로 비용을 아낀다. 공통점은 "비밀을 코드 밖에 두고 런타임에 가져온다"이다. 하드코딩된 자격증명을 본 상황은 거의 항상 이 둘 중 하나가 정답이다.