
환경 변수와 12-Factor App: 시크릿 관리의 정석
API 키를 GitHub에 올려서 털려본 적 있나요? 환경 변수의 개념부터 보안 사고를 막기 위한 시크릿 관리 전략, 그리고 Docker/K8s 환경에서의 주입 패턴까지. 12-Factor App 방법론에 입각한 설정 관리의 모든 것을 정리합니다.

API 키를 GitHub에 올려서 털려본 적 있나요? 환경 변수의 개념부터 보안 사고를 막기 위한 시크릿 관리 전략, 그리고 Docker/K8s 환경에서의 주입 패턴까지. 12-Factor App 방법론에 입각한 설정 관리의 모든 것을 정리합니다.
프론트엔드 개발자가 알아야 할 4가지 저장소의 차이점과 보안 이슈(XSS, CSRF), 그리고 언제 무엇을 써야 하는지에 대한 명확한 기준.

Debug에선 잘 되는데 Release에서만 죽나요? 범인은 '난독화'입니다. R8의 원리, Mapping 파일 분석, 그리고 Reflection을 사용하는 라이브러리를 지켜내는 방법(@Keep)을 정리해봤습니다.

서버를 끄지 않고 배포하는 법. 롤링, 카나리, 블루-그린의 차이점과 실제 구축 전략. DB 마이그레이션의 난제(팽창-수축 패턴)와 AWS CodeDeploy 활용법까지 심층 분석합니다.

새벽엔 낭비하고 점심엔 터지는 서버 문제 해결기. '택시 배차'와 '피자 배달' 비유로 알아보는 오토 스케일링과 서버리스의 차이, 그리고 Spot Instance를 활용한 비용 절감 꿀팁.

