Chapter 11

Secrets Manager 비밀 관리

"DB 비밀번호를 .env 파일이 아닌 안전한 금고에 보관하자"

학습 목표

  • Secrets Manager에 DB 자격 증명을 저장할 수 있다
  • IAM 역할에 Secrets Manager 접근 권한을 부여할 수 있다
  • EC2에서 AWS CLI로 비밀 값을 조회할 수 있다
  • 비밀번호 자동 교체(로테이션)의 개념과 필요성을 이해할 수 있다
Chapter 11 - Secrets Manager 아키텍처
EC2 (API 서버)
Node.js :5000
IAM Role: ShopEasy-EC2-Role
↓ secretsmanager:GetSecretValue
Secrets Manager
ShopEasy/DB
DB 자격 증명 암호화 저장
↓ 비밀번호 조회 후 DB 접속
RDS MySQL
shopeasy-db (Private Subnet)
ap-northeast-2

왜 Secrets Manager가 필요한가?

현재 ShopEasy API 서버는 DB 접속 정보를 .env 파일에 평문으로 저장하고 있습니다.

env
# .env 파일 (현재 상태 - 위험!)
DB_TYPE=mysql
DB_HOST=shopeasy-db.xxxx.ap-northeast-2.rds.amazonaws.com
DB_PORT=3306
DB_USER=admin
DB_PASSWORD=ShopEasy2024!
DB_NAME=ecommerce

이 방식의 문제점

  • Git 커밋 유출: 실수로 .env 파일을 Git에 커밋하면 비밀번호가 공개 저장소에 노출됩니다
  • 서버 침해: EC2 서버가 해킹되면 .env 파일을 읽어 DB에 직접 접근할 수 있습니다
  • 비밀번호 변경 어려움: 비밀번호를 바꾸려면 모든 서버의 .env 파일을 수동으로 수정해야 합니다
  • 감사 불가: 누가 언제 비밀번호를 조회했는지 추적할 수 없습니다
비유로 이해하기: .env 파일 vs Secrets Manager

.env 파일에 비밀번호를 저장하는 것은 포스트잇에 비밀번호를 적어 모니터에 붙여두는 것과 같습니다. 누구나 지나가면서 볼 수 있고, 복사할 수 있으며, 누가 봤는지 알 수 없습니다.

반면 Secrets Manager는 잠금장치가 달린 금고와 같습니다. 열쇠(IAM 권한)가 있는 사람만 열 수 있고, 금고를 열 때마다 CCTV(CloudTrail)에 기록이 남습니다. 게다가 금고 안의 비밀번호를 자동으로 주기적으로 교체해주는 기능까지 있습니다.

Secrets Manager 동작 원리

기존 방식 vs Secrets Manager 방식

기존 방식: 앱 시작 → .env 파일에서 비밀번호 읽기 → DB 접속

Secrets Manager 방식: 앱 시작 → Secrets Manager API 호출 → 비밀번호 받기 → DB 접속

코드나 파일에 비밀번호가 존재하지 않으므로, 서버가 침해되어도 비밀번호가 바로 노출되지 않습니다. API 호출에는 IAM 권한이 필요하기 때문입니다.

핵심 특징

특징 설명
암호화 저장 비밀 값은 KMS 키로 암호화되어 저장됩니다. 평문으로 디스크에 저장되지 않습니다
접근 제어 IAM 정책으로 누가 어떤 비밀에 접근할 수 있는지 세밀하게 제어합니다
감사 추적 CloudTrail을 통해 모든 비밀 조회/변경 기록이 남습니다
자동 교체 Lambda 함수를 연결하면 비밀번호를 자동으로 주기적으로 변경합니다
버전 관리 비밀 값이 변경될 때 이전 버전을 유지하여, 교체 중에도 서비스가 중단되지 않습니다

비용 구조

항목 비용 설명
비밀 저장 $0.40 / 비밀 / 월 저장된 비밀 1개당 월 $0.40
API 호출 $0.05 / 10,000건 GetSecretValue 등 API 호출 건수 기준
비용 참고

비밀 1개를 저장하고 하루 100번 조회한다면, 월 비용은 약 $0.42입니다 ($0.40 + 3,000건 × $0.05/10,000). DB 자격 증명 유출로 인한 피해 비용에 비하면 매우 저렴한 보험입니다.

실습: Secrets Manager 구성

사전 준비
  • Chapter 04에서 만든 IAM Role (ShopEasy-EC2-Role)이 EC2에 연결되어 있어야 합니다
  • Chapter 03에서 만든 RDS MySQL 인스턴스가 실행 중이어야 합니다
  • EC2에 SSH 접속이 가능해야 합니다
