API 키 보안 가이드 5단계 — .env 유출 방지부터 Mac Keychain까지

AI 에이전트를 운영하다 보면 API 키가 한두 개가 아니다. OpenAI, Claude, GitHub 토큰, Telegram Bot 토큰, Cloudflare API 키… 프로젝트 하나에 5~6개의 시크릿이 붙는 건 일상이다. 문제는, 이 키들이 단 한 번의 실수로 전부 노출될 수 있다는 것이다. .env 파일을 git push 한 번 잘못하면, GitHub의 퍼블릭 리포지토리에 내 모든 API 키가 올라간다. 봇이 이걸 수십 초 안에 탐지해서 악용하기 시작한다.

나도 초기에 사이드 프로젝트를 진행하면서 .env를 커밋한 적이 있다. 다행히 프라이빗 리포지토리였기 때문에 피해는 없었지만, 나중에 그 리포를 퍼블릭으로 전환하려다가 git 히스토리에 남아있는 키를 발견하고 식은땀을 흘렸다. 그때부터 API 키 관리에 대해 제대로 정리하게 됐고, 이 글은 그 과정에서 쌓인 실전 노하우를 한 곳에 모은 것이다.

MacBook M1을 기준으로, 로컬 개발 환경에서의 키 관리부터 CI/CD 파이프라인의 시크릿 관리까지 다룬다. 특히 Mac Keychain을 활용한 방법은 의외로 모르는 분들이 많은데, 한번 세팅하면 .env 파일 없이도 안전하게 API 키를 관리할 수 있다.

.env 유출 사고 실제 사례와 위험성

GitHub에서 시크릿이 유출되는 건 생각보다 훨씬 빈번하게 일어난다. GitGuardian의 2024년 보고서에 따르면, 퍼블릭 리포지토리에서 탐지된 시크릿 유출 건수가 연간 1,280만 건을 넘었다. 하루에 3만 5천 건꼴이다. 여기에는 AWS 키, OpenAI API 키, Slack 토큰 등이 포함된다. 관련 내용은 Mac Claude Code CLI 설치 가이드에서도 다루고 있다.

실제로 어떤 일이 벌어지는지 정리하면 이렇다.

  • AWS 키 노출 → 가상화폐 채굴: 가장 흔한 케이스다. 노출된 AWS Access Key로 EC2 인스턴스 수백 대를 띄워서 채굴에 사용한다. 하룻밤 사이에 수천 달러 청구서가 날아온 사례가 수두룩하다.
  • OpenAI API 키 노출 → 무단 사용: 퍼블릭 리포에 올린 OpenAI 키가 수 분 내에 탐지돼서, GPT-4 호출 비용이 하루에 수백 달러씩 청구된 사례가 있다. OpenAI는 이런 경우 자동으로 키를 비활성화하기도 하지만, 늦게 탐지되면 그 사이에 쌓인 비용은 본인 부담이다.
  • GitHub 토큰 노출 → 코드 탈취/변조: 리포지토리 쓰기 권한이 있는 토큰이 노출되면, 공격자가 악성 코드를 커밋하거나 시크릿을 추가로 빼낼 수 있다.

무서운 건 속도다. 2024년 기준, GitHub 퍼블릭 리포지토리에 시크릿이 노출되면 평균 30초~2분 이내에 봇이 탐지한다는 연구 결과가 있다. “실수로 올렸는데 바로 지우면 되지 않을까?”라고 생각할 수 있지만, git 히스토리에 남아있는 이상 git rm만으로는 완전히 제거되지 않는다. force push로 히스토리를 덮어써야 하는데, 그 사이에 이미 누군가 clone했을 수도 있다.

.gitignore 제대로 설정하기 (이미 커밋된 .env 제거)

API 키 — 설정 및 실행 결과 화면

가장 기본적이면서 가장 중요한 방어선이 .gitignore다. 프로젝트를 시작할 때 가장 먼저 해야 할 일이다.

필수 .gitignore 패턴

# .gitignore — API 키 및 시크릿 관련 필수 패턴

# 환경변수 파일
.env
.env.*
.env.local
.env.development
.env.production
!.env.example          # 예시 파일은 커밋해도 됨

# OS 파일
.DS_Store
Thumbs.db

# IDE 설정 (종종 환경변수가 포함됨)
.idea/
.vscode/settings.json
*.code-workspace

# 키/인증서 파일
*.pem
*.key
*.p12
*.pfx
credentials.json
service-account.json
token.json

