
Claude Code 권한 설정을 안전하게 설계하는 방법 ― Write/Edit·Ask/Deny를 실제로 검증하며 알게 된 것
요약
Claude Code의 권한 설정(Write/Edit, Ask/Deny)을 용도별로 분리하여 보안 경계를 설계하는 방법을 다룹니다. 실제 검증 과정을 통해 권한 우선순위 규칙과 안전한 테스트 환경 구축 방법을 설명합니다.
핵심 포인트
- Claude Code의 권한 평가 순서는 deny > ask > allow 순임
- 용도별 권한 경계(Permission Boundary) 설정을 통한 보안 강화
- 검증용 별도 settings.json 파일을 활용한 안전한 테스트 방법
- Edit 규칙이 내장 파일 편집 도구 전체에 적용됨을 유의
동작 확인 환경
- Claude Code 2.1.209
- Ubuntu (WSL)
- Manual Mode
- 커맨드 라인에서 전용의
settings.json지정
본 기사는 2026년 7월 시점에서 실제로 확인한 동작을 정리한 것입니다. Claude Code는 업데이트 빈도가 높으므로, 도입 시에는 최신 공식 문서와 실행 시의 경고도 확인해 주세요.
Claude Code에 조사나 리뷰를 맡길 때, 처음부터 넓은 권한을 부여하는 것은 피하고 싶었습니다.
이번에 하고 싶었던 것은 단순히 "쓰기를 허용하는" 것이 아닙니다. 목표는 다음과 같이 용도별로 권한 경계(Permission Boundary)를 나누는 것이었습니다.
- 일반적인 개발 세션에서는 실제 로그나 로컬 출력을 읽지 못하게 함
- 조사 전용 세션에서만 필요한 입력을 읽을 수 있도록 함
- 조사 리포트 저장소에 대해서만 인간의 승인 후 쓰기가 가능하도록 함
- 소스 코드, 테스트, 설정, Git 관리 영역에 대한 쓰기는 거부함
- Bash를 통한 파일 생성이나 Git 변경도 금지된 상태로 유지함
- 조사 전용 세션을 닫은 후, 일반 세션에 일시적인 허용 권한이 남지 않도록 함
즉, 검증하고 싶었던 경계는 다음과 같습니다.
필요한 읽기
+
지정된 출력처에 대한 승인제 쓰기
...
본 기사에서는 성공한 설정뿐만 아니라, 실제로 빠졌던 다음의 2가지 포인트도 포함하여 기록합니다.
- 경로가 포함된
Write(path)를 설정했더니 실행 시 경고가 발생함 - 절대 경로로 의도하여 맨 앞에/를 붙였으나 일치하지 않아//로 수정해야 했음
Claude Code의 공식 문서에서는 권한 규칙이 다음 순서로 평가됩니다.
deny
ask
allow
따라서 넓은 ask나 allow와 금지 대상인 deny가 동시에 일치하는 경우에는 deny가 우선됩니다.
- 공식 문서: https://code.claude.com/docs/en/permissions
- 해당 부분:
Rules are evaluated in order: deny, then ask, then allow.
이번 목적에서는 이 우선순위가 중요합니다.
저장 위치 디렉터리 → ask
소스 코드 영역 → deny
이렇게 나누어 두면, 리포트 저장은 매번 확인하면서도 금지 영역에 대한 쓰기는 확인 화면 없이 거부할 수 있습니다.
또한, 공식 문서에는 다음과 같은 설명이 있습니다.
Edit rules apply to all built-in tools that edit files.
즉, Edit 규칙은 Claude Code의 내장 파일 편집 도구 전체에 적용됩니다.
통상 운용 설정을 직접 변경하면, 검증 중인 허용 설정이 평소의 개발 세션에 섞일 위험이 있습니다.
그래서 통상 설정과는 별도로 검증용 Settings를 만들고, 다음 형식으로 실행했습니다.
claude --setting-sources user --settings ~/.claude/xserver-log-analyzer-write-test.settings.json
--setting-sources user를 붙여, 커맨드 라인에서 지정한 Settings와 User 설정만을 읽어오도록 구성한 것입니다.
검증용 파일은 본 운영 환경에 남기지 않고 검증 종료 후 삭제했습니다. 검증용 임시 디렉터리도 /tmp 하위에 생성하여 마지막에 모두 삭제했습니다.
처음에는 Write 도구만을 대상으로 하면 신규 파일 생성을 한정할 수 있다고 생각하여, 다음과 같은 규칙을 설정했습니다.
{
"permissions": {
"ask": [
...
/permissions의 Ask 탭에서는 Edit(...)와 Write(...)가 모두 표시되었습니다.
Write 도구에 지정 디렉터리 내에 한 줄뿐인 Markdown을 작성하도록 요청하자, 작성 전 확인 화면이 표시되었습니다.
여기서는 다음의 3가지 선택지가 표시되었습니다.
- 이번만 허용
- 세션 중, 대상 디렉터리에 대한 모든 편집을 허용
- 거부
"이번만 허용"을 선택하면 파일이 생성되었고 내용도 확인할 수 있었습니다.
이 시점에서는 언뜻 보기에 Write(path)가 기능하고 있는 것처럼 보였습니다. 하지만 나중에 실행 시의 경고를 통해, 경로가 포함된 파일 권한에 대한 개념을 다시 검토하게 됩니다.
다음으로, 허가 대상이 아닌 프로젝트 루트(Project Root)에 파일을 생성하도록 요청했습니다.
이 단계에서는 확인 화면이 표시되었습니다.
그 후, 프로젝트 루트에 대한 거부(Deny) 규칙을 추가하고 동일한 작업을 수행하자, Error writing file 메시지가 나타나며 파일이 생성되지 않았습니다.
이 검증을 통해, Deny 규칙에 일치하는 경우에는 Claude의 문장상 지시가 아니라, Claude Code 측의 권한 제어에 의해 쓰기가 중단된다는 것을 확인할 수 있었습니다.
공식 문서에도 권한 규칙은 모델이 아니라 Claude Code가 강제한다고 기재되어 있습니다.
- 공식 문서: https://code.claude.com/docs/en/permissions
- 해당 부분:
Permission rules are enforced by Claude Code, not by the model.
프롬프트에 "변경하지 마세요"라고 쓰는 것도 중요하지만, 그것만으로는 권한 경계(Permission Boundary)가 되지 않습니다. 실제 금지는 Settings의 Deny 규칙을 통해 수행해야 합니다.
검증 도중부터 Claude Code를 실행할 때 노란색 경고가 표시되기 시작했습니다.
경고 내용은 다음과 같습니다.
Permission deny rule (...):
Write(...) is not matched by file permission checks
— only Edit(path) rules are.
...
Ask 측의 Write(path)에도 동일한 경고가 표시되었습니다.
여기서 중요한 점은, Write 도구 자체가 존재하지 않는 것도 아니고, Write를 전면 금지해야만 하는 것도 아니라는 점입니다.
이번에 확인한 Claude Code 2.1.209에서는, 경로 단위로 파일 편집 계열 도구를 제어할 때는 Edit(path)를 사용하라는 경고가 나왔습니다. 공식 문서에도 Edit 규칙은 내장된 파일 편집 도구 전체에 적용된다고 되어 있습니다. 이에 따라 경로가 포함된 Write(...)를 Ask와 Deny에서 삭제하고, Edit(...)로 통일했습니다.
Write(path) 다음에 맞닥뜨린 문제는 경로의 시작 기호였습니다.
처음에는 일반적인 Linux의 절대 경로와 같은 감각으로 다음과 같이 작성했습니다.
"ask": [
"Edit(/tmp/xserver-log-analyzer-claude-write-test/reports/**)"
]
하지만 이 지정으로는 기대했던 절대 경로로 취급되지 않았습니다.
Claude Code의 Read/Edit 규칙에서의 경로는 일반적인 셸(Shell) 경로 표기법과 의미가 다릅니다. 공식 문서에서는 다음 4가지 유형으로 나뉩니다.
| 패턴 | 의미 |
|---|---|
//path | 파일 시스템 루트로부터의 절대 경로 |
~/path | 홈 디렉터리로부터의 상대 경로 |
/path | Settings 파일의 스코프(Scope)에 대응하는 디렉터리로부터의 상대 경로 |
path / ./path | Claude Code를 실행한 현재 디렉터리(Current Directory)로부터의 상대 경로 |
공식 문서에는 다음과 같이 명시되어 있습니다.
A pattern like
/Users/alice/file
isn’t an absolute path.
Use //Users/alice/file for absolute paths.
이번 Settings는 ~/.claude/ 하위의 파일을 --settings로 지정했습니다. 따라서 앞부분이 /tmp/...와 같이 슬래시 하나인 경우, OS의 /tmp/...가 아니라 Settings 파일의 위치를 기준으로 해결(Resolve)됩니다.
그래서 다음과 같이 앞부분을 //로 변경했습니다.
"ask": [
"Edit(//tmp/xserver-log-analyzer-claude-write-test/reports/**)"
]
프로젝트의 절대 경로를 Deny할 때도 마찬가지입니다.
"deny": [
"Edit(//home/USER/projects/example-project/**)"
]
이번 검증에서는 /인 상태로는 의도한 경로 제어가 되지 않았으나, //로 수정함으로써 일치하게 되었습니다.
경로가 포함된 Write(...)
를 삭제하고, Ask에는 Edit(...)만 남겼습니다.
{
"permissions": {
"ask": [
...
이 상태에서 Write 도구(tool)를 통한 신규 생성을 시도하자 확인 화면이 표시되었습니다.
「이번만 허용」을 선택하자, Write 도구는 지정된 파일을 생성했습니다.
생성 후의 결과에서는 다음 사항을 확인할 수 있었습니다.
- Write 도구로 1행만 작성됨
- Bash는 사용되지 않음
- 지정한 파일 이외에는 변경되지 않음
- 상위 디렉토리가 필요한 경우 Write 도구 측에서 생성함
이 결과로부터, Ask의 Edit(path)가 Write 도구에 의한 신규 생성에도 적용된다는 것을 실측할 수 있었습니다.
임시 디렉토리에서의 기본 검증 후, 실제 운용을 상정한 구성으로 진행했습니다.
저장 위치는 Git 관리 대상 외로 설정한 로컬 디렉토리입니다.
.local/
└── real-log-investigation/
검증용으로는 동일한 구조를 /tmp 하위에 만들었습니다.
/tmp/xserver-log-analyzer-permission-test/
├── .local/
│ └── real-log-investigation/
...
권한은 다음과 같이 나누었습니다.
{
"permissions": {
"ask": [
...
먼저, 허용 대상인 .local/real-log-investigation/ 하위에 신규 생성을 요청했습니다.
Claude Code는 Write 도구를 사용하기 전에 확인 화면을 표시했습니다.
여기서도 「이번만 허용」을 선택했습니다.
「세션 중, 이 디렉토리에 대한 모든 편집을 허용」도 선택할 수 있지만, 검증에서는 허용 범위를 넓히지 않고 매번 확인하는 방식을 택했습니다.
승인 후, 지정한 Markdown 파일이 생성되었습니다.
화면상에서는 다음 내용을 확인할 수 있었습니다.
- Write 도구가 성공함
- 내용은 지정한 1행뿐임
- Bash를 사용하지 않음
- 다른 파일을 변경하지 않음
- 쓰기 전에 권한 프롬프트(permission prompt)를 통과함
터미널 측에서도 대상 파일의 내용을 확인했습니다.
cat /tmp/xserver-log-analyzer-permission-test/.local/real-log-investigation/local-write-test.md
결과는 지정한 1행뿐이었습니다.
이 단계에서, 허용 대상 저장소는 Ask를 거쳐 쓸 수 있다는 것을 확인할 수 있었습니다.
마지막으로, 동일한 세션에서 Deny 대상인 src/ 하위에 신규 생성을 요청했습니다.
/tmp/xserver-log-analyzer-permission-test/src/deny-write-test.md
결과는 Error writing file이 되었으며, 다음 이유로 거부되었습니다.
File is in a directory that is denied by your permission settings.
이 이미지가 이번 최종 확인입니다.
.local/real-log-investigation/**는 Ask 후에 성공src/**는 Deny에 의해 거부- 동일한 Write 도구라도 대상 경로에 따라 결과가 갈림
공식 문서에 있는 deny → ask → allow 우선순위대로의 동작을 실제 파일 생성을 통해 확인할 수 있었습니다.
실제 설정에는 파일 편집뿐만 아니라 Git 변경, Bash를 통한 쓰기, 외부 통신, 비밀 정보 읽기 금지도 포함했습니다.
이하는 사고방식을 남겨둔 간략 버전입니다. 환경에 따른 사용자 이름이나 프로젝트명은 교체해 주세요.
{
"$schema": "https://json.schemastore.org/claude-code-settings.json",
"disableClaudeAiConnectors": true,
...
Bash 전체를 Deny하면 읽기 확인이나 필요한 검증 명령까지 사용할 수 없게 됩니다.
반면, Bash를 Ask로만 설정하면 사람이 실수로 승인했을 경우 리다이렉션(redirection)이나 rm, cp, Git 변경 등을 실행할 가능성이 있습니다.
그래서 다음과 같은 이단계 방식을 취했습니다.
Bash 전체 → Ask
위험한 변경 계열 명령 → Deny
이를 통해 읽기 중심의 단일 명령은 확인 후 실행할 수 있고, 명확한 변경 계열 명령은 거부할 수 있습니다.
하지만 공식 문서(Official Documentation)에 따르면, Read/Edit 규칙은 임의의 Python이나 Node.js 프로그램 등 간접적으로 파일을 여는 모든 자식 프로세스(Child Process)까지는 제어하지 않는다고 설명되어 있습니다. OS 레벨에서 완전히 차단하고 싶다면 샌드박스(Sandbox)도 검토해야 합니다.
이번 환경에서는 샌드박스를 활성화하여 실행하는 것이 정상적으로 이루어지지 않았기 때문에, 필수 요구 사항에는 포함하지 않고 Claude Code의 권한 규칙으로 검증 가능한 범위를 확인했습니다.
Settings 편집 중, 실수로 JSON에 //를 입력하여 다음과 같은 에러가 발생했습니다.
Expecting value: line 13 column 5
JSON에서는 주석을 사용할 수 없기 때문에, 주석 행을 삭제한 후 다시 확인했습니다.
구문 확인에는 다음 명령어를 사용했습니다.
python3 -m json.tool ~/.claude/xserver-log-analyzer-write-test.settings.json
설정 변경 후에는 Claude Code를 실행하기 전에 매번 이 명령어를 실행했습니다.
권한 설계가 올바르더라도 JSON 자체가 깨져 있으면 Settings 전체가 로드되지 않습니다. 공식 문서에서도 User·Project·Local 설정은 엄격하게 다뤄지며, 파일 검증에 실패하면 전체가 거부된다고 설명되어 있습니다.
Settings의 defaultMode는 처음에 plan으로 설정했습니다.
Plan Mode에서는 읽기와 계획이 중심이 되어 쓰기 검증 단계로 넘어갈 수 없습니다. 따라서 실제로 Write 도구의 확인 화면과 거부 결과를 보는 단계에서는 Manual Mode로 전환했습니다.
공식 문서에서 manual은 default의 별칭이며, CLI 상에서는 Manual로 표시됩니다.
이번 검증에서는 자동 승인되는 모드를 사용하지 않고, 반드시 사람이 결과를 확인할 수 있는 상태에서 진행했습니다.
쓰기 확인 화면에는 세션 중 지속 허용(Continuous Permission) 옵션도 표시되었습니다.
하지만 이번에는 권한 경계 그 자체를 검증하는 것이 목적이므로, "이번만 허용"을 선택했습니다.
지속 허용을 선택하면 이후의 확인 횟수가 줄어들어, Ask 규칙이 어떤 조작에서 발생하는지 추적하기 어려워집니다. 최소 권한 검증에서는 다소 번거롭더라도 한 번씩 확인하는 것이 더 안전합니다.
또한, 검증 종료 후에는 일반 세션을 실행하여 임시 허용이 남아 있지 않은지도 확인했습니다.
검증용 임시 파일이나 Settings가 남지 않도록 마지막에 삭제했습니다.
rm -rf /tmp/xserver-log-analyzer-claude-write-test
rm -rf /tmp/xserver-log-analyzer-permission-test
rm ~/.claude/xserver-log-analyzer-write-test.settings.json
그 후, 프로젝트의 작업 트리(Working Tree)에 변경 사항이 없는 것을 확인했습니다.
git status --short
검증용 Settings가 삭제된 것도 확인했습니다.
ls ~/.claude/xserver-log-analyzer-write-test.settings.json
검증에서는 성공 조건뿐만 아니라, 종료 후에 불필요한 권한 설정과 테스트 파일을 남기지 않는 것까지를 하나의 세트로 구성했습니다.
| 확인 항목 | 결과 |
|---|---|
경로가 포함된 Write(path) | 실행 시 경고가 발생하여 사용 중단 |
Edit(path)로 Write 도구의 신규 생성 제어 | 성공 |
/tmp/...를 절대 경로로 지정 | 예상대로 일치하지 않음 |
//tmp/...로 수정 | 절대 경로로 일치 |
| Ask 대상에 대한 신규 생성 | 확인 화면 이후 성공 |
| Deny 대상에 대한 신규 생성 | Error writing file로 거부 |
| Bash를 사용하지 않고 Write 도구만으로 생성 | 성공 |
| 지정된 파일 이외에는 변경하지 않음 | 확인 완료 |
| JSON 구문 확인 | python3 -m json.tool로 실시 |
| 검증 후 임시 파일 삭제 | 실시 완료 |
| Git 작업 트리에 대한 영향 | 없음 |
이번 검증에서 특히 중요했던 점은 다음 4가지입니다.
Claude Code 2.1.209에서는 경로가 포함된 Write(path)에 대해 실행 시 경고가 표시되었습니다.
새로 생성하는 작업을 Write 도구로 수행하는 경우에도, 권한 규칙은 Edit(path)로 제어할 수 있었습니다.
Read/Edit 규칙에서 맨 앞에 붙는 하나의 /는 파일 시스템 루트 (File System Root)를 나타내지 않습니다.
/path → Settings의 스코프 (Scope)를 기준으로 함
//path → 파일 시스템 루트로부터의 절대 경로 (Absolute Path)
Linux의 일반적인 경로 표기 방식과 같은 느낌으로 작성하면, 의도하지 않은 위치를 기준으로 해결(Resolve)되기 때문에 주의가 필요합니다.
저장해도 좋은 곳 → Ask
건드리면 안 되는 곳 → Deny
Deny가 Ask보다 우선되기 때문에, 허가 대상과 금지 대상을 명확하게 분리할 수 있습니다.
"소스 코드를 변경하지 마세요"라는 지시는 Claude의 행동 방침은 될 수 있지만, 강제적인 권한 경계 (Permission Boundary)는 아닙니다.
실제 거부는 Claude Code의 Deny 규칙을 통해 이루어집니다.
이번 목적은 Claude Code에게 단순히 쓰기 권한을 허용하는 것이 아니었습니다.
조사에 필요한 범위만 허용하고, 그 외에는 실제로 거부할 수 있다는 것을 작은 검증 환경에서 확인하는 것이 목적이었습니다.
검증 도중에는 다음과 같이 설정 예시를 살펴보는 것만으로는 알 수 없는 점들이 여러 가지 있었습니다.
Write(path)에 의한 실행 시 경고
/와 //의 의미 차이
JSON 주석에 의한 구문 오류 (Syntax Error)
Plan Mode에서는 쓰기 검증으로 진행할 수 없다는 점
Sandbox를 활성화한 실행이 환경상 잘 되지 않았던 점
최종적으로는,
허가 대상 → Edit(path)를 Ask
금지 대상 → Edit(path)를 Deny
절대 경로 → 맨 앞에 //
...
이라는 구성으로, 지정된 디렉터리에 대한 승인제 쓰기와 소스 코드 영역에 대한 쓰기 거부를 실제로 측정할 수 있었습니다.
Claude Code를 실운영에 도입할 때는 갑자기 운영 환경의 권한을 변경하지 말고, 먼저 /tmp와 같은 안전한 장소에서 Ask와 Deny를 모두 실제로 테스트해 보시는 것을 권장합니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Qiita AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기