환경 변수와 시크릿 관리, 어디까지 해야 하나

2026. 10. 24. 13:00·IT
728x90
반응형

데이터베이스 비밀번호를 어디에 두는지 물어보면 답이 제각각이다. .env 파일, 도커 이미지 안, 배포 스크립트, 심지어 저장소 안에 커밋된 설정 파일까지 나온다. 이 글은 시크릿을 다루는 단계별 기준과, 사고가 났을 때 무엇을 해야 하는지를 정리한다.

설정과 시크릿은 다르다

먼저 구분이 필요하다. 둘을 같이 다루면 규칙이 흐려진다.

설정은 환경마다 다른 값이지만 노출돼도 피해가 없는 것이다. API 기본 URL, 로그 레벨, 타임아웃, 기능 플래그 같은 것들이다. 저장소에 넣어도 된다.

시크릿은 노출되면 피해가 생기는 것이다. 데이터베이스 비밀번호, API 키, 서명 키, 인증서 개인키, OAuth 클라이언트 시크릿.

기준은 단순하다. 이 값을 슬랙 공개 채널에 붙여넣어도 괜찮은가. 안 된다면 시크릿이다.

절대 하면 안 되는 것부터

순서대로 위험한 것들이다.

저장소에 커밋하는 것. 가장 흔하고 가장 위험하다. 나중에 지워도 Git 히스토리에 남는다. 저장소를 클론한 사람 누구나 꺼낼 수 있고, 공개 저장소였다면 자동 스캐너가 이미 수집했다. 실제로 공개 저장소의 키는 몇 분 안에 악용된다.

도커 이미지에 넣는 것. COPY .env .나 ENV DB_PASSWORD=...는 이미지 레이어에 그대로 남는다. 이미지를 받을 수 있는 누구나 볼 수 있다. 나중 레이어에서 지워도 앞 레이어에 남는다.

빌드 인자로 넘기는 것. --build-arg로 넘긴 값은 docker history에 보인다.

로그에 찍는 것. 앞서 로깅 글에서 다룬 내용이지만, 요청 본문이나 설정 객체를 통째로 로그에 남기면 시크릿이 따라간다.

CI 로그에 노출되는 것. 환경 변수를 출력하는 디버깅 코드를 남겨두면 CI 로그에 찍힌다. CI 로그는 대개 접근 권한이 넓다.

단계별로 올라가는 관리 방법

조직 규모와 요구 수준에 따라 선택지가 다르다.

1단계는 로컬 개발용이다. .env를 만들고 .gitignore에 반드시 넣는다. 그리고 .env.example을 만들어 커밋한다. 키 이름만 있고 값은 비어 있는 파일이다. 새로 합류한 사람이 무엇을 채워야 하는지 알 수 있다.

DATABASE_URL=
REDIS_URL=
STRIPE_API_KEY=

2단계는 배포 환경이다. 쿠버네티스 Secret, CI의 암호화된 변수, 클라우드 콘솔의 환경 변수 설정을 쓴다. 애플리케이션은 여전히 환경 변수로 읽으므로 코드는 그대로다.

쿠버네티스 Secret은 기본적으로 base64 인코딩일 뿐 암호화가 아니다. etcd 암호화를 켜고, RBAC으로 접근을 제한하고, Secret을 읽을 수 있는 대상을 좁혀야 한다. 이걸 안 하면 이름만 Secret이다.

3단계는 시크릿 매니저다. 값이 중앙에서 관리되고, 접근이 감사 로그에 남고, 회전이 가능하다. 애플리케이션이 시작할 때 받아오거나 사이드카가 주입한다.

4단계는 동적 자격 증명이다. 고정된 비밀번호 대신 요청할 때마다 짧은 수명의 자격 증명을 발급받는다. 유출돼도 곧 만료된다. 클라우드의 IAM 역할 기반 접근이 이 방식이다. 가장 좋은 시크릿은 존재하지 않는 시크릿이라는 관점이다.

유출됐을 때 해야 할 일

발견했을 때 순서가 중요하다. 많은 사람이 순서를 거꾸로 한다.

1. 먼저 회전한다. 해당 키를 즉시 무효화하고 새 키를 발급한다. 이게 최우선이다. 히스토리를 지우는 것이 아니다.

2. 그다음 정리한다. 코드에서 제거하고 커밋한다. Git 히스토리에서 지우는 것(filter-repo 등)은 선택이다. 이미 유출된 키는 회전했으므로 가치가 없다. 히스토리 재작성은 모든 클론을 무효화하므로 비용이 크다.

3. 악용 흔적을 확인한다. 해당 키로 이루어진 접근 로그를 본다. 언제부터 노출됐는지, 그 사이 비정상 접근이 있었는지 확인한다.

4. 재발을 막는다. 시크릿 스캐닝을 CI에 넣는다. 커밋 전 훅으로도 검사할 수 있다. 사람의 주의력에 기대는 대신 도구가 막게 한다.

개발 환경도 프로덕션만큼 조심해야 한다

마지막으로 자주 간과되는 지점이다. 개발 환경 자격 증명이라고 느슨하게 다루면 안 된다.

이유가 셋이다. 개발 환경이 프로덕션과 같은 네트워크에 있는 경우가 많다. 개발 데이터베이스에 프로덕션 데이터 복사본이 들어 있는 경우가 흔하다. 그리고 개발 키가 실수로 프로덕션에 배포되거나, 반대로 프로덕션 키가 개발용으로 복사되는 일이 생긴다.