# Terraform (인프라 시크릿)
*.tfvars
.terraform/

# Node.js
node_modules/

# Python
__pycache__/
*.pyc
.venv/

!.env.example 패턴이 중요하다. .env.example은 프로젝트에 필요한 환경변수 목록을 문서화하는 파일인데, 실제 값 대신 플레이스홀더를 넣어둔다. 이걸 커밋해두면 새로운 개발자가 어떤 환경변수가 필요한지 바로 알 수 있다.

이미 커밋된 .env 제거하기

이미 .env를 커밋해버렸다면, 단순히 .gitignore에 추가하는 것만으로는 부족하다. Git이 이미 추적 중인 파일은 .gitignore를 추가해도 계속 추적된다. 제거 절차는 이렇다.

# 1. .gitignore에 .env 추가 (아직 안 했다면)
echo ".env" >> .gitignore

# 2. Git 캐시에서 .env 제거 (로컬 파일은 유지)
git rm --cached .env

# 3. 커밋
git commit -m "Remove .env from tracking, add to .gitignore"

# 4. 하지만 이것만으로는 부족하다! git 히스토리에 여전히 남아있다.
# git log에서 .env가 포함된 커밋 확인
git log --all --full-history -- .env

# 5. 히스토리에서 완전히 제거하려면 git filter-repo 사용
# (git filter-branch는 deprecated, filter-repo 사용 권장)
pip3 install git-filter-repo

# .env 파일을 모든 커밋 히스토리에서 제거
git filter-repo --path .env --invert-paths

# 6. 이미 push한 리포라면 force push 필요 (주의!)
git push origin main --force

# 7. 가장 중요한 단계: 노출된 모든 키 즉시 재발급
# .env에 있던 모든 API 키를 새로 발급받아야 한다

7번 단계가 핵심이다. 히스토리에서 파일을 지우더라도, 이미 노출된 키는 누군가 복사해뒀을 수 있다. 반드시 모든 키를 재발급해야 한다. 이건 타협의 여지가 없다.

git-secrets, gitleaks로 사전 차단

.gitignore가 첫 번째 방어선이라면, pre-commit 훅은 두 번째 방어선이다. 커밋하기 전에 시크릿이 포함되어 있는지 자동으로 검사한다.

gitleaks 설치 및 설정

gitleaks는 시크릿 탐지 전용 도구로, 170개 이상의 패턴(AWS, GCP, OpenAI, Slack 등)을 기본 지원한다. 나는 git-secrets보다 gitleaks를 선호하는데, 패턴이 더 풍부하고 false positive가 적기 때문이다.

# macOS에서 gitleaks 설치
brew install gitleaks

# 버전 확인 (2026년 4월 기준 v8.21.x)
gitleaks version

# 현재 리포지토리에서 시크릿 검사
gitleaks detect --source . --verbose

# 커밋되지 않은 변경사항만 검사
gitleaks protect --source . --verbose

# 특정 커밋 범위만 검사
gitleaks detect --source . --log-opts="HEAD~10..HEAD"

# pre-commit 훅으로 설정 (커밋할 때마다 자동 검사)
# .pre-commit-config.yaml
cat > .pre-commit-config.yaml << 'EOF'
repos:
  - repo: https://github.com/gitleaks/gitleaks
    rev: v8.21.2
    hooks:
      - id: gitleaks
EOF

# pre-commit 프레임워크 설치 및 훅 활성화
pip3 install pre-commit
pre-commit install

# 이제부터 git commit할 때마다 gitleaks가 자동 실행된다
# 시크릿이 탐지되면 커밋이 차단된다:
# ❌ gitleaks has detected secrets in your code
# Finding: sk-proj-abc123...
# File: config.py
# Rule: openai-api-key

gitleaks가 탐지하면 커밋 자체가 차단되므로, 실수로라도 시크릿이 포함된 코드가 리포지토리에 들어가지 않는다. 하루에 한 번 놓치면 영구적인 유출이 되는 걸 생각하면, pre-commit 훅 설정에 5분 투자하는 건 보험 중에서도 가성비가 좋은 보험이다.

git-secrets (AWS 유저라면)

AWS를 주로 쓴다면 AWS Labs에서 만든 git-secrets도 좋다. AWS 키 패턴에 특화되어 있다.

# 설치
brew install git-secrets

# 현재 리포지토리에 훅 설치
git secrets --install

# AWS 패턴 등록
git secrets --register-aws

