Tips & Tricks

Claude Code 보안 완전 가이드: API 키 관리, 권한 설정, 프로덕션 보호

Claude Code를 안전하게 사용하기 위한 실전 보안 가이드. API 키 관리부터 권한 설정, Hooks 기반 자동화, 프로덕션 환경 보호까지 — 바로 동작하는 코드 예제와 함께 설명합니다.

Claude Code는 강력한 파일 조작 및 명령 실행 능력을 갖추고 있지만, 잘못된 설정은 되돌릴 수 없는 사고로 이어질 수 있습니다. .env 파일 커밋, 프로덕션 DB 실수 삭제, API 키 로그 출력 — 이것들은 모두 Claude Code를 무방비 상태로 사용한 결과로 발생한 실제 사례입니다.

이 글에서는 Claude Code를 안전하게 사용하기 위한 보안 대책을 구현 수준에서 설명합니다. 개념 설명보다는 바로 복사해서 사용할 수 있는 설정과 예방 코드를 중심으로 정리했습니다.

Claude Code에 보안 대책이 필요한 이유

일반 텍스트 에디터와 달리, Claude Code는 다음과 같은 권한을 가집니다.

  • 임의 파일 읽기·쓰기·삭제 (Read / Write / Edit / Bash(rm))
  • 셸 명령 실행 (Bash)
  • 네트워크 액세스 (WebFetch / API 호출)
  • 외부 서비스 게시 (GitHub, Slack 등)

이것들은 모두 사용자가 승인만 하면 실행됩니다. 문제는 “승인을 기계적으로 계속 OK하면 의도하지 않은 조작이 통과된다”는 것입니다. 보안 대책이란 “실수가 끼어들 여지를 구조적으로 없애는” 작업입니다.

대책 1: API 키 관리 — .env + .gitignore가 기본

해서는 안 되는 예시

// ❌ 소스 코드에 직접 작성
const client = new Anthropic({ apiKey: "sk-ant-api03-..." });

// ❌ CLAUDE.md나 설정 파일에 작성
// ANTHROPIC_API_KEY=sk-ant-api03-...

// ❌ claude -p 프롬프트 안에 작성
// QIITA_TOKEN=abc123을 사용해서 Qiita에 게시해줘

올바른 관리 방법

# .env (git 관리 외, 로컬 머신에만 저장)
ANTHROPIC_API_KEY=sk-ant-api03-...
QIITA_TOKEN=06b4441b...
SLACK_BOT_TOKEN=xoxb-...
DATABASE_URL=postgresql://...
# .gitignore에 반드시 추가
.env
.env.*
.env.local
!.env.example   # ← 샘플만은 OK
*.pem
*.key
credentials.json
*-service-account.json
# .env.example (git 관리 OK, 값은 비워둠)
ANTHROPIC_API_KEY=
QIITA_TOKEN=
SLACK_BOT_TOKEN=
DATABASE_URL=

코드에서의 읽기

// ✅ 환경 변수에서 읽기
import { config } from "dotenv";
config();

const token = process.env.QIITA_TOKEN;
if (!token) throw new Error("QIITA_TOKEN이 설정되어 있지 않습니다. .env를 확인해주세요.");

CLAUDE.md에 금지 사항으로 명시

## 보안 금지 사항
- API 키·토큰을 프롬프트에 포함하지 않음
- .env 파일을 읽어서 내용을 출력하지 않음
- 환경 변수 값을 로그나 주석에 작성하지 않음
- process.env의 내용을 console.log 하지 않음

대책 2: 커밋 전 비밀 정보 스캔

.env를 gitignore해도, 다른 파일에 잘못 기재하거나 복사·붙여넣기 누락은 방지할 수 없습니다. 커밋 전 자동 스캔 체계를 도입합시다.

Hooks로 커밋 전 체크

.claude/settings.json:

{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash(git commit*)",
        "hooks": [
          {
            "type": "command",
            "command": "node scripts/secret-scan.mjs"
          }
        ]
      }
    ]
  }
}

scripts/secret-scan.mjs:

import { execSync } from "child_process";

// 스테이징된 변경 사항 가져오기
const diff = execSync("git diff --cached").toString();

