바이브 코딩을 위한 Git & GitHub
Part 3: 협업과 보안

10장 — 내 API 키를 지켜라: .gitignore와 보안 규칙

2026년 6월 30일 화요일 오전 7시 05분. 기말고사 마지막 날 아침이었습니다. 김진관 선생님이 와이셔츠를 입으며 출근 준비를 하던 중 핸드폰이 짧게 진동했습니다. 메일 한 통이 도착해 있었습니다. 발신자는 Anthropic. 제목은 이랬습니다. "Your API key has been exposed."

손가락이 멈췄습니다. 메일을 열어 본문을 읽어 내려갔습니다. 지난주 class-2b 학급 웹사이트에 학생 글쓰기 피드백 기능을 추가하면서, Claude로부터 API 키를 받아 자바스크립트 파일 맨 위에 그대로 써뒀습니다. 그 파일이 GitHub 공개 저장소에 고스란히 올라가 있었습니다. 자동화된 봇이 감지하기까지 걸린 시간은 수 분. 키는 이미 Anthropic이 자동 폐기한 상태였습니다. 손이 떨렸습니다. 다행히 비용 청구 전 조치였습니다. 이 챕터를 먼저 읽었더라면 일어나지 않았을 사고였습니다.

API 키가 GitHub에 올라가는 순간 전 세계가 그 키를 읽을 수 있습니다. .gitignore 파일 하나가 이 사고를 막습니다.

이 챕터를 마치면 다음 세 가지를 할 수 있습니다.

  • 프로젝트 루트에 .gitignore 파일을 만들어 .env와 API 키 파일을 추적에서 제외할 수 있습니다.
  • .env.env.example 패턴으로 키는 숨기고 구조만 공유하는 방식을 적용할 수 있습니다.
  • 이미 커밋된 .env 파일을 git rm --cached로 제거하고 키를 교체할 수 있습니다.

왜 이 챕터가 중요한가

바이브 코딩으로 앱을 만들 때 Claude는 종종 .env 파일에 API 키를 넣으라고 안내합니다. 거기까지는 정상입니다. 문제는 그 파일이 GitHub로 함께 올라가는 순간 발생합니다. 자동화된 봇이 공개 저장소를 쉬지 않고 스캔하며 sk-, AKIA, AIza로 시작하는 문자열을 찾아냅니다. 노출된 키는 매우 빠르게 감지될 수 있습니다. 악성 사용자의 손에 먼저 들어가면 하루 사이에 수백만 원 단위의 요금이 청구된 사례가 개발자 커뮤니티에 여러 건 공유되어 있습니다. 미리 알면 막을 수 있습니다.

(1) .gitignore는 "열지 마세요"라고 써 붙인 서랍입니다

사무실 서랍에 직원 급여 명세서를 넣어뒀는데 손님이 들어왔습니다. "이 서랍은 열지 마세요"라고 메모를 붙여두면 실수로 열어볼 일이 줄어듭니다. .gitignore 파일이 바로 이 메모입니다. Git에게 "이 파일들은 추적하지 말고, GitHub에도 올리지 마라"라고 알려주는 단순한 텍스트 파일입니다.

김진관 선생님은 사고가 난 그날 오전, 보충수업 쉬는 시간을 쪼개어 class-2b 프로젝트 폴더를 열었다. 순서는 이랬다.

(1) 프로젝트 루트(저장소의 가장 바깥 폴더) 안에서 VSCode를 엽니다. 좌측 파일 탐색기에서 빈 공간을 우클릭하고 "새 파일"을 선택합니다. (2) 파일 이름을 .gitignore로 입력합니다. 점(.)으로 시작하는 것이 포인트입니다. 탐색기에서 직접 만들 때 "파일 이름을 바꿀 수 없습니다"라는 경고가 뜨면 VSCode 안에서 만들면 됩니다. (3) 아래 내용을 그대로 복사해 붙여넣고 저장(Ctrl+S)합니다.

# 환경변수 파일 (API 키 포함)
.env
.env.local
.env.production
.env.development

# AI 도구 설정 폴더
.cursor/
.claude/

# OS 생성 파일
.DS_Store
Thumbs.db

# Node.js 의존성 폴더
node_modules/

저장이 끝나면 GitHub Desktop으로 돌아가 Changes 탭을 엽니다. 방금 추가한 .gitignore 한 줄만 목록에 올라 있고, 어제까지 보이던 .env는 목록에서 사라져 있습니다. 이것이 이 챕터의 Quick Win입니다. .env는 여전히 내 컴퓨터에 있습니다. 다만 Git이 더 이상 그 파일의 변경을 추적하지 않습니다.

잘 안 되면? .gitignore를 추가했는데 Changes 탭에 .env가 여전히 보인다면, 그 .env는 이미 이전에 한 번 커밋된 적이 있다는 뜻입니다. 이 경우는 아래 개념 3에서 해결합니다. 지금은 당황하지 말고 계속 읽으면 됩니다.

(2) .env와 .env.example — 키는 숨기고 구조는 공유합니다

집 현관 열쇠 사진을 찍어 SNS에 올리는 교사는 없습니다. API 키를 GitHub에 올리는 것이 바로 그 행위와 같습니다. 누구든 그 키로 내 계정에 요청을 보낼 수 있고, 요금은 내 카드에서 빠져나갑니다.

