Chapter 10 - 강사용 답안

KMS 데이터 암호화

"데이터를 금고에 넣자 - 저장된 데이터를 암호화하여 보호하기"

강사 전용 문서

이 문서는 강사용 답안입니다. 학생에게 공유하지 마세요. 각 단계의 정확한 답과 해설, 트러블슈팅 가이드가 포함되어 있습니다.

Step 1: RDS 암호화 상태 확인

답안

웹 콘솔 방법

  1. AWS 콘솔에서 RDS 서비스로 이동
  2. 좌측 메뉴에서 데이터베이스 클릭
  3. ShopEasy RDS 인스턴스 (예: shopeasy-db) 클릭
  4. 구성(Configuration) 탭 클릭
  5. 스토리지 섹션에서 암호화 항목 확인:
    • 활성화됨: 스토리지가 암호화되어 있음 (KMS 키 ARN도 표시됨)
    • 비활성화됨: 스토리지가 암호화되지 않음

AWS CLI 방법

bash
# RDS 인스턴스의 암호화 상태 확인
aws rds describe-db-instances \
  --query "DBInstances[?DBInstanceIdentifier=='shopeasy-db'].{ID:DBInstanceIdentifier,Encrypted:StorageEncrypted,KmsKey:KmsKeyId}" \
  --output table \
  --region ap-northeast-2

# 또는 모든 RDS 인스턴스의 암호화 상태 한번에 확인
aws rds describe-db-instances \
  --query "DBInstances[].{ID:DBInstanceIdentifier,Engine:Engine,Encrypted:StorageEncrypted,KmsKey:KmsKeyId}" \
  --output table \
  --region ap-northeast-2

정상 출력 예시 (암호화된 경우):

text
-------------------------------------------------------------------------------------
|                            DescribeDBInstances                                    |
+-------------+-----------+--------------------------------------------------------+
|  Encrypted  |    ID     |                        KmsKey                          |
+-------------+-----------+--------------------------------------------------------+
|  True       | shopeasy-db | arn:aws:kms:ap-northeast-2:123456789012:key/xxxx-xxxx |
+-------------+-----------+--------------------------------------------------------+

암호화되지 않은 경우:

text
--------------------------------------
|       DescribeDBInstances          |
+-------------+-----------+----------+
|  Encrypted  |    ID     | KmsKey   |
+-------------+-----------+----------+
|  False      | shopeasy-db | None   |
+-------------+-----------+----------+
해설: 암호화되지 않은 RDS를 암호화하는 방법

이미 생성된 암호화되지 않은 RDS 인스턴스에는 암호화를 직접 활성화할 수 없습니다. 다음 과정을 거쳐야 합니다:

  1. 스냅샷 생성: 현재 DB 인스턴스의 수동 스냅샷을 생성
  2. 암호화된 스냅샷 복사: 스냅샷을 복사하면서 암호화 옵션을 활성화
  3. 새 인스턴스 복원: 암호화된 스냅샷에서 새 DB 인스턴스를 복원
  4. 엔드포인트 변경: 애플리케이션의 DB 연결 엔드포인트를 새 인스턴스로 교체
  5. 기존 인스턴스 삭제: 확인 후 기존 비암호화 인스턴스 삭제
bash
# [참고용] 암호화되지 않은 RDS를 암호화하는 CLI 과정
# (이번 실습에서는 실행하지 않습니다)

# 1. 스냅샷 생성
aws rds create-db-snapshot \
  --db-instance-identifier shopeasy-db \
  --db-snapshot-identifier shopeasy-db-snapshot-for-encryption \
  --region ap-northeast-2

# 2. 스냅샷 생성 완료 대기
aws rds wait db-snapshot-available \
  --db-snapshot-identifier shopeasy-db-snapshot-for-encryption \
  --region ap-northeast-2

# 3. 암호화된 스냅샷으로 복사
aws rds copy-db-snapshot \
  --source-db-snapshot-identifier shopeasy-db-snapshot-for-encryption \
  --target-db-snapshot-identifier shopeasy-db-snapshot-encrypted \
  --kms-key-id alias/aws/rds \
  --region ap-northeast-2

# 4. 복사 완료 대기
aws rds wait db-snapshot-available \
  --db-snapshot-identifier shopeasy-db-snapshot-encrypted \
  --region ap-northeast-2