Hands-on Lab
  1. Secrets Manager에 DB 비밀번호 저장

    RDS MySQL 접속에 필요한 자격 증명을 Secrets Manager에 저장합니다.

    • 비밀 이름: ShopEasy/DB
    • 비밀 유형: 다른 유형의 보안 암호 (키/값 쌍)
    • 저장할 키/값:
      • host: RDS 엔드포인트
      • port: 3306
      • username: admin
      • password: ShopEasy2024!
      • dbname: ecommerce
    • 암호화 키: aws/secretsmanager (기본 KMS 키)
    비밀 이름 규칙

    ShopEasy/DB처럼 슬래시(/)로 계층 구조를 만들면 관리가 편합니다. 나중에 ShopEasy/API-Key, ShopEasy/Redis 등으로 확장할 수 있습니다.

    AWS 콘솔 → Secrets Manager → 새 보안 암호 저장 → 보안 암호 유형: "다른 유형의 보안 암호" 선택 → 키/값 쌍에 host, port, username, password, dbname을 각각 입력 → 다음 → 보안 암호 이름: ShopEasy/DB 입력 → 다음 → 교체 구성은 건너뛰기 → 저장

  2. IAM 역할에 Secrets Manager 권한 추가

    EC2가 Secrets Manager에서 비밀 값을 조회할 수 있도록 ShopEasy-EC2-Role에 권한을 추가합니다.

    • 정책 이름: ShopEasy-SecretsManager-Access
    • 허용 액션: secretsmanager:GetSecretValue
    • 리소스: ShopEasy/DB 비밀의 ARN (특정 비밀만 허용)
    최소 권한 원칙

    secretsmanager:*로 모든 권한을 주지 마세요. GetSecretValue 액션만, ShopEasy/DB 비밀에만 허용하는 것이 보안 모범 사례입니다. 다른 비밀이나 비밀 삭제/수정 권한은 EC2에 필요하지 않습니다.

    IAM 콘솔 → 역할 → ShopEasy-EC2-Role → 권한 추가 → 인라인 정책 생성 → JSON 편집기에서 정책 작성 → 정책 이름: ShopEasy-SecretsManager-Access → 정책 생성. Resource에는 Secrets Manager 콘솔에서 확인한 비밀 ARN을 넣되, 끝에 *를 붙입니다 (Secrets Manager가 자동으로 랜덤 접미사를 추가하기 때문).

  3. EC2에서 비밀 값 조회 테스트

    EC2에 SSH로 접속한 후, AWS CLI를 사용하여 Secrets Manager에서 비밀 값을 정상적으로 조회할 수 있는지 테스트합니다.

    bash
    # EC2 접속
    ssh -i your-key.pem ec2-user@{EC2_PUBLIC_IP}
    
    # Secrets Manager에서 비밀 값 조회
    aws secretsmanager get-secret-value \
      --secret-id ShopEasy/DB \
      --region ap-northeast-2

    응답의 SecretString 필드에 JSON 형식의 DB 자격 증명이 포함되어 있으면 성공입니다.

    보기 좋게 출력하기

    --query SecretString --output text | python3 -m json.tool을 추가하면 비밀 값만 깔끔한 JSON 형식으로 볼 수 있습니다.

    AccessDeniedException이 발생하면 Step 2의 IAM 정책이 올바르게 설정되었는지 확인하세요. 정책의 Resource ARN이 실제 비밀 ARN과 일치하는지, 그리고 EC2에 IAM Role이 연결되어 있는지 확인합니다.

  4. 비밀번호 교체(로테이션) 개념 이해

    Secrets Manager의 가장 강력한 기능 중 하나인 자동 비밀번호 교체(Auto Rotation)의 개념을 이해합니다.

    자동 교체(Auto Rotation)란?

    비밀번호를 주기적으로 자동 변경하는 기능입니다. Secrets Manager가 Lambda 함수를 호출하여 다음 작업을 자동으로 수행합니다:

    1. 새 비밀번호 생성: 강력한 랜덤 비밀번호를 만듭니다
    2. DB 비밀번호 변경: RDS에 접속하여 비밀번호를 새 값으로 변경합니다
    3. 비밀 값 업데이트: Secrets Manager에 저장된 비밀번호를 새 값으로 교체합니다
    4. 테스트: 새 비밀번호로 DB 접속이 되는지 확인합니다

    왜 비밀번호 교체가 중요한가?

    • 유출 시 피해 최소화: 비밀번호가 유출되더라도, 자동 교체로 인해 유효 기간이 제한됩니다 (예: 30일마다 교체)
    • 컴플라이언스 준수: PCI-DSS, HIPAA 등 보안 규정은 정기적인 비밀번호 변경을 요구합니다
    • 수동 작업 제거: 관리자가 비밀번호를 직접 변경하고 모든 서버에 반영하는 번거로움이 없습니다
    자동 교체 흐름
    Secrets Manager
    교체 일정 트리거
    (예: 30일마다)
    ↓ Lambda 호출
    Lambda (교체 함수)
    1. 새 비밀번호 생성
    2. RDS 비밀번호 변경
    3. Secrets Manager 업데이트
    4. 접속 테스트
    ↓ 비밀번호 변경
    RDS MySQL
    새 비밀번호 적용
    이번 실습에서는 교체를 구현하지 않습니다

    자동 교체에는 Lambda 함수 설정, VPC 네트워크 구성 등 추가 작업이 필요합니다. 이번 실습에서는 개념을 이해하는 것이 목표이며, 실제 구현은 하지 않습니다. 프로덕션 환경에서는 반드시 자동 교체를 활성화하는 것을 권장합니다.

확인 사항

아래 항목을 모두 완료했는지 체크하세요:

  • Secrets Manager에 ShopEasy/DB 비밀이 생성되었다
  • 비밀에 host, port, username, password, dbname 키/값 쌍이 포함되어 있다
  • ShopEasy-EC2-RoleShopEasy-SecretsManager-Access 정책이 추가되었다
  • 정책에 secretsmanager:GetSecretValue 액션만 허용되어 있다
  • 정책의 Resource가 ShopEasy/DB 비밀 ARN으로 제한되어 있다
  • EC2에서 aws secretsmanager get-secret-value 명령이 정상 동작한다
  • 응답의 SecretString에 올바른 DB 자격 증명이 포함되어 있다
  • 자동 교체(로테이션) 개념을 이해했다