.env 파일은 환경변수(Environment Variables)의 줄임말로, 코드와 분리해서 API 키·비밀번호·데이터베이스 주소를 저장하는 전용 파일입니다. 일반적인 형식은 다음과 같습니다.

ANTHROPIC_API_KEY=sk-ant-api03-xxxxxxxxxxxxxxxxxxx
OPENAI_API_KEY=sk-proj-xxxxxxxxxxxxxxxxxxx
DATABASE_URL=postgresql://user:password@localhost/mydb

이 파일은 .gitignore에 등록되어 있으므로 GitHub에 올라가지 않습니다. 그런데 문제가 하나 생깁니다. 동료 교사 박혜원 선생님이 집 컴퓨터에서 class-2b 저장소를 clone 받았다고 해 봅시다. .env 파일은 따라오지 않습니다. 그러면 어떤 키가 필요한지 박 선생님은 어떻게 알 수 있을까요. 이때 쓰는 것이 .env.example 파일입니다.

ANTHROPIC_API_KEY=여기에_본인_키_입력
OPENAI_API_KEY=여기에_본인_키_입력
DATABASE_URL=여기에_DB_주소_입력

.env.example.gitignore에 등록하지 않습니다. 그래서 이 파일은 GitHub에 올라갑니다. 실제 키 값은 빠져 있고, "여기에 어떤 키가 들어가야 하는지"만 보여줍니다. 학생들에게 나눠 줄 구글 폼에 "이메일을 입력하세요"라고 안내만 써두고 실제 이메일 칸은 비워두는 것과 같은 원리입니다. 키는 숨기고, 구조만 공유합니다.

(3) 이미 올라간 키를 제거하는 순서 — 자물쇠 먼저, 열쇠 나중

현관 열쇠를 잃어버렸다고 가정해 봅시다. 새 열쇠를 만들기 전에 문을 아무리 단단히 잠가봤자 소용이 없습니다. 먼저 자물쇠 자체를 교체해야 합니다. 이미 GitHub에 올라간 API 키도 똑같습니다. 뒤늦게 .gitignore.env를 추가해봤자, 한 번 올라간 키는 커밋 히스토리에 영구 보존되어 있습니다. 순서가 중요합니다.

김진관 선생님이 사고 당일 실제로 밟은 순서는 이렇다.

(1) Anthropic 대시보드(console.anthropic.com)에 접속해 노출된 키를 즉시 폐기(Revoke) 버튼으로 무효화합니다. 이것이 가장 먼저입니다. 이 순서를 뒤집으면 안 됩니다. (2) 같은 화면에서 "Create Key" 버튼을 눌러 새 키를 발급받습니다. (3) 내 컴퓨터의 .env 파일을 열어 옛 키를 지우고 새 키로 교체합니다. (4) .gitignore.env가 들어 있는지 확인합니다. 없으면 추가합니다. (5) VSCode 터미널(Ctrl + `)을 열고 프로젝트 루트에서 아래 명령을 실행합니다.

git rm --cached .env

이 명령은 내 컴퓨터의 .env 파일은 그대로 두고, Git의 추적 목록에서만 제거합니다. --cached를 빼면 실제 파일까지 삭제되니 반드시 붙여야 합니다. (6) GitHub Desktop으로 돌아가 "chore: remove .env from tracking"이라는 메시지로 커밋하고 Push origin을 누릅니다.

여기까지 마치면 앞으로의 커밋에서는 .env가 더 이상 따라 올라가지 않습니다. 다만 한 가지를 기억해야 합니다. 과거 히스토리에 남은 옛 키는 여전히 읽을 수 있으므로, (1)단계의 키 폐기가 최종 방어선입니다. 그래서 순서가 중요합니다.

잘 안 되면? git rm --cached .env를 어디에 붙여넣어야 할지 모르겠다면 이렇게 하면 됩니다. VSCode에서 프로젝트 폴더를 엽니다. 상단 메뉴에서 "터미널 → 새 터미널"을 클릭합니다. 화면 아래쪽에 검은 창이 열리면 그 창의 첫 줄에 이미 프로젝트 루트 경로가 표시되어 있습니다. 거기에 명령을 그대로 붙여넣고 엔터만 누르면 됩니다.

핵심 3줄 요약

  • .gitignore는 Git에게 "이 파일은 추적하지 마라"를 알려주는 메모 파일입니다. 프로젝트 루트에 둡니다.
  • .env에 API 키를 넣고 .env.example로 구조만 공유하면 키 노출을 원천 차단합니다.
  • 이미 올라간 키는 복구 불가. 즉시 폐기 → 새 키 발급 → git rm --cached 순서로 대응합니다.

완료 체크리스트

  • 프로젝트 루트에 .gitignore 파일을 만들었다.
  • .env, .cursor/, .claude/, node_modules/ 항목을 등록했다.
  • .env.example 파일로 팀원에게 키 구조만 공유할 수 있다.
  • 이미 커밋된 .envgit rm --cached로 제거하는 순서를 설명할 수 있다.

다음은 에필로그입니다. 3월 3일의 빈 화면이 어떻게 7월의 한 줄 히스토리로 남았는지, 한 학기의 마지막 장면으로 이어집니다.