환경변수와 시크릿
환경변수와 시크릿
.env 파일과 환경변수는 입문 단계에서 자주 마주치는 개념. 이 글은 두 개념의 출자 · 동작 · 시크릿 관리 도구를 사실 기준으로 정리합니다.
1. 환경변수와 .env 의 출자
환경변수 (environment variable) 는 프로세스가 운영체제에서 읽는 키-값 쌍. Unix 계열은 getenv(3), Windows 는 GetEnvironmentVariable 로 접근. 셸의 export FOO=bar (bash) 또는 $env:FOO = "bar" (PowerShell) 가 자식 프로세스에 전달.
.env 파일은 환경변수의 키-값을 텍스트 파일로 적어 두고, 라이브러리가 읽어 프로세스 환경에 주입하는 관습. 명시적으로 정의된 표준은 없고, 사실상 표준은 두 갈래로:
- dotenv (Node.js, motdotla/dotenv, 2013) — Brandon Keepers 가 처음 만들고 Scott Motte 가 이어 받음.
KEY=value줄을 읽어process.env에 채움. BSD-2. - python-dotenv (2014) — Saurabh Kumar 가 시작. Python 의
os.environ에 동일 동작.
12-Factor App 방법론 (Adam Wiggins, Heroku, 2011) 의 III. Config 절이 "config 는 환경에 저장하라" 고 정리하면서 이 패턴이 널리 굳어짐.
환경변수가 선택된 이유:
- 언어 / OS 비종속 표준.
- 코드 저장소에 실수로 들어갈 가능성이 낮음.
- 배포마다 독립적으로 관리.
2. 어떻게 동작하는가
런타임에 .env 가 환경에 들어가는 흐름:
- 라이브러리 (
dotenv·python-dotenv· Vite · Next.js 등) 가 시작 시 파일을 읽음. - 줄 단위로 파싱 (따옴표 · 공백 · 주석 처리) 하고
process.env·os.environ에 set. - 이미 OS 환경에 같은 키가 있으면 보통 덮어쓰지 않음 (라이브러리 · 옵션에 따라 다름).
런타임이 알아서 읽는 경우:
- Next.js —
.env.local·.env.development·.env.production자동 로드.NEXT_PUBLIC_접두는 클라이언트 번들에 포함, 그 외는 서버에서만. - Vite —
.env자동 로드,VITE_접두만 클라이언트로 노출. - Docker Compose —
env_file:또는--env-file로 컨테이너에 주입.
3. 환경별 분리 관습
| 파일 | 의도 |
|---|---|
.env |
모든 환경의 공통값. 커밋 가능 여부는 팀 정책. |
.env.local |
로컬 개발자 머신 전용. 보통 git 무시. |
.env.development / .env.production |
환경별 기본값. |
.env.example |
키 목록만 적어 둔 템플릿. 새 개발자에게 어떤 변수를 채워야 하는지 알림. |
4. 시크릿 관리 도구
진짜 시크릿 (외부 API 키 · DB 비밀번호) 과 빌드 설정 (공개 URL · 기능 플래그) 은 다르게 관리하는 편이 좋다는 의견이 흔함.
- HashiCorp Vault (2015) — 셀프 호스트 가능한 시크릿 매니저. 동적 비밀번호 발급 · 짧은 수명 토큰.
- AWS Secrets Manager · GCP Secret Manager · Azure Key Vault — 클라우드 매니지드.
- SOPS (Mozilla, 2017 OSS) — 파일을 KMS / age / PGP 키로 암호화해 그대로 git 에 커밋.
git diff가능한 구조라 GitOps 와 잘 맞음. - 1Password CLI (
op) — 1Password vault 의 시크릿을 셸에서 환경변수로 주입. - Doppler · Infisical — 시크릿 매니저 SaaS. CLI 로
.env를 대체. - GitHub Actions Secrets — CI 한정 시크릿.
.env 를 그대로 운영에 쓰는 환경, .env 는 개발만 두고 운영은 시크릿 매니저로 가는 환경, 둘 다 흔합니다. 팀 규모 · 규제 · 운영 인력에 따라 적합한 쪽이 달라집니다.
5. 자주 쓰는 모양
.env.example (커밋):
DATABASE_URL=postgres://user:pass@localhost:5432/app
SMTP_HOST=
SMTP_USER=
SMTP_PASS=
JWT_SECRET=replace-me
Node 측 사용:
import 'dotenv/config';
console.log(process.env.DATABASE_URL);
Python 측 사용:
from dotenv import load_dotenv
import os
load_dotenv()
db_url = os.environ["DATABASE_URL"]
셸에서 직접:
# macOS · Linux
export FOO=bar
echo $FOO
unset FOO
# Windows PowerShell
$env:FOO = "bar"
echo $env:FOO
Remove-Item Env:FOO
6. 자주 걸리는 자리
.env 무심코 커밋 — 시크릿이 git 히스토리에 들어가는 사고. 발견 시 키 회전이 가장 안전. git filter-repo 같은 도구는 히스토리를 다시 쓰지만 이미 클론한 사람이 있으면 노출은 사라지지 않음.
키 충돌 — OS 환경에 같은 이름의 변수가 이미 있으면 라이브러리에 따라 .env 값이 무시될 수 있음. dotenv 의 override 옵션 같은 동작을 미리 확인.
줄바꿈 · 따옴표 — 멀티라인 PEM 키를 .env 에 넣을 때 따옴표 · \n 처리가 라이브러리마다 다름. 공식 문서 예시를 따름.
클라이언트 번들 노출 — 프런트엔드 빌드 도구는 특정 접두 (NEXT_PUBLIC_ · VITE_) 만 노출한다고는 하지만, 결과 번들에 들어간 값은 사용자에게 평문 노출. 진짜 시크릿은 클라이언트 변수에 두지 않음.
".env 는 커밋해도 되나" — 팀 정책. 평문 시크릿이 들어 있다면 일반적으로 커밋하지 않고, 의도적으로 평문 설정만 담기로 한 팀이라면 커밋. 어느 쪽이든 정책을 명확히 적어 두는 편이 사고를 줄임.
하고픈 말
환경변수는 12-Factor App 의 III. Config 절이 정리한 단순하고 강력한 표준. .env 의 진짜 시크릿은 git 에 들어가지 않게 하고, 시크릿 매니저 (Vault · SOPS · 1Password) 를 도입하면 운영 안전성이 한 단계 올라감. 클라이언트 번들에는 진짜 시크릿이 절대 안 들어가도록 (접두 규칙은 빌드 도구의 도움일 뿐).
Next
- version-managers
- git-workflow
dotenv (Node.js) GitHub · python-dotenv 공식 문서 · HashiCorp Vault 공식 문서 · Mozilla SOPS · The Twelve-Factor App III. Config · OWASP Secrets Management Cheat Sheet · GitGuardian State of Secrets Sprawl 를 참고합니다.