# 커스텀 패턴 추가 (예: OpenAI 키 패턴)
git secrets --add 'sk-proj-[A-Za-z0-9]{20,}'
git secrets --add 'sk-ant-[A-Za-z0-9]{20,}'

# 전체 히스토리 스캔
git secrets --scan-history

나는 두 도구를 비교해보고 gitleaks로 통일했다. git-secrets는 패턴을 직접 추가해야 하는 반면, gitleaks는 대부분의 주요 서비스 키 패턴이 내장되어 있어서 초기 설정이 간단하다.

Mac Keychain Access로 API 키 저장 및 조회

.env 파일의 근본적인 문제는 평문 텍스트라는 것이다. 디스크에 암호화 없이 저장되어 있고, 파일만 열면 누구나 읽을 수 있다. Mac을 쓴다면 Keychain Access를 활용해서 이 문제를 해결할 수 있다.

macOS Keychain은 운영체제 레벨에서 제공하는 암호화 저장소다. Touch ID나 시스템 비밀번호로 보호되고, 하드웨어 보안 모듈(Secure Enclave)과 연동된다. M1 이후의 Apple Silicon Mac에서는 Secure Enclave가 키 관리를 담당하므로 소프트웨어 레벨의 공격으로는 키를 탈취하기 어렵다.

security 명령어로 키 저장 및 조회

macOS에는 security라는 CLI 도구가 내장되어 있다. Keychain Access 앱의 터미널 버전이라고 생각하면 된다.

# API 키를 Keychain에 저장
# -s: 서비스 이름 (구분용)
# -a: 계정명 (환경변수 이름으로 사용)
# -w: 비밀번호 (실제 API 키 값)
security add-generic-password \
  -s "ai-agent" \
  -a "OPENAI_API_KEY" \
  -w "sk-proj-xxxxxxxxxxxxxxxxxxxxxxxx" \
  -T "" \
  /Users/$(whoami)/Library/Keychains/login.keychain-db

security add-generic-password \
  -s "ai-agent" \
  -a "ANTHROPIC_API_KEY" \
  -w "sk-ant-xxxxxxxxxxxxxxxxxxxxxxxx" \
  -T "" \
  /Users/$(whoami)/Library/Keychains/login.keychain-db

security add-generic-password \
  -s "ai-agent" \
  -a "GITHUB_TOKEN" \
  -w "ghp_xxxxxxxxxxxxxxxxxxxxxxxx" \
  -T "" \
  /Users/$(whoami)/Library/Keychains/login.keychain-db

# Keychain에서 API 키 조회
security find-generic-password \
  -s "ai-agent" \
  -a "OPENAI_API_KEY" \
  -w
# 출력: sk-proj-xxxxxxxxxxxxxxxxxxxxxxxx

# 키 업데이트 (기존 값 덮어쓰기)
# 먼저 삭제 후 다시 추가해야 한다
security delete-generic-password -s "ai-agent" -a "OPENAI_API_KEY"
security add-generic-password \
  -s "ai-agent" \
  -a "OPENAI_API_KEY" \
  -w "sk-proj-새로운키값여기에"

# 저장된 키 목록 확인 (키 값은 표시 안 됨)
security dump-keychain | grep "ai-agent" -A 5

-T "" 옵션은 어떤 앱에도 접근 권한을 자동 부여하지 않겠다는 뜻이다. 이렇게 하면 처음 접근할 때 macOS가 팝업으로 비밀번호를 물어보기 때문에, 악성 스크립트가 몰래 키를 빼가는 걸 방지할 수 있다. 터미널에서 매번 비밀번호 치는 게 귀찮다면 -T /usr/bin/security를 대신 사용하면 된다.

셸 프로필에 Keychain 연동하기

Keychain에 저장한 키를 환경변수로 자동 로드하려면, ~/.zshrc에 아래 내용을 추가한다.

# ~/.zshrc에 추가

# Keychain에서 API 키를 환경변수로 로드
export OPENAI_API_KEY=$(security find-generic-password -s "ai-agent" -a "OPENAI_API_KEY" -w 2>/dev/null)
export ANTHROPIC_API_KEY=$(security find-generic-password -s "ai-agent" -a "ANTHROPIC_API_KEY" -w 2>/dev/null)
export GITHUB_TOKEN=$(security find-generic-password -s "ai-agent" -a "GITHUB_TOKEN" -w 2>/dev/null)

# 키가 로드되었는지 확인 (값은 표시하지 않음)
if [ -n "$OPENAI_API_KEY" ]; then
  echo "OPENAI_API_KEY loaded from Keychain"