# 5. 암호화된 스냅샷에서 새 인스턴스 복원
aws rds restore-db-instance-from-db-snapshot \
  --db-instance-identifier shopeasy-db-encrypted \
  --db-snapshot-identifier shopeasy-db-snapshot-encrypted \
  --region ap-northeast-2

주의: 이 과정은 새 인스턴스를 생성하므로 엔드포인트가 변경됩니다. 또한 다운타임이 발생하며, 추가 비용이 들 수 있습니다. 이번 실습에서는 상태 확인만 수행하고, 실제 변환은 하지 않습니다.

실무 교훈

RDS 인스턴스를 처음 생성할 때 반드시 암호화를 활성화해야 합니다. 나중에 변경하려면 매우 번거롭고 다운타임이 발생합니다. AWS CloudFormation이나 Terraform 등 IaC 도구에서 StorageEncrypted: true를 기본 템플릿에 포함시키는 것이 좋습니다.

Step 2: S3 버킷 기본 암호화 설정

답안

웹 콘솔 방법

  1. AWS 콘솔에서 S3 서비스로 이동
  2. shopeasy-images-{ACCOUNT_ID} 버킷 클릭
  3. 속성(Properties) 탭 클릭
  4. 기본 암호화(Default encryption) 섹션으로 스크롤
  5. 편집 클릭
  6. 암호화 유형 설정:
    • 방법 A (SSE-S3): "Amazon S3 관리형 키(SSE-S3)" 선택 → 암호화 알고리즘: AES-256
    • 방법 B (SSE-KMS): "AWS Key Management Service 키(SSE-KMS)" 선택 → AWS 관리형 키: aws/s3
  7. 버킷 키: 활성화 (SSE-KMS 선택 시 KMS API 호출 비용 절감)
  8. 변경 사항 저장 클릭

AWS CLI 방법

방법 A: SSE-S3 (AES-256) 설정

bash
# 계정 ID 확인
ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)

# S3 버킷에 SSE-S3 기본 암호화 설정
aws s3api put-bucket-encryption \
  --bucket shopeasy-images-${ACCOUNT_ID} \
  --server-side-encryption-configuration '{
    "Rules": [{
      "ApplyServerSideEncryptionByDefault": {
        "SSEAlgorithm": "AES256"
      },
      "BucketKeyEnabled": true
    }]
  }'

# 설정 확인
aws s3api get-bucket-encryption \
  --bucket shopeasy-images-${ACCOUNT_ID}

방법 B: SSE-KMS (aws/s3 키) 설정

bash
# S3 버킷에 SSE-KMS 기본 암호화 설정
aws s3api put-bucket-encryption \
  --bucket shopeasy-images-${ACCOUNT_ID} \
  --server-side-encryption-configuration '{
    "Rules": [{
      "ApplyServerSideEncryptionByDefault": {
        "SSEAlgorithm": "aws:kms",
        "KMSMasterKeyID": "alias/aws/s3"
      },
      "BucketKeyEnabled": true
    }]
  }'

# 설정 확인
aws s3api get-bucket-encryption \
  --bucket shopeasy-images-${ACCOUNT_ID}

정상 출력 예시 (SSE-S3의 경우):

json
{
  "ServerSideEncryptionConfiguration": {
    "Rules": [
      {
        "ApplyServerSideEncryptionByDefault": {
          "SSEAlgorithm": "AES256"
        },
        "BucketKeyEnabled": true
      }
    ]
  }
}
해설: 기본 암호화의 동작 방식

S3 버킷의 기본 암호화를 설정하면, 업로드 시 암호화 헤더를 지정하지 않은 객체에도 자동으로 서버 측 암호화가 적용됩니다.

  • 이미 업로드된 기존 객체에는 소급 적용되지 않습니다 (새로 업로드되는 객체부터 적용)
  • 업로드 시 명시적으로 다른 암호화를 지정하면 기본 설정보다 우선됩니다
  • BucketKeyEnabled: true는 SSE-KMS 사용 시 S3 버킷 키를 생성하여 KMS API 호출 횟수를 줄여 비용을 절감합니다
프론트엔드 버킷에도 적용하기 (선택)

shopeasy-frontend-{ACCOUNT_ID} 버킷에도 동일하게 기본 암호화를 설정할 수 있습니다. 프론트엔드 파일(HTML, CSS, JS)은 공개 콘텐츠이지만, 저장 데이터 암호화는 보안 모범 사례입니다.

