AWS Secrets Manager: Python Lambda에서 비밀을 설정하고 가져오는 방법

발행: (2025년 12월 19일 오후 03:52 GMT+9)
6 분 소요
원문: Dev.to

Source: Dev.to

민감한 정보(예: 데이터베이스 비밀번호, API 키, 토큰 등)를 관리하는 것은 안전한 클라우드 애플리케이션을 구축하는 데 있어 중요한 부분입니다. 소스 코드나 설정 파일에 비밀을 하드코딩하는 것은 흔히 발생하는 안티패턴으로, 보안 취약점을 초래합니다.

AWS Secrets Manager는 런타임에 비밀을 동적으로 저장하고 검색할 수 있는 안전하고 확장 가능하며 감사 가능한 방법을 제공합니다. 이 글에서는 다음 내용을 다룹니다:

  • AWS Secrets Manager가 무엇인지
  • 비밀을 생성하고 저장하는 방법
  • 필요한 IAM 권한
  • Python AWS Lambda에서 비밀을 가져오는 방법
  • 모범 사례

1. AWS Secrets Manager란 무엇인가?

AWS Secrets Manager는 다음을 도와주는 관리형 서비스입니다:

  • 비밀(자격 증명, API 키, 토큰)을 안전하게 저장
  • AWS KMS를 사용하여 비밀을 암호화
  • IAM을 통해 접근 제어
  • 지원되는 서비스에 대해 비밀을 자동으로 교체
  • 런타임에 프로그래밍 방식으로 비밀을 검색

일반적인 사용 사례:

  • 데이터베이스 자격 증명 (RDS, Aurora)
  • 타사 API 키
  • JWT 서명 비밀
  • OAuth 클라이언트 비밀

2. AWS Secrets Manager에서 비밀 생성

단계 1: AWS Secrets Manager 열기

  1. AWS 콘솔에 로그인합니다.
  2. Secrets Manager 로 이동합니다.
  3. Store a new secret 를 클릭합니다.

단계 2: 비밀 유형 선택

맞춤형 키/값 쌍을 저장하려면 Other type of secret 을 선택합니다. 예시:

DB_USERNAME = admin
DB_PASSWORD = StrongPassword@123
DB_HOST     = mydb.cluster-xyz.us-east-1.rds.amazonaws.com

Secrets Manager는 이러한 값을 암호화된 JSON 형태로 저장합니다.

단계 3: 암호화 구성

  • 기본 AWS 관리형 KMS 키를 선택하거나, 또는
  • 보다 엄격한 규정 준수를 위해 고객 관리형 KMS 키를 선택합니다.

단계 4: 비밀 이름 지정

예시와 같이 명확하고 환경을 구분할 수 있는 이름을 지정합니다:

  • myapp/dev/database
  • myapp/staging/database
  • myapp/prod/database

이러한 명명 전략은 실수로 다른 환경에 접근하는 것을 방지합니다.

단계 5: 검토 및 생성

Store 를 클릭합니다. 이제 비밀이 안전하게 저장되었습니다.

3. Lambda에 대한 IAM 권한

Lambda 함수는 비밀을 읽을 수 있는 권한이 있어야 합니다.

IAM 정책 예시

다음 정책을 Lambda 실행 역할에 연결하십시오:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "secretsmanager:GetSecretValue"
      ],
      "Resource": "arn:aws:secretsmanager:us-east-1:123456789012:secret:myapp/dev/database*"
    }
  ]
}

중요: Resource"*" 대신 특정 비밀에만 제한하도록 항상 설정하십시오.

4. Python Lambda에서 비밀 가져오기

단계 1: Python 종속성

AWS Lambda에는 이미 boto3botocore가 포함되어 있습니다. 추가 라이브러리는 필요하지 않습니다.

단계 2: 비밀을 가져오는 Python 코드

import json
import boto3
from botocore.exceptions import ClientError

def get_secret(secret_name, region_name="us-east-1"):
    client = boto3.client(
        service_name="secretsmanager",
        region_name=region_name
    )

    try:
        response = client.get_secret_value(SecretId=secret_name)
    except ClientError as e:
        raise RuntimeError(f"Unable to retrieve secret: {e}")

    # Secrets are usually stored as JSON strings
    if "SecretString" in response:
        return json.loads(response["SecretString"])
    else:
        # Binary secrets (rare case)
        return response["SecretBinary"]

단계 3: Lambda 핸들러에서 비밀 사용

def lambda_handler(event, context):
    secret_name = "myapp/dev/database"

    secrets = get_secret(secret_name)

    db_user = secrets["DB_USERNAME"]
    db_password = secrets["DB_PASSWORD"]
    db_host = secrets["DB_HOST"]

    # Example usage
    print(f"Connecting to DB at {db_host} with user {db_user}")

    return {
        "statusCode": 200,
        "body": "Secrets fetched successfully"
    }

5. 성능 고려 사항 (중요)

GetSecretValue에 대한 각 호출은 네트워크 호출입니다. 지연 시간과 API 사용량을 줄이기 위해 모듈 수준에서 비밀을 캐시하세요:

_cached_secrets = None

def get_cached_secret(secret_name):
    global _cached_secrets
    if _cached_secrets is None:
        _cached_secrets = get_secret(secret_name)
    return _cached_secrets

6. 환경 기반 비밀 관리

환경 변수를 사용하여 어떤 비밀이 로드될지 제어합니다:

import os

secret_name = os.environ["SECRET_NAME"]   # e.g., myapp/dev/database
secrets = get_cached_secret(secret_name)

이렇게 하면:

  • DEV / STAGE / PROD 전반에 동일한 코드베이스
  • 환경별 비밀
  • 보다 안전한 배포

7. Security and Best Practices

  • 절대로 비밀을 하드코딩하지 마세요.
  • 최소 권한 IAM 정책을 사용하세요.
  • 환경별로 별도의 비밀을 유지하세요.
  • 지원되는 경우 자동 회전을 활성화하세요.
  • 성능을 위해 Lambda 내부에 비밀을 캐시하세요.
  • 로그를 신중하게 남기세요—비밀 값을 절대 로그에 남기지 마세요.
  • 매우 민감한 데이터는 SSM Parameter Store보다 Secrets Manager를 선호하세요.
Back to Blog

관련 글

더 보기 »