fi

이렇게 하면 .env 파일 없이도 환경변수가 세팅된다. 키가 디스크에 평문으로 저장되지 않으므로, git에 실수로 올라갈 위험이 원천적으로 차단된다. 셸을 열 때마다 Keychain에서 가져오는 거라 약간의 지연(0.1초 미만)이 있지만, 체감상 차이는 없다.

환경변수 설정 방법 비교 (.env vs export vs Keychain)

세 가지 방법을 비교하면 이렇다. 프로젝트 성격에 따라 선택하면 된다.

방법 보안 편의성 팀 공유 적합한 경우
.env + dotenv 낮음 (평문 파일) 높음 가능 (.env.example 공유) 빠른 프로토타이핑, 팀 프로젝트
export in .zshrc 낮음 (dotfiles에 평문) 보통 불편 개인 개발, 키가 1~2개일 때
Mac Keychain 높음 (OS 레벨 암호화) 보통 불가 (로컬 전용) 개인 개발, 보안 중요할 때
1Password CLI / Vault 매우 높음 보통 가능 (Vault 공유) 팀 프로젝트, 엔터프라이즈

나의 현재 세팅은 이렇다. 개인 프로젝트에서는 Mac Keychain을 기본으로 사용하고, 프로젝트별로 특수한 환경변수가 필요할 때만 .env를 보조적으로 사용한다. .env를 쓸 때는 반드시 .gitignore에 등록하고, gitleaks pre-commit 훅을 걸어둔다. CI/CD에서는 GitHub Actions secrets를 사용한다. 이 삼중 구조면 개인 개발자 수준에서는 충분하다.

한 가지 팁을 더하면, .env.example 파일은 반드시 만들어두자. 실제 키 값 대신 설명이나 더미 값을 넣어둔다.

# .env.example — 이 파일은 커밋해도 안전하다
OPENAI_API_KEY=sk-proj-여기에-실제-키를-넣으세요
ANTHROPIC_API_KEY=sk-ant-여기에-실제-키를-넣으세요
GITHUB_TOKEN=ghp_여기에-실제-토큰을-넣으세요
TELEGRAM_BOT_TOKEN=123456789:ABCdefGHIjklMNOpqrSTUvwxyz
TELEGRAM_CHAT_ID=123456789

# 신규 개발자 셋업:
# 1. cp .env.example .env
# 2. 각 값을 실제 키로 교체
# 3. .env는 .gitignore에 포함되어 있으므로 커밋되지 않음

API 키 로테이션 주기와 방법

API 키를 한 번 발급받고 영원히 쓰는 사람이 많다. 나도 그랬다. 하지만 키를 주기적으로 교체하는 것은 보안의 기본이다. 유출을 인지하지 못한 상태에서 오랫동안 같은 키를 쓰면, 그만큼 피해가 누적된다.

권장 로테이션 주기는 서비스 특성에 따라 다르다.

키 종류 권장 주기 이유
OpenAI API Key 90일 사용량 기반 과금, 유출 시 금전 피해 직접적
Anthropic API Key 90일 동일 이유
GitHub Personal Access Token 30~90일 (만료일 설정 필수) 코드 접근 권한, 유출 시 심각
Cloudflare API Token 90일 DNS, Workers 등 인프라 접근
Telegram Bot Token 필요 시 (이벤트 기반) 봇 자체 위험도는 상대적으로 낮음

로테이션할 때 핵심은 무중단 교체다. 새 키를 발급받고, 모든 사용처를 업데이트한 후, 구 키를 삭제하는 순서를 지켜야 한다. 순서가 바뀌면 서비스가 중단된다.

# API 키 로테이션 절차 (Mac Keychain 기준)

# 1. 새 키 발급 (각 서비스 대시보드에서)
#    OpenAI: https://platform.openai.com/api-keys
#    Anthropic: https://console.anthropic.com/settings/keys
#    GitHub: https://github.com/settings/tokens

# 2. 새 키를 Keychain에 저장 (기존 키 덮어쓰기)
security delete-generic-password -s "ai-agent" -a "OPENAI_API_KEY" 2>/dev/null
security add-generic-password \
  -s "ai-agent" \
  -a "OPENAI_API_KEY" \
  -w "sk-proj-새로발급받은키"

# 3. 환경변수 갱신 (새 셸 열거나 source)
source ~/.zshrc

# 4. 키가 제대로 작동하는지 테스트
curl -s https://api.openai.com/v1/models \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  | head -c 200
# 정상이면 JSON 응답이 온다