bash
# 프론트엔드 버킷에도 SSE-S3 기본 암호화 설정
aws s3api put-bucket-encryption \
  --bucket shopeasy-frontend-${ACCOUNT_ID} \
  --server-side-encryption-configuration '{
    "Rules": [{
      "ApplyServerSideEncryptionByDefault": {
        "SSEAlgorithm": "AES256"
      },
      "BucketKeyEnabled": true
    }]
  }'

Step 3: DynamoDB 암호화 확인

답안

웹 콘솔 방법

  1. AWS 콘솔에서 DynamoDB 서비스로 이동
  2. 좌측 메뉴에서 테이블 클릭
  3. Reviews 테이블 클릭
  4. 추가 설정(Additional settings) 탭 클릭
  5. 암호화(Encryption) 섹션 확인:
    • 암호화 유형: "Amazon DynamoDB가 소유" (기본값) 또는 "AWS 관리형 키" 또는 "고객 관리형 키"
    • 기본값인 "Amazon DynamoDB가 소유"는 AWS 소유 키를 사용하는 것을 의미합니다

AWS CLI 방법

bash
# DynamoDB Reviews 테이블의 암호화 상태 확인
aws dynamodb describe-table \
  --table-name Reviews \
  --query "Table.SSEDescription" \
  --region ap-northeast-2

출력 결과 해석:

text
# 경우 1: AWS 소유 키 사용 (기본값)
# SSEDescription이 null로 반환됩니다
null

# 경우 2: AWS 관리형 키 (aws/dynamodb) 사용
{
  "Status": "ENABLED",
  "SSEType": "KMS",
  "KMSMasterKeyArn": "arn:aws:kms:ap-northeast-2:123456789012:key/xxxx-xxxx"
}

# 경우 3: 고객 관리형 키 사용
{
  "Status": "ENABLED",
  "SSEType": "KMS",
  "KMSMasterKeyArn": "arn:aws:kms:ap-northeast-2:123456789012:key/yyyy-yyyy"
}
해설: SSEDescription이 null인 경우

CLI에서 SSEDescriptionnull로 반환되면, 이는 암호화가 안 되어 있다는 의미가 아닙니다. DynamoDB의 기본 암호화인 AWS 소유 키를 사용하고 있다는 뜻입니다.

DynamoDB는 모든 데이터를 항상 암호화합니다. SSEDescription에 값이 있는 경우는 기본 AWS 소유 키 대신 KMS 관리형 키 또는 고객 관리형 키를 명시적으로 선택한 경우뿐입니다.

DynamoDB 암호화 키 유형별 비교
키 유형 비용 CloudTrail 감사 키 관리
AWS 소유 키 (기본값) 무료 불가 AWS가 완전 관리
AWS 관리형 키 (aws/dynamodb) 무료 가능 AWS가 관리, 사용자가 확인 가능
고객 관리형 키 (CMK) $1/월 + API 호출 가능 사용자가 직접 관리

Step 4: KMS 키 확인

답안

웹 콘솔 방법

  1. AWS 콘솔에서 KMS (Key Management Service) 서비스로 이동
  2. 좌측 메뉴에서 AWS 관리형 키 클릭
  3. 다음과 같은 키 목록이 표시됩니다 (사용한 서비스에 따라 다름):
    • aws/rds - RDS 암호화에 사용되는 키
    • aws/s3 - S3 SSE-KMS 암호화에 사용되는 키
    • aws/dynamodb - DynamoDB KMS 암호화에 사용되는 키
    • aws/ebs - EBS 볼륨 암호화에 사용되는 키
  4. 각 키를 클릭하면 키 ID, ARN, 생성 날짜, 키 정책 등을 확인할 수 있습니다
  5. 좌측 메뉴에서 고객 관리형 키를 클릭하면 직접 생성한 키 목록을 확인할 수 있습니다 (이번 실습에서는 없을 수 있음)

AWS CLI 방법

bash
# AWS 관리형 키 목록 확인 (aws/로 시작하는 별칭)
aws kms list-aliases \
  --query "Aliases[?contains(AliasName,'aws/')].[AliasName,TargetKeyId]" \
  --output table \
  --region ap-northeast-2

정상 출력 예시:

