Claude Code 권한·네트워크 허용, 프로젝트에서 어떻게 좁히나
Claude Code 권한 설정으로 프로젝트에서 도구·네트워크를 좁히려면, 공유 규칙은 .claude/settings.json의 permissions.allow / ask / deny에 두고, 도메인은 WebFetch(domain:…)와(필요 시) sandbox.network.allowedDomains·deniedDomains로 맞춥니다. 규칙 평가는 deny → ask → allow 순입니다.
이 글은 공식 Configure permissions·Settings 문서를 따라 설정 파일 위치, 허용·거부 목록, Cursor rules와의 맞춤만 다룹니다. 프로젝트 설정 전반 튜토리얼·요금은 다루지 않습니다.
설정 파일은 어디?
한 줄 답: 팀 공유는 .claude/settings.json, 개인 예외는 .claude/settings.local.json, 전역 기본은 ~/.claude/settings.json입니다.
공식 Settings 문서는 범위를 네 층으로 나눕니다.
- Shared project:
.claude/settings.json— 레포에 커밋해 팀 권한·훅을 공유합니다. - Project local:
.claude/settings.local.json— 본인만. “Yes, and don’t ask again”으로 저장한 Bash·WebFetch 승인이 여기에 쌓입니다. - User:
~/.claude/settings.json— 모든 프로젝트의 개인 기본. - Managed: 조직
managed-settings.json등 — 사용자가 덮어쓸 수 없습니다.
permissions.allow와 additionalDirectories는 워크스페이스 신뢰(trust) 후에만 적용됩니다. deny·ask는 제한만 하므로 신뢰 전에도 바로 적용됩니다. 목록형 키(permissions.allow 등)는 여러 파일에 있으면 병합되고, deny가 어느 스코프에 있어도 allow로 풀 수 없습니다.
허용 목록은 어떻게?
한 줄 답: Tool 또는 Tool(specifier) 규칙을 allow·ask·deny에 넣고, 네트워크는 WebFetch(domain:…)와 Bash deny·sandbox 도메인 목록을 함께 씁니다.
규칙 예:
{
"permissions": {
"allow": [
"Bash(npm run lint)",
"Bash(npm run test *)",
"WebFetch(domain:docs.example.com)"
],
"ask": [
"Bash(git push *)"
],
"deny": [
"Read(./.env)",
"Read(./.env.*)",
"Bash(curl *)",
"Bash(wget *)",
"WebFetch(domain:*.internal.example)"
]
}
}
핵심 계약은 다음과 같습니다.
- 평가 순서: deny → ask → allow. 좁은 allow가 넓은 deny를 뚫지 않습니다.
- Bash
*: 접두·중간·접미 와일드카드. compound(&&등)는 서브커맨드마다 따로 맞춥니다. - WebFetch:
WebFetch(domain:host)로 호스트를 좁힙니다. 단독WebFetchdeny는 도구를 제거하고,WebFetch(domain:*)는 도메인 단위로 거절하며 sandbox 도메인 목록에도 영향을 줍니다. - 네트워크 우회: Bash에
curl/wget이 열려 있으면 WebFetch만으로 네트워크를 막지 못합니다. 문서가 권하는 조합은 Bash 네트워크 도구 deny + WebFetch 도메인 allow(+ sandbox allowlist)입니다.
샌드박스를 켜면 sandbox.network.allowedDomains / deniedDomains가 Bash 쪽 호스트를 OS 수준으로 제한합니다. strictAllowlist: true는 user·managed·CLI --settings에서만 효과가 있고, 레포 settings.json에 넣어도 적용되지 않습니다.
세션 중에는 /permissions로 규칙 출처를 확인하고 추가·삭제할 수 있습니다.
Cursor rules와 맞추려면?
한 줄 답: Cursor rules·CLAUDE.md는 “무엇을 하려는지”를 말하고, Claude Code permissions는 “무엇을 실행해도 되는지”를 강제합니다. 문구를 맞춰도 권한 파일에 deny가 없으면 막히지 않습니다.
역할을 나누면 충돌이 줄어듭니다.
| 층 | 어디에 | 역할 |
|---|---|---|
| 의도·스타일 | CLAUDE.md, Cursor rules/AGENTS.md | 빌드 명령, 금지 관행, 리뷰 기준을 설명 |
| 강제 경계 | .claude/settings.json permissions | 도구·경로·도메인을 허용/질문/거부 |
| 런타임 가드 | PreToolUse hooks (Claude) / Hooks (Cursor) | 규칙으로 못 잡는 예외를 스크립트로 차단 |
실무 맞춤 예:
- 문서·이슈 트래커 도메인만
WebFetch(domain:…)allow. - 시크릿은
Read(./.env*)deny — Cursor.cursorignore와 경로를 맞춥니다. npm test·npm run lint만 Bash allow — Cursor hooks의 포맷/테스트 가드와 같은 명령을 씁니다.- “프로덕션에 curl 금지”를 rules에만 쓰지 말고
Bash(curl *)deny(+ sandbox)까지 넣습니다.
규칙은 모델이 아니라 Claude Code 런타임이 강제합니다. 프롬프트나 CLAUDE.md만으로는 permissions를 바꾸지 못합니다.
마무리
프로젝트에서 권한·네트워크를 좁히려면 ① 공유 파일(.claude/settings.json) → ② allow/ask/deny·WebFetch 도메인 → ③ Cursor rules와 의도만 맞추고 강제 경계는 permissions 순으로 잡습니다. 상세 문법과 sandbox 키는 Configure permissions·Settings를 기준으로 확인하시기 바랍니다.
출처
- Configure permissions — allow/ask/deny, 평가 순서, WebFetch·Bash
- Settings — 파일 위치·우선순위·병합
- Sandboxing — network allow/deny domains, strictAllowlist