Claude Code 권한 게이트 해부: allow/deny/ask는 어떻게 갈리나

AI 코딩 에이전트에게 "이 파일 지워줘"를 시켰다고 하자. 어떤 요청은 바로 실행되고, 어떤 요청은 "정말요?"라고 되묻고, 어떤 요청은 아예 거절당한다. 이 갈림길이 어디서 갈라지는지 궁금해서 소스를 뜯어본 적이 있다. 겉보기엔 팝업창 하나가 뜨고 마는 단순한 확인 절차인데, 안쪽은 생각보다 층이 많았다.
층이 많은 이유는 단순하다. "허용해도 되는가"라는 질문 하나로는 실제 위험을 다 못 잡는다. 명령어 자체는 허용 목록에 있어도 뒤에 붙은 옵션이 위험할 수 있고, 같은 명령이라도 사람이 직접 시켰는지 하위 에이전트가 대신 요청했는지에 따라 누가 승인해야 하는지가 달라진다. 이 글은 그 갈림길, 즉 명령 실행 전 권한 판정 로직이 왜 3단 분기(허용·거부·확인질문)로 설계되는지를 다룬다. 특정 제품의 함수명이나 파일 경로 대신, 어느 AI 에이전트를 만들어도 마주치는 아키텍처 패턴으로 풀어본다.
허용·거부·확인질문, 세 갈래로 갈리는 이유
사람이 비서에게 심부름을 시키는 상황을 떠올려 보자. "우편함 확인해줘"는 그냥 시킨다. "내 통장에서 돈 빼줘"는 절대 안 시킨다. "이 이메일 답장 보내줘"는 초안을 보여달라고 한 번 확인한다. 세 가지 반응이 다 다르다. AI 에이전트의 명령 실행도 똑같다. 읽기 전용 조회는 곧장 허용하고, 되돌릴 수 없는 파괴적 작업은 아예 막고, 애매한 중간지대는 사람에게 한 번 물어본다.
이걸 이진 판정(허용/거부 둘 중 하나)으로 설계하면 둘 중 하나가 망가진다. 안전 쪽으로 몰면 매번 다 물어봐서 에이전트가 쓸모없어진다. 편의 쪽으로 몰면 위험한 명령까지 조용히 통과한다. 확인질문이라는 세 번째 갈래가 있어야 이 딜레마가 풀린다. 위험도가 낮으면 자동으로, 위험도가 확실히 높으면 차단으로, 판단이 갈리는 회색지대만 사람에게 넘긴다.
중요한 건 이 판정이 한 곳에서 한 번에 끝나지 않는다는 점이다. 명령이 실행되기까지 최소 두 개의 검사 층을 통과한다. 첫 번째 층은 규칙 기반의 일반 판정, 두 번째 층은 명령 내용을 직접 뜯어보는 세부 검사다. 두 층이 따로 있는 이유는 다음 장에서 설명한다.
규칙 문서로 미리 정하는 1차 판정
1차 판정은 미리 정해둔 규칙표를 찾아보는 일에 가깝다. "이 도구는 항상 허용", "이 명령 패턴은 항상 거부" 같은 규칙을 사용자나 팀이 문서로 정해두면, 에이전트는 매번 그 문서를 펼쳐 해당 규칙이 있는지부터 찾는다. 이때 규칙은 정적인 값이 아니라 실행 중에도 바뀌는 상태다. 사용자가 "이번엔 허용"이라고 한 번 답하면 그 결정이 이후 규칙에 반영되기도 한다. 그래서 이 층은 단순 조회가 아니라, 계속 갱신되는 정책을 읽고 쓰는 계층으로 봐야 한다.
여기서 자주 나오는 오해가 하나 있다. 규칙표에 명령어 이름 하나만 등록해두면 충분하다고 생각하는 것이다. 실제로는 그렇지 않다. 파일 삭제 도구를 허용 목록에 올렸다고 해서 그 도구로 시스템 전체를 지우는 명령까지 안전한 건 아니다. 도구 단위 허용과 명령 내용 단위 위험은 서로 다른 축이다. 이 간극을 메우는 게 다음 층의 역할이다.
또 하나, 실행 환경도 이 판정에 영향을 준다. 화면을 보며 실시간으로 답할 수 있는 상황(대화형)과, 사람이 자리를 비운 채 자동으로 돌아가는 상황(비대화형)은 같은 명령이라도 다르게 취급돼야 한다. 비대화형 상황에서 확인질문이 뜨면 아무도 답을 못 하니 그 자체가 사실상 거부로 끝난다. 그래서 실행 맥락(누가, 어떤 모드로 돌리는가)은 규칙 자체와 별개로 판정 시점에 함께 고려되는 런타임 정보로 다뤄야 한다.
같은 명령도 내용을 뜯어봐야 하는 2차 검사
규칙표 조회가 끝나도 아직 안심할 수 없다. 특히 자유 형식 명령어(셸 명령)를 실행하는 도구는 별도의 정밀 검사가 필요하다. 이유는 간단하다. 셸 명령은 "이름"이 아니라 "문장"이다. 같은 도구를 호출해도 뒤에 어떤 옵션과 인자를 붙이느냐에 따라 완전히 다른 일이 벌어진다.
비유하면 이렇다. 회사 정책에 "칼을 쓸 수 있다"는 규칙이 있다고 치자. 그런데 그 칼로 사과를 깎는지 타이어를 찢는지는 정책 이름만 봐서는 모른다. 실제로 뭘 하려는지 동작 하나하나를 봐야 안다. 셸 명령 검사가 하는 일이 이거다. 삭제 옵션이 강제로 걸려 있는지, 되돌릴 수 없는 초기화 명령인지, 파일 시스템의 민감한 경로를 건드리는지를 명령 문자열 자체에서 다시 분류한다.
경로 검사도 같은 결의 문제다. 에이전트가 접근하려는 파일 경로가 진짜로 작업 허용 범위 안에 있는지 확인해야 한다. 여기서 흔한 함정이 심볼릭 링크다. 겉보기엔 허용된 폴더 안의 파일 같지만, 실제로는 그 링크가 완전히 다른 곳을 가리킬 수 있다. 표면 경로만 보고 판정하면 이 우회를 못 잡는다. 링크를 따라가 실제 대상 경로까지 확인해야 진짜 판정이 된다.
이 두 번째 층이 왜 필요한지 정리하면, 1차 규칙은 "이 도구를 써도 되는가"를 묻고, 2차 검사는 "이번에 실제로 하려는 일이 안전한가"를 묻는다. 질문이 다르니 검사도 따로 있어야 한다. 하나만 있으면 나머지 절반의 위험이 그대로 새나간다.
확인질문은 누구에게 가는가
확인질문 갈래로 넘어가면 새로운 문제가 생긴다. "누구에게 물어볼 것인가"다. 사람이 화면 앞에 앉아 직접 시킨 작업이면 답은 간단하다. 그 사람에게 팝업을 띄우면 된다. 그런데 요즘 에이전트는 혼자 일하지 않는다. 상위 에이전트가 여러 하위 에이전트에게 작업을 나눠주는 구조, 즉 조율자와 작업자로 나뉜 위임 구조가 흔하다.
이 구조에서는 승인자가 고정돼 있지 않다. 하위 작업자가 위험한 명령을 요청하면, 그 승인 권한이 화면 앞의 사용자에게 갈 수도 있고, 작업을 배분한 상위 에이전트(조율자)에게 갈 수도 있고, 미리 정해둔 정책에 따라 자동으로 결정될 수도 있다. 요청을 만든 주체와 승인할 권한을 가진 주체가 다르다는 뜻이다. 이걸 요청 주체와 승인 주체로 나눠서 생각하면 명확해진다. 하위 작업자는 "이거 해도 되나요"라고 요청만 하고, 실제 승인 여부는 그 요청을 받을 자격이 있는 상위 계층에서 결정한다.
왜 이렇게 복잡하게 만들까. 위임 구조에서 승인 권한까지 하위 작업자에게 넘겨버리면, 여러 작업자가 동시에 서로 다른 위험한 명령을 각자 알아서 승인하는 상황이 생긴다. 통제가 사라진다. 승인 권한을 한 군데로 모아두면, 여러 작업자가 동시에 뭘 하고 있는지 한눈에 보이고 위험한 순간에 개입할 지점도 명확해진다. 그래서 이런 구조에서는 요청 처리 로직과 승인 처리 로직을 아예 다른 코드 경로로 분리해둔다. "인터랙티브 사용자용 확인질문"과 "위임 흐름용 확인질문"이 이름부터 다른 별개의 처리기로 존재하는 이유다.
여기에 감사 로그가 붙는다. 누가 요청했고 누가 승인했는지, 확인질문이 뜬 시점과 답변 시점을 기록해야 나중에 "이 명령이 왜 통과됐지"를 되짚을 수 있다. 실시간 확인만 하고 기록을 안 남기면, 사고가 난 뒤에 원인을 추적할 방법이 없다. 승인은 그 순간의 판단이지만 로그는 그 판단을 나중에 검증할 수 있는 유일한 증거다.
허용됐어도 어디까지 손댈 수 있는지는 다른 문제다
여기까지 "실행해도 되는가"를 다뤘다. 그런데 이것과는 결이 다른 질문이 하나 더 남는다. "실행을 허락하더라도, 어디까지 손댈 수 있게 둘 것인가"다. 이게 실행 격리(샌드박스) 영역이다.
비유하면, 손님에게 주방 출입을 허락하는 것과 냉장고 문을 다 열어두는 건 다른 결정이다. 요리를 허락했다고 냉동실 안쪽 재료까지 마음대로 쓰게 둘 필요는 없다. AI 에이전트도 마찬가지다. 어떤 명령이 실행 가능 판정을 받았다고 해서 파일 시스템 전체, 네트워크 전체에 자유롭게 접근하게 둘 이유는 없다. 작업에 필요한 최소 범위로 실행 공간 자체를 좁혀두고, 그 공간 밖으로 나가려는 시도는 권한 판정과 별개로 한 번 더 막는다.
그래서 실행 격리는 "허용/거부/확인질문" 3단 분기와 나란히 있는 또 하나의 축이다. 판정 로직이 "이 명령을 실행해도 되는가"를 정한다면, 격리 로직은 "실행되는 동안 어디까지 볼 수 있고 어디까지 바꿀 수 있는가"를 정한다. 둘을 하나로 섞으면 설계가 꼬인다. 판정은 허락 여부의 문제이고 격리는 반경의 문제라서, 판정 통과 후에도 격리 경계는 독립적으로 다시 적용돼야 한다.
이 구조를 실제로 접하고 나서 생각이 하나 바뀌었다. "위험한 명령을 막는다"는 목표를 한 겹의 확인창으로 해결하려던 게 애초에 무리한 접근이었다. 겹겹이 쌓인 이유는 각 층이 서로 다른 질문에 답하기 때문이다. 규칙표는 정책 질문에, 명령 내용 검사는 실제 동작 질문에, 승인자 결정은 권한 소재 질문에, 실행 격리는 반경 질문에 답한다. 네 가지 질문을 하나로 뭉뚱그리면 그중 하나는 반드시 구멍이 난다.
권한 게이트를 설계할 때 점검할 것
직접 비슷한 걸 설계하거나 리뷰할 일이 생기면, 아래 표로 층마다 뭘 확인해야 하는지 정리해뒀다.
| 검사 층 | 답하는 질문 | 놓치기 쉬운 지점 |
|---|---|---|
| 규칙 기반 1차 판정 | 이 도구를 써도 되는가 | 규칙이 실행 중 갱신되는 상태라는 점, 대화형/비대화형 맥락 차이 |
| 명령 내용 2차 검사 | 이번에 하려는 일이 실제로 안전한가 | 도구 이름만 보고 내용(옵션·인자)은 안 보는 경우 |
| 경로 검증 | 접근하려는 대상이 허용 범위 안인가 | 심볼릭 링크로 표면 경로와 실제 대상이 달라지는 우회 |
| 승인자 라우팅 | 확인질문을 누구에게 보낼 것인가 | 위임 구조에서 요청 주체와 승인 주체를 같게 취급하는 실수 |
| 실행 격리 | 허용된 실행이 어디까지 손댈 수 있는가 | 판정 통과 후 격리 경계를 다시 확인하지 않는 설계 |
| 감사 로그 | 누가 언제 무엇을 승인했는가 | 실시간 확인만 하고 사후 추적 기록을 안 남기는 경우 |
이 표를 체크리스트로 바꾸면 이렇다.
- 도구 이름 단위 허용 목록과 명령 내용 단위 위험 분류를 같은 것으로 착각하지 않았는가.
- 비대화형(자동 실행) 모드에서 확인질문이 뜨는 명령이 남아 있지 않은가.
- 파일 경로 검증이 심볼릭 링크의 실제 대상까지 따라가는가.
- 위임 구조에서 하위 작업자가 스스로 승인까지 끝내는 경로가 없는가.
- 실행 허용과 실행 격리 범위를 같은 판정 한 번으로 퉁치지 않았는가.
- 확인질문의 요청자·승인자·시각이 로그로 남는가.
이 원칙은 코딩 에이전트에만 해당하지 않는다. 결제를 대신 처리하거나 이메일을 대신 보내는 에이전트를 설계할 때도 똑같은 질문이 반복된다. AI 에이전트에게 일을 맡기기 전에 계약을 정하는 법도 결국 같은 뿌리에서 나온 이야기다. 무엇을 자동으로 허용할지, 무엇을 절대 허용하지 않을지, 애매한 영역은 누구에게 물어볼지를 미리 정해두는 것. 권한 게이트는 그 결정을 코드로 옮겨놓은 것뿐이다.
아직 댓글이 없습니다.