text
--------------------------------------------------------------
|                        ListAliases                         |
+-------------------+----------------------------------------+
|  aws/dynamodb     |  abcd1234-5678-90ef-ghij-klmnopqrstuv  |
|  aws/ebs          |  bcde2345-6789-01fg-hijk-lmnopqrstuvw  |
|  aws/rds          |  cdef3456-7890-12gh-ijkl-mnopqrstuvwx  |
|  aws/s3           |  defg4567-8901-23hi-jklm-nopqrstuvwxy  |
+-------------------+----------------------------------------+
bash
# 모든 별칭(alias) 목록 확인 (관리형 + 고객 관리형)
aws kms list-aliases \
  --query "Aliases[].[AliasName,TargetKeyId]" \
  --output table \
  --region ap-northeast-2

# 특정 키의 상세 정보 확인 (예: aws/s3)
aws kms describe-key \
  --key-id alias/aws/s3 \
  --query "KeyMetadata.{KeyId:KeyId,KeyState:KeyState,KeyManager:KeyManager,CreationDate:CreationDate,Description:Description}" \
  --region ap-northeast-2

# 고객 관리형 키만 확인
aws kms list-keys \
  --region ap-northeast-2 \
  --query "Keys[].KeyId" \
  --output table
해설: KMS 키가 보이지 않는 경우

AWS 관리형 키는 해당 서비스에서 암호화를 처음 사용할 때 자동으로 생성됩니다.

  • aws/rds가 없다면: 아직 RDS에서 KMS 암호화를 사용한 적이 없음
  • aws/s3가 없다면: 아직 S3에서 SSE-KMS를 사용한 적이 없음 (SSE-S3는 KMS를 사용하지 않음)
  • aws/dynamodb가 없다면: DynamoDB에서 AWS 관리형 키를 선택한 적이 없음 (기본 AWS 소유 키는 KMS 콘솔에 표시되지 않음)

키가 보이지 않는 것은 정상입니다. 이번 실습에서 S3에 SSE-KMS를 설정했다면 aws/s3 키가 새로 생성되어 있을 것입니다.

강사 참고: 키 유형 요약 정리
서비스 기본 암호화 사용되는 키 비용
RDS 생성 시 선택 (기본: 비활성화) aws/rds (선택 시) 무료
S3 (SSE-S3) 2023.01~ 자동 적용 S3 자체 관리 키 무료
S3 (SSE-KMS) 수동 설정 aws/s3 무료 (관리형 키)
DynamoDB 항상 활성화 (비활성화 불가) AWS 소유 키 (기본) 무료

트러블슈팅 가이드

자주 발생하는 문제와 해결 방법

KMS 콘솔에 "AWS 관리형 키"가 하나도 보이지 않는다

원인: 아직 해당 리전에서 KMS 암호화를 사용하는 서비스를 한 번도 사용하지 않았음

해결 방법:

  1. 리전이 ap-northeast-2 (서울)로 설정되어 있는지 확인
  2. AWS 관리형 키는 해당 서비스에서 암호화를 처음 사용할 때 자동 생성됩니다
  3. Step 2에서 S3 버킷에 SSE-KMS를 설정하면 aws/s3 키가 생성됩니다
  4. 키가 없어도 정상 - 서비스를 사용하면 자동으로 만들어집니다
S3 기본 암호화 설정 시 "Access Denied" 에러

원인: IAM 사용자에게 S3 또는 KMS 관련 권한이 부족

해결 방법:

  1. 현재 로그인한 IAM 사용자의 권한을 확인합니다
  2. s3:PutEncryptionConfiguration 권한이 필요합니다
  3. SSE-KMS를 설정하는 경우 kms:DescribeKey, kms:GenerateDataKey 권한도 필요합니다
bash
# 현재 사용자 확인
aws sts get-caller-identity

# S3 버킷 암호화 설정 권한 테스트
aws s3api get-bucket-encryption \
  --bucket shopeasy-images-${ACCOUNT_ID}
RDS 암호화 상태가 "비활성화"로 표시된다

원인: RDS 인스턴스 생성 시 암호화 옵션을 선택하지 않았음

해결 방법:

  1. 이것은 정상적인 상황입니다 (이전 챕터에서 암호화 없이 생성한 경우)
  2. 이미 생성된 인스턴스에는 직접 암호화를 켤 수 없습니다
  3. 실습에서는 상태 확인 후 "스냅샷 복사 방식으로 암호화 적용 가능"이라는 개념만 이해하면 됩니다
  4. 시간과 비용이 허락한다면 Step 1의 해설에 있는 스냅샷 방식으로 변환 가능합니다