const PATTERNS = [
  { name: "Anthropic API 키", re: /sk-ant-api\d+-[A-Za-z0-9_-]{80,}/ },
  { name: "OpenAI API 키", re: /sk-[A-Za-z0-9]{48}/ },
  { name: "AWS 액세스 키", re: /AKIA[0-9A-Z]{16}/ },
  { name: "Slack 토큰", re: /xox[baprs]-[0-9A-Za-z-]{10,}/ },
  { name: "Generic 시크릿", re: /[Ss]ecret[_-]?[Kk]ey\s*[:=]\s*['"][^'"]{10,}['"]/ },
];

const found = PATTERNS.filter(({ re }) => re.test(diff));

if (found.length > 0) {
  console.error("🚨 시크릿 감지! 커밋을 중단합니다:");
  found.forEach(({ name }) => console.error(`  - ${name}`));
  console.error("\n대처법: git reset HEAD <file>로 unstage 해주세요");
  process.exit(1);  // 종료 코드 1 → Hook이 명령을 블록
}

console.log("✓ 시크릿 스캔: 문제 없음");
process.exit(0);

이로써 git commit을 Claude Code가 실행하려는 순간 자동 스캔이 작동하고, 유출이 감지된 경우 블록됩니다.

대책 3: 권한 모드 설정

Claude Code의 허용·거부는 파일 수준에서 세밀하게 제어할 수 있습니다.

.claude/settings.json의 권한 설정

{
  "permissions": {
    "allow": [
      "Read(**)",
      "Glob(**)",
      "Grep(**)"
    ],
    "deny": [
      "Bash(rm -rf*)",
      "Bash(git push --force*)",
      "Bash(git reset --hard*)",
      "Bash(DROP TABLE*)",
      "Bash(truncate*)",
      "Bash(curl * | bash)",
      "Bash(wget * | sh)"
    ],
    "ask": [
      "Write(**)",
      "Edit(**)",
      "Bash(git commit*)",
      "Bash(git push*)",
      "Bash(npm publish*)",
      "Bash(wrangler pages deploy*)"
    ]
  }
}
설정의미
allow확인 없이 실행
deny일절 실행 불가 (거부)
ask매번 승인 필요

포인트: 파괴적 명령은 deny, 쓰기 계열은 ask, 읽기 계열은 allow가 기본 분류입니다.

프로덕션 환경 전용 설정 파일

프로덕션 환경에서는 읽기 전용으로 한정하는 것이 안전합니다.

// .claude/settings.production.json
{
  "permissions": {
    "allow": ["Read(**)", "Glob(**)", "Grep(**)", "Bash(git log*)", "Bash(git diff*)"],
    "deny": ["Write(**)", "Edit(**)", "Bash(git push*)", "Bash(rm*)", "Bash(*deploy*)"],
    "ask": []
  }
}
# 프로덕션 작업 시 명시적으로 지정
CLAUDE_SETTINGS=.claude/settings.production.json claude

대책 4: 프로덕션 환경 보호

연결 대상을 명시적으로 분리

## CLAUDE.md — 프로덕션 환경 규칙

## 환경 판정
- DATABASE_URL에 'prod' 또는 'production'이 포함된 경우 **프로덕션 환경**
- 프로덕션 환경에서는 절대로 실행하지 않음:
  - DROP / TRUNCATE / DELETE (WHERE 없이)
  - 마이그레이션 (사전 확인 필수)
  - 파일 일괄 삭제

## 확인 플로우
프로덕션 변경은 반드시:
1. 스테이징 환경에서 테스트
2. 사용자에게 확인 받기
3. 실행 후 결과 보고

환경 변수로 연결 대상 제어

// scripts/db-query.mjs
const env = process.env.NODE_ENV ?? "development";
const dbUrl = process.env.DATABASE_URL;

if (env === "production" && process.argv.includes("--write")) {
  console.error("❌ 프로덕션 환경에 쓰기는 --force-production 플래그가 필요합니다");
  process.exit(1);
}

대책 5: 파일 조작 안전 장치

삭제 전 백업 자동화

// .claude/settings.json의 Hooks
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash(rm *)",
        "hooks": [
          {
            "type": "command",
            "command": "echo '⚠️  삭제 명령이 실행되려 합니다. Ctrl+C로 중지할 수 있습니다.' && sleep 3"
          }
        ]
      }
    ]
  }
}

중요 파일을 실수 편집으로부터 보호

## CLAUDE.md — 변경 금지 파일