# 5. CI/CD secrets도 업데이트
#    GitHub Actions: 리포 Settings → Secrets and variables → Actions
#    Cloudflare Workers: wrangler secret put OPENAI_API_KEY

# 6. 모든 사용처 업데이트 확인 후, 이전 키 삭제 (서비스 대시보드에서)
# ⚠️ 반드시 새 키가 정상 작동하는 걸 확인한 후에 삭제할 것

Claude, OpenAI, GitHub 토큰 권한 최소화

API 키는 가능한 한 최소 권한(Least Privilege)으로 발급해야 한다. 만약 키가 유출되더라도, 권한이 제한되어 있으면 피해 범위를 줄일 수 있다.

GitHub: Fine-grained Personal Access Token

2023년부터 GitHub은 Fine-grained PAT를 정식 지원한다. 기존 Classic 토큰과 달리, 리포지토리 단위로 권한을 세밀하게 제어할 수 있다.

  • Settings > Developer settings > Personal access tokens > Fine-grained tokens
  • Repository access: "Only select repositories"를 선택하고 필요한 리포만 지정한다. "All repositories"는 절대 선택하지 않는다.
  • Permissions: 필요한 것만 선택한다. 블로그 배포용이라면 Contents: Read and write만 있으면 된다. Administration이나 Actions 권한은 불필요하면 빼자.
  • Expiration: 반드시 만료일을 설정한다. 최대 1년이지만, 90일을 권장한다.

OpenAI: Project API Key

OpenAI는 2024년부터 Project-level API Key를 지원한다. 계정 전체에 접근하는 키 대신, 프로젝트별로 키를 분리할 수 있다.

  • Organization > Projects에서 프로젝트를 생성한다.
  • 각 프로젝트에서 별도의 API Key를 발급한다. 키 형식이 sk-proj-로 시작한다.
  • 프로젝트별로 사용량 제한(Usage Limit)을 설정할 수 있다. 예를 들어, 사이드 프로젝트에는 월 $10 제한을 걸어두면 유출되더라도 피해가 제한된다.
  • 모델 접근 제한: 특정 프로젝트에서 GPT-4o만 사용하고 GPT-4.5는 사용하지 못하게 제한할 수도 있다.

Anthropic: Workspace API Key

Anthropic Console에서도 Workspace 단위로 키를 분리할 수 있다. 프로덕션과 개발 환경의 키를 분리하고, 각각에 사용량 제한을 거는 것을 권장한다.

  • Settings > API Keys에서 키를 발급한다.
  • 키 이름에 용도를 명시한다 (예: blog-autobot-prod, local-dev).
  • Usage Limits에서 월별 사용량 상한을 설정한다.

CI/CD에서의 시크릿 관리 (GitHub Actions secrets)

CI/CD 파이프라인에서 API 키를 관리하는 방법도 중요하다. GitHub Actions를 기준으로 정리한다.

GitHub Actions Secrets 설정

GitHub Actions에서는 리포지토리 Settings에서 시크릿을 등록하고, 워크플로우 YAML에서 ${{ secrets.KEY_NAME }}으로 참조한다.

# .github/workflows/deploy.yml
name: Deploy

on:
  push:
    branches: [main]

# 권한을 최소한으로 제한
permissions:
  contents: read

jobs:
  deploy:
    runs-on: ubuntu-24.04
    steps:
      - uses: actions/checkout@v4

      - name: Deploy to production
        env:
          # secrets 컨텍스트에서 환경변수로 주입
          OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
          WP_APP_PASSWORD: ${{ secrets.WP_APP_PASSWORD }}
          TELEGRAM_BOT_TOKEN: ${{ secrets.TELEGRAM_BOT_TOKEN }}
        run: |
          # 시크릿이 로그에 출력되지 않도록 GitHub이 자동으로 마스킹한다
          # 아래 명령어를 실행하면 로그에 "***"로 표시된다
          echo "Using API key: $OPENAI_API_KEY"
          # 출력: Using API key: ***

          # 실제 배포 명령어
          npm run deploy

      # 시크릿 존재 여부 체크 (선택적 기능 활성화 시 유용)
      - name: Check optional secrets
        run: |
          if [ -n "${{ secrets.SLACK_WEBHOOK_URL }}" ]; then
            echo "Slack notifications enabled"
          else
            echo "Slack notifications disabled (secret not set)"
          fi