DynamoDB describe-table 결과에 SSEDescription이 null이다

원인: DynamoDB가 기본 AWS 소유 키를 사용하고 있음 (정상)

해결 방법:

  1. 이것은 정상적인 결과입니다
  2. DynamoDB는 항상 암호화되어 있습니다 (비활성화 불가)
  3. SSEDescription이 null이면 기본 AWS 소유 키를 사용한다는 의미입니다
  4. AWS 관리형 키(aws/dynamodb)나 고객 관리형 키를 명시적으로 설정한 경우에만 값이 표시됩니다
bash
# DynamoDB 테이블 전체 정보 확인
aws dynamodb describe-table \
  --table-name Reviews \
  --region ap-northeast-2 \
  --query "Table.{Name:TableName,Status:TableStatus,SSE:SSEDescription}"

# 출력 예시 (기본 암호화 - 정상):
# {
#   "Name": "Reviews",
#   "Status": "ACTIVE",
#   "SSE": null        <-- null이지만 암호화는 되어 있음!
# }
S3 암호화 설정 후 기존 객체는 암호화되지 않는다

원인: S3 기본 암호화는 설정 이후 새로 업로드되는 객체에만 적용됨

해결 방법:

  1. 기본 암호화 설정은 새로 업로드되는 객체에만 자동 적용됩니다
  2. 기존 객체를 암호화하려면 해당 객체를 다시 업로드(덮어쓰기)해야 합니다
  3. S3 Batch Operations 또는 aws s3 cp 명령으로 일괄 처리 가능합니다
bash
# 기존 객체를 SSE-S3로 다시 암호화 (동일 위치에 복사)
aws s3 cp \
  s3://shopeasy-images-${ACCOUNT_ID}/ \
  s3://shopeasy-images-${ACCOUNT_ID}/ \
  --recursive \
  --sse AES256

# 특정 객체의 암호화 상태 확인
aws s3api head-object \
  --bucket shopeasy-images-${ACCOUNT_ID} \
  --key uploads/test-image.png \
  --query "ServerSideEncryption"
SSE-KMS 설정 후 S3 객체 접근 시 "AccessDenied" 에러

원인: EC2 IAM Role에 KMS 키 사용 권한이 없음

해결 방법:

  1. SSE-KMS로 암호화된 객체를 읽으려면 해당 KMS 키에 대한 kms:Decrypt 권한이 필요합니다
  2. AWS 관리형 키(aws/s3)를 사용하는 경우, 동일 계정 내에서는 보통 자동으로 권한이 있습니다
  3. 문제가 지속되면 SSE-S3(AES-256)으로 변경하세요 - SSE-S3는 별도 KMS 권한이 필요 없습니다
bash
# SSE-S3로 변경 (KMS 권한 문제 회피)
aws s3api put-bucket-encryption \
  --bucket shopeasy-images-${ACCOUNT_ID} \
  --server-side-encryption-configuration '{
    "Rules": [{
      "ApplyServerSideEncryptionByDefault": {
        "SSEAlgorithm": "AES256"
      },
      "BucketKeyEnabled": true
    }]
  }'
강사 참고: 학생들이 자주 혼동하는 포인트
  1. DynamoDB SSEDescription이 null = 암호화 안됨? - 아닙니다! AWS 소유 키로 항상 암호화되어 있습니다. null은 기본 키를 사용한다는 의미입니다.
  2. S3 기본 암호화 = 기존 파일도 자동 암호화? - 아닙니다. 기본 암호화는 새로 업로드되는 객체에만 적용됩니다. 기존 객체는 별도 작업이 필요합니다.
  3. RDS 암호화를 나중에 켤 수 있나요? - 직접 켤 수 없습니다. 스냅샷 → 암호화 복사 → 복원 과정이 필요합니다. 처음부터 암호화를 켜는 것이 중요합니다.
  4. SSE-S3와 SSE-KMS 중 어떤 것을 선택? - 특별한 규제 요구사항이 없다면 SSE-S3(AES-256)으로 충분합니다. CloudTrail 감사 로그가 필요하면 SSE-KMS를 사용하세요.
  5. 암호화하면 성능이 떨어지나요? - AWS 서비스의 서버 측 암호화는 성능에 거의 영향을 주지 않습니다. AWS가 하드웨어 수준에서 최적화하기 때문입니다.