그래서 환경별로 완전히 분리된 자격 증명을 쓰고, 개발 데이터베이스에는 실제 개인정보를 넣지 않는 것이 원칙이다. 테스트 데이터는 익명화해서 넣는다. 이 원칙이 지켜지면 개발 환경 유출이 사고로 번지지 않는다.

한 가지 더. 로컬 개발에서 시크릿을 아예 없애는 방법도 있다. 외부 서비스를 로컬 목(mock)이나 컨테이너로 대체하면 키가 필요 없다. 결제 API 대신 테스트 모드 키를, 이메일 발송 대신 로컬 SMTP 서버를 쓰는 식이다. 필요한 곳에만 시크릿이 있는 상태가 관리하기 가장 쉽다.

참고 자료

  • OWASP Secrets Management Cheat Sheet — 저장·전달·회전에 관한 실무 지침
  • Kubernetes: Secrets — Secret 의 실제 보호 수준과 etcd 암호화
  • The Twelve-Factor App: Config — 설정을 환경 변수로 분리하는 원칙
728x90
반응형

'IT' 카테고리의 다른 글

HTTP 상태 코드와 오류 응답 설계  (0) 2026.10.26
알림 피로를 줄이는 SLO 기반 모니터링  (0) 2026.10.25
메시지 큐를 언제 써야 하고 언제 쓰면 안 되나  (0) 2026.10.23
트랜잭션 격리 수준과 데드락 줄이기  (0) 2026.10.22
API 버저닝, 언제 올리고 언제 안 올리나  (0) 2026.10.21
'IT' 카테고리의 다른 글
  • HTTP 상태 코드와 오류 응답 설계
  • 알림 피로를 줄이는 SLO 기반 모니터링
  • 메시지 큐를 언제 써야 하고 언제 쓰면 안 되나
  • 트랜잭션 격리 수준과 데드락 줄이기
밍글링글링
밍글링글링
mingling - 밍글링, 밍글밍글링. 코드와 어우러지다. IT/ 프로그래밍/소스
    반응형
    250x250
  • 밍글링글링
    mingling
    밍글링글링
  • 전체
    오늘
    어제
    • 밍글링글링 (463)
      • Flutter (2)
      • 일상생활 (8)
        • 리뷰 (1)
        • 생활정보 (4)
        • 맛집 (0)
        • 여행 (0)
        • 모든정보 (3)
      • JAVA (126)
        • 개념 (6)
        • 예제 (115)
        • Exception (2)
      • C (1)
        • C (1)
        • C++ (0)
        • C# (0)
      • JS (29)
        • JavaScript (18)
        • JQuery (5)
        • AJax (0)
        • NODE.JS (6)
        • Angular.JS 2.0 (0)
      • WEB (87)
        • HTML (6)
        • CSS (61)
        • JSP (20)
        • JSTL (0)
      • FrameWork (8)
        • Spring (8)
        • BootStrap (0)
        • MyBATIS (0)
        • JUnit (0)
      • 외부 라이브러리 (5)
      • 공유 소스 관리 (5)
        • Git (5)
        • SVN (0)
      • 빅데이터 프로그래밍 (37)
        • Python (37)
        • R Programming (0)
      • DB (7)
        • ORACLE (0)
        • MySql (6)
      • Development Tools (7)
        • StarUML (0)
        • eXERD (0)
        • Eclipse (4)
      • SKILL (6)
        • Migration (0)
        • Security (6)
      • MicroSoft (0)
        • Excel (0)
        • Word (0)
      • Android (0)
      • Server (21)
        • Ubuntu (5)
        • Linux (15)
      • IOS (0)
      • XML (0)
      • 미디어 (0)
      • 공지사항 (3)
      • NETWORK (1)
      • 게임 (4)
        • 피파 (1)
        • 리니지M (0)
        • 배틀그라운드 (1)
        • 듀랑고 (2)
      • 세상 이슈 (6)
      • 일렉트론 (0)
      • 대회 소식 (4)
      • 업무 (2)
      • Express, Vue (6)
      • docker (11)
      • svelte (3)
      • 블록체인 (1)
      • IT (66)
      • Rust (0)
  • 블로그 메뉴

    • 홈
    • 태그
    • 미디어로그
    • 위치로그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    nginx
    러스트
    Java Array
    자바 배열
    lang rust
    Node
    Extension Bisect
    제미나이
    vscode
    ssl 인증서 발급
    에디터 팁
    자바 객체 지향
    servlet class
    자바 클래스
    css tb
    오류
    API 설계
    SSL 인증서
    nginx ssl 설정
    VS Code 팁
    프런트엔드
    브라우저 자동화
    css float
    proxy pass
    클론코딩
    React Compiler
    ubuntu
    css table
    docker
    자바 for문
    mysql db
    spring java
    svelte
    자바 생성자
    AI 반도체
    gitlab 설치
    jsp parameter
    java casting
    티스토리 자동화
    jsp include
    Rust lang
    리눅스 설치
    nginx ssl 적용
    AI 코딩 에이전트
    vue cli
    css transition
    css perspective
    자바 exception
    vue 설치
    rust linux
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.6
밍글링글링
환경 변수와 시크릿 관리, 어디까지 해야 하나
상단으로

티스토리툴바