시크릿 관리 주의사항

  • 한 번 등록하면 값을 다시 볼 수 없다: 업데이트는 가능하지만, 현재 값 조회는 불가능하다. 따라서 Keychain이나 비밀번호 관리자에 원본을 별도 저장해두자.
  • Fork에서는 시크릿이 전달되지 않는다: 보안상 당연한 조치인데, Fork된 리포의 PR에서는 시크릿에 접근할 수 없다. 이건 외부 기여자의 PR이 시크릿을 탈취하는 걸 방지하기 위한 것이다.
  • Environment secrets 활용: 프로덕션과 스테이징 환경별로 시크릿을 분리할 수 있다. Settings > Environments에서 환경을 만들고, 각 환경에 별도의 시크릿을 등록한다.
  • Organization secrets: 여러 리포지토리에서 공통으로 사용하는 시크릿은 Organization 레벨에서 한 번에 관리할 수 있다.

워크플로우에서 절대 하면 안 되는 것

간혹 디버깅한다고 시크릿을 직접 출력하거나, 환경변수 전체를 덤프하는 경우가 있다. GitHub이 기본적으로 마스킹 처리를 하긴 하지만, base64 인코딩 같은 우회 방법으로 우연히 노출될 수 있다. env, printenv, set 같은 명령어를 워크플로우에 넣지 말자.

API 키 유출 시 긴급 대응 체크리스트

아무리 조심해도 유출은 일어날 수 있다. 중요한 건 유출을 인지한 후 얼마나 빠르게 대응하느냐다. 아래 체크리스트를 즐겨찾기 해두고, 유사시에 바로 참고하자.

즉시 수행 (5분 이내)

  1. 유출된 키 즉시 비활성화/삭제
    • OpenAI: https://platform.openai.com/api-keys → 해당 키 삭제
    • Anthropic: https://console.anthropic.com/settings/keys → 해당 키 삭제
    • GitHub: https://github.com/settings/tokens → 해당 토큰 삭제
    • AWS: IAM 콘솔에서 Access Key 비활성화
  2. 새 키 발급: 삭제와 동시에 새 키를 발급받는다.
  3. 모든 사용처 업데이트: Keychain, CI/CD secrets, 서버 환경변수 등 해당 키를 사용하는 모든 곳을 새 키로 교체한다.

후속 조치 (1시간 이내)

  1. 유출 경로 파악: git 히스토리, 로그 파일, 공유 문서 등 어디서 유출되었는지 확인한다.
  2. git 히스토리 정리: 퍼블릭 리포에 커밋된 경우, git filter-repo로 히스토리에서 제거하고 force push한다.
  3. 사용 내역 확인: 각 서비스의 대시보드에서 비정상 사용 내역이 있는지 확인한다. OpenAI Usage 페이지, AWS CloudTrail, GitHub Audit Log 등을 체크한다.
  4. 피해 범위 산정: 유출된 키의 권한 범위를 파악하고, 해당 권한으로 접근 가능한 모든 리소스를 점검한다.

재발 방지

  1. gitleaks pre-commit 훅 설치 (아직 안 했다면)
  2. GitHub의 Secret Scanning 활성화: 리포지토리 Settings > Code security and analysis > Secret scanning을 켠다. 퍼블릭 리포는 기본 활성화, 프라이빗 리포는 GitHub Advanced Security 구독이 필요하다.
  3. 사용량 알림 설정: OpenAI, Anthropic 등에서 사용량 알림을 설정해두면, 비정상적인 사용이 발생했을 때 빠르게 인지할 수 있다.
  4. 키 로테이션 캘린더 등록: 90일마다 키를 교체하도록 캘린더에 반복 일정을 등록한다.

가장 중요한 건 1번이다. 유출을 인지한 순간, 다른 모든 것보다 키 비활성화가 먼저다. 원인 분석은 그다음이다. 1분의 차이가 수십만 원의 피해로 이어질 수 있다.

API 키 관리는 귀찮고 번거로운 작업이다. 하지만 한 번 유출 사고를 겪으면, 그때부터는 절대 귀찮다고 넘기지 않게 된다. 나는 Keychain + gitleaks + GitHub Actions secrets 조합으로 운영하고 있고, 이 세 가지만 제대로 세팅해두면 개인 프로젝트 수준에서는 충분한 보안이 확보된다. 처음 세팅하는 데 30분이면 된다. 그 30분이 나중에 수백 달러, 어쩌면 수천 달러를 지켜줄 수 있다. 자세한 내용은 GitHub Actions Secrets 공식 문서를 참고하자.