제 인생 최악의 실수는 첫 프로젝트를 GitHub에 올린 날 일어났습니다.
AWS_ACCESS_KEY를 코드 안에 그대로 박아놓고 커밋해버린 것입니다.
정확히 30분 뒤, 아마존에서 이메일이 왔습니다. "당신의 계정이 비정상적인 활동을 감지했습니다."
들어가 보니 누군가 제 계정으로 시가 500만 원어치의 채굴용 인스턴스를 돌리고 있었습니다.
이게 바로 우리가 환경 변수(Environment Variables)를 써야 하는 가장 강력한 이유입니다. 코드(Code)와 설정(Config)은 반드시 분리되어야 합니다. 코드는 Git에 올라가 전 세계에 공유되지만, 설정(비밀번호, API 키)은 절대 공개되면 안 되기 때문입니다.
초보자가 자주 하는 실수는 환경 변수가 어디서 오는지 헷갈리는 것입니다. Node.js나 Python 앱이 실행될 때, 변수는 여러 곳에서 주입될 수 있습니다. 우선순위는 보통 다음과 같습니다 (아래로 갈수록 덮어씀):
/etc/environment 등에 설정된 전역 변수dotenv 라이브러리로 로드하는 파일export API_KEY=abc로 설정한 값API_KEY=abc node server.js 처럼 실행 시 앞에 붙이는 값팁: 로컬 개발할 때는 .env.local 같은 파일을 써서 Git이 추적하지 않게 하고, 팀원들과 공유해야 할 기본값은 .env.example에 넣어두는 것이 국룰입니다.
회사가 커지고 마이크로서비스(MSA)를 도입하면 새로운 지옥이 열립니다. 바로 Secret Sprawl(시크릿 확산)입니다.
서비스가 100개면 DB 비밀번호도 100군데에 흩어져 있습니다.
개발자 A의 로컬 PC .env 파일에, 개발자 B의 슬랙 DM에, 심지어 노션 문서 어딘가에 비밀번호가 평문으로 돌아다닙니다.
이것을 막기 위해 GitGuardian 같은 도구를 CI 파이프라인에 심어둬야 합니다.
누군가 실수로 커밋에 비밀번호 형태의 문자열(예: sk_live_...)을 포함시키면, 커밋 자체를 막아버리는(Pre-commit Hook) 것입니다.
"실수하고 나서 수습"하는 게 아니라 "실수 자체를 못 하게" 막아야 합니다.
요즘은 서버에 직접 들어가서 .env 파일을 수정하지 않습니다. 컨테이너 환경이기 때문이죠.
docker run 명령어를 쓸 때 -e 옵션을 줍니다.
docker run -e DB_PASSWORD=secret my-app
하지만 변수가 많으면 --env-file .env 옵션으로 파일 통째로 주입합니다.
쿠버네티스에서는 ConfigMap과 Secret 리소스를 사용합니다.
Pod를 띄울 때 이 Secret을 환경 변수로 주입(Injection)해서 사용합니다. 애플리케이션 입장에서는 이게 파일에서 왔는지, K8s가 넣어줬는지 알 필요가 없습니다. 그냥 process.env로 읽으면 되니까요. 이것이 바로 인프라 독립적인(Infrastructure Agnostic) 애플리케이션 설계입니다.
모던 애플리케이션 배포의 바이블인 The 12-Factor App에서는 설정을 이렇게 정의합니다.
"설정을 코드에서 엄격하게 분리하라. 코드는 지금 당장 오픈소스로 공개해도 아무런 문제가 없어야 한다."
만약 코드를 GitHub에 올리기 전에 "잠깐, 이 파일 지워야 해"라고 생각한다면, 당신은 원칙을 어긴 것입니다. 설정은 배포 환경(Development, Staging, Production)에 따라 달라지는 모든 것을 말합니다. 데이터베이스 주소, 외부 서비스 URL, 캐시 설정 등이 여기에 속합니다. 이 모든 것을 환경 변수로 관리해야만, 빌드된 아티팩트(Docker Image) 하나를 가지고 여러 환경에 똑같이 배포(Build Once, Deploy Anywhere)할 수 있습니다.
프로덕션 환경에서는 환경 변수조차 위험할 수 있습니다.
DevOps 엔지니어가 docker inspect 명령어를 치면 환경 변수가 평문으로 다 보이기 때문입니다.
그리고 데이터베이스 비밀번호를 3개월마다 바꿔야 한다면? 수많은 서버를 다 재시작해야 할까요?
그래서 대규모 시스템에서는 AWS Secrets Manager나 HashiCorp Vault 같은 전용 시크릿 저장소를 씁니다.
이 방식의 장점은 자동 로테이션(Rotation)이 가능하다는 것입니다. AWS가 알아서 DB 비밀번호를 바꾸고, 애플리케이션은 API로 바뀐 비밀번호를 받아오면 되니까, 서버 중단 없이 보안을 강화할 수 있습니다.
React나 Next.js 같은 프론트엔드 개발 시 주의할 점이 있습니다.
브라우저로 전송되는 자바스크립트 번들에는 비밀이 있을 수 없습니다.
REACT_APP_API_KEY나 NEXT_PUBLIC_ANALYTICS_ID 같은 변수들은 빌드 타임(Build Time)에 코드에 치환(Replacement)되어 들어갑니다.
개발자 도구(F12)를 열어서 소스 코드를 보면 다 보입니다.
그러니 프론트엔드 환경 변수에는 절대 "AWS Secret Key" 같은 걸 넣으면 안 됩니다. 오직 "공개되어도 상관없는 정보(Public Key, API URL)"만 넣어야 합니다.
Q: 실수로 .env 파일을 GitHub에 올려버렸어요. 지우면 되나요?
A: 아니요! 커밋을 revert 하거나 파일을 지워도, Git의 커밋 히스토리(history)에는 영원히 남아있습니다. 해커들은 이 히스토리를 뒤집니다.
반드시 BFG Repo-Cleaner 같은 도구로 히스토리 자체를 세탁하거나, 더 안전하게는 노출된 모든 키를 폐기(Revoke)하고 재발급 받아야 합니다. 키를 바꾸는 게 가장 확실한 방법입니다.
Q: 프로덕션 환경에서도 .env 파일을 쓰면 안 되나요?
A: 써도 되지만 권장하지 않습니다. .env 파일은 파일 시스템에 평문으로 존재하므로, 서버가 해킹당하면 바로 털립니다. AWS Param Store나 Secrets Manager 같은 주입식 방식을 쓰는 것이 훨씬 안전합니다.
Q: ENV_VAR vs config.json 중 뭐가 낫나요?
A: config.json은 구조화된 데이터를 표현하기 좋지만, 배포 환경마다 파일을 따로 만들어야 하므로 관리가 복잡합니다. 반면 환경 변수는 어디서든 오버라이드하기 쉬워서 Docker/K8s 환경 표준입니다. 12-Factor App을 따른다면 환경 변수가 정답입니다.