# 환경 변수와 비밀 정보

> 비밀 값을 코드 밖으로 분리하고 .env와 .env.example로 관리한다.

관련 STEP: [STEP 04 되돌리기와 무시 규칙](https://echo.qus0in.dev/git/04-amend-ignore.md)

API 키, 액세스 토큰, 비밀번호는 코드에 그대로 적지 않고 환경 변수로 분리한다. 이 부록은 비밀 정보가 왜 위험한지, `.env` 파일을 어떻게 쓰고 숨기는지, 실수로 커밋했을 때 무엇을 먼저 해야 하는지 정리한다.

## 학습 목표

- 비밀 정보의 예를 구분한다.
- 코드에 값을 직접 적었을 때 생기는 문제를 설명한다.
- 환경 변수와 `.env` 파일의 역할을 안다.
- `.env.example`로 키 이름만 공유한다.
- 비밀 값이 노출됐을 때의 대응 순서를 안다.

## 왜 필요한가

코드에 API 키를 직접 적으면 그 값은 소스 파일과 커밋 이력에 함께 남는다. 저장소를 공개하면 누구나 볼 수 있고, 나중에 코드에서 지워도 이전 커밋에는 남을 수 있다. 비밀 값을 코드 밖으로 빼면 같은 코드를 여러 환경에서 실행하면서 값만 바꿀 수 있다.

## 핵심 개념

- 비밀 정보에는 API 키, 액세스 토큰, 비밀번호, 데이터베이스 접속 정보, 개인 키가 있다.
- 코드에 값을 직접 적는 것을 하드코딩이라고 한다. 하드코딩한 값은 커밋 이력에 남고, 공개 저장소·포크·캐시를 통해 노출될 수 있다.
- 환경 변수는 코드 밖에서 값을 넣어 주는 방식이다. 코드는 환경 변수 이름을 읽고, 실제 값은 실행 환경이나 `.env` 파일에 둔다.
- `.env` 파일은 `KEY=value` 형식으로 한 줄에 하나씩 적는다. `#`으로 시작하는 줄은 주석이고, 값에 공백이나 특수 문자가 있으면 따옴표로 감싼다.
- `.env`는 `.gitignore`에 추가해 커밋하지 않는다. 저장소에는 값이 없는 `.env.example`만 둔다.
- `.env.example`에는 `API_KEY=`처럼 키 이름만 적는다. 다른 사람이 복사해 자기 값을 채울 수 있다.
- 공개 클라이언트 키는 브라우저에 전달되는 것을 전제로 하므로 노출을 막을 수 없다. 비밀 키는 서버에서만 쓰고 클라이언트 코드에 넣지 않는다.
- 실수로 커밋하거나 push했다면 이력 삭제보다 키 폐기·재발급이 먼저다. 노출된 값은 이미 유출된 것으로 보고 새 값으로 교체한다.
- 이력 삭제만으로는 포크, 캐시, 다른 사람의 복제본까지 회수할 수 없다.

## .env 예시

```text
# 실제 값을 넣는 파일. 커밋하지 않는다.
API_KEY=your_api_key_here
DATABASE_URL="postgres://user:password@localhost:5432/app"
```

```text
# .env.example: 키 이름만 공유한다.
API_KEY=
DATABASE_URL=
```

```text
# .gitignore
.env
```

- `.env`는 실제 값이 들어 있으므로 저장소에 올리지 않는다.
- `.env.example`은 키 목록을 설명하는 문서 역할을 한다. 실제 값을 넣지 않는다.
- `.env`를 이미 커밋했다면 `.gitignore`에 추가하는 것만으로는 부족하다. `git rm --cached .env`로 인덱스에서 제거하고 키를 교체한다.

`.env`에는 실제 값을 넣는다. 아래 화면의 값은 별표로 가린 예시이며 실제 비밀이 아니다.

![vi로 연 `.env`에 `API_KEY=********`와 `TOKEN=********`만 있다. 실제 비밀을 가린 값이 아니라 처음부터 적은 예시 값이다.](/shot-appendix11-env-1000.webp)

`.env.example`에는 키 이름만 적고 값은 비워 둔다.

![vi로 연 `.env.example`에 값이 비어 있는 `API_KEY=`와 `TOKEN=`만 있다.](/shot-appendix11-env-example-1000.webp)

`.gitignore`에 `.env` 한 줄을 적어 실제 값이 든 파일을 커밋에서 제외한다.

![vi로 연 `.gitignore`에 `.env` 한 줄이 있다.](/shot-appendix11-gitignore-1000.webp)


## 체크리스트

- [ ] 비밀 정보에 해당하는 값을 코드에 직접 적지 않았다.
- [ ] `.env`를 `.gitignore`에 추가했다.
- [ ] `.env.example`에는 키 이름만 있다.
- [ ] `git status`에서 `.env`가 보이지 않는다.
- [ ] 공개 클라이언트 키와 비밀 키를 구분했다.
- [ ] 노출 시 키 폐기·재발급이 이력 삭제보다 먼저라는 점을 안다.

## 주의할 점

- `.env`를 커밋한 뒤 파일만 지우지 않는다. 이전 커밋에 값이 남아 있을 수 있다.
- 비밀 값을 채팅, 이슈, 스크린샷, 로그에 남기지 않는다.
- `.env.example`에도 실제 키를 넣지 않는다.
- 공개 저장소에 올린 비밀 값은 이미 노출된 것으로 본다. 키를 폐기하고 새로 발급한다.
- 이력 삭제는 협업 저장소에서 다른 사람의 작업을 방해할 수 있으므로 강사와 상의한 뒤 진행한다.
- 프레임워크가 환경 변수를 읽는 방식과 `.env` 자동 로드 여부는 도구마다 다르다. 사용하는 도구의 문서를 확인한다.

## 복습 퀴즈

1. 코드 밖에서 값을 넣어 주는 방식을 ::환경 변수::라고 한다.
2. 추적하지 않을 파일의 이름이나 패턴을 지정하는 파일은 ::.gitignore::이다.
3. 이미 추적 중인 비밀 파일을 작업 공간에 남긴 채 Git 인덱스에서 제거하는 명령은 ::git rm --cached::이다.

## 참고 자료

- [OWASP Secrets Management Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Secrets_Management_Cheat_Sheet.html)
- [GitHub 비밀 스캐닝 문서](https://docs.github.com/en/code-security/concepts/secret-security/secret-scanning)