다음 파일은 **절대로 편집하지 않음**:
- .env (환경 변수, 비밀 키 포함)
- wrangler.toml (Cloudflare 프로덕션 설정)
- scripts/deploy.sh (배포 스크립트)
- .github/workflows/*.yml (CI/CD 설정)

변경이 필요한 경우 사용자에게 확인 받을 것.

함정 5가지

1. .gitignore를 나중에 추가해도 이미 늦음 이미 커밋된 .env는 gitignore를 추가해도 git 히스토리에 남습니다.

# 히스토리에서 완전 삭제 (주의: force push 필요)
git filter-branch --force --index-filter \
  "git rm --cached --ignore-unmatch .env" \
  --prune-empty --tag-name-filter cat -- --all

# 또는 BFG Repo Cleaner 사용

GitHub에 이미 푸시한 경우는 반드시 API 키를 로테이션한 후 대처하세요.

2. 서비스 계정 JSON을 저장소에 배치 Google Cloud나 AWS의 서비스 계정 키는 .json으로 배포되는 경우가 많지만, 저장소에 두는 것은 위험합니다. 환경 변수화하거나 Secret Manager (AWS Secrets Manager / GCP Secret Manager)로 이전하세요.

3. Bash 도구에서 대화형 명령 실행 claude -p에서 헤드리스 실행 중에 sudovim 등 대화형 입력이 필요한 명령이 섞이면 프로세스가 멈춥니다. 비대화형 명령만 사용하세요.

4. 에러 메시지에 인증 정보 포함

// ❌ 위험: API 키가 로그에 출력됨
throw new Error(`인증 실패: token=${process.env.TOKEN}`);

// ✅ 안전: 값을 출력하지 않음
throw new Error(`인증 실패: TOKEN 환경 변수를 확인해주세요`);

5. 전 프로젝트에서 같은 권한 설정을 재사용 취미 프로젝트와 업무 프로젝트에서 같은 settings.json을 사용하면, 업무 측에서 필요한 제한이 취미 측의 느슨한 설정으로 덮어써집니다. 프로젝트마다 .claude/settings.json을 관리하세요.

보안 체크리스트

Claude Code 프로젝트 도입 시 확인 목록:

### 기본 설정
- [ ] .env 생성하고 .gitignore에 추가 완료
- [ ] .env.example 생성하고 팀 공유 완료
- [ ] git log로 기존 커밋에 비밀 정보 없는지 확인

### 권한 설정
- [ ] .claude/settings.json에 deny 리스트 설정
- [ ] 파괴적 명령 (rm -rf, DROP TABLE 등)을 deny에 추가
- [ ] 프로덕션 배포 명령을 ask에 설정

### 자동화
- [ ] 커밋 전 시크릿 스캔 Hook 설정
- [ ] CLAUDE.md에 보안 금지 사항 기재

### 운용
- [ ] API 키 로테이션 주기 결정 (권장: 90일)
- [ ] 프로덕션 환경은 전용 settings.production.json 사용
- [ ] 인시던트 발생 시 대처 플로우 문서화

정리

Claude Code의 보안은 “제한을 부과하는” 것이 아니라 “사고가 일어나지 않는 구조를 만드는” 것입니다.

위협대책
API 키 유출.env + .gitignore + 시크릿 스캔 Hook
의도하지 않은 삭제deny 리스트 + 삭제 전 Hook
프로덕션 오조작프로덕션 전용 settings + CLAUDE.md 금지
커밋 오염PreToolUse Hook으로 커밋 전 스캔

설정은 한 번 넣으면 메인터넌스 프리입니다. 오늘 30분 투자하면 미래의 큰 사고를 막을 수 있습니다.

관련 글

참고 자료

#claude-code #security #api-key #permissions #devops #best-practices

Claude Code 워크플로우를 한 단계 업그레이드하세요

지금 바로 Claude Code에 복사해 쓸 수 있는 검증된 프롬프트 템플릿 50선.

무료 제공

무료 PDF: 5분 완성 Claude Code 치트시트

이메일 주소만 등록하시면 A4 한 장짜리 치트시트 PDF를 즉시 보내드립니다.

개인정보는 엄격하게 관리하며 스팸은 보내지 않습니다.

Masa

이 글을 작성한 사람

Masa

Claude Code를 적극 활용하는 엔지니어. 10개 언어, 2,000페이지 이상의 테크 미디어 claudecode-lab.com을 운영 중.