당신의 AI 에이전트가 sudo 권한을 가지고 있습니다. 이를 회수하기 위한 도구를 만들었습니다.
요약
AI 에이전트의 과도한 권한 남용을 방지하기 위해 최소 권한 원칙을 적용하는 CLI 도구인 AgentPerms를 소개합니다. MCP(Model Context Protocol) 환경에서 에이전트의 동작을 관찰하고, 필요한 권한만 추출하여 강제함으로써 보안 위협을 차단합니다.
핵심 포인트
- MCP 에이전트의 파일 시스템 및 데이터베이스 접근 권한 제어
- 관찰, 추론, 잠금, 강제 적용의 4단계 보안 워크플로우 제공
- 투명한 stdio 프록시 방식을 통해 클라이언트 수정 없이 보안 적용
- SSH 키 유출, 데이터 삭제 등 다양한 공격 시나리오 차단
몇 주 전, 저는 MCP를 통해 AI 에이전트에게 제 머신에 대한 접근 권한을 부여했습니다. 에이전트는 파일을 읽고, PR(Pull Request)을 열고, 데이터베이스를 쿼리했습니다. 정말 훌륭했습니다 — 도구 설명(tool description)이 오염되거나 프롬프트 인젝션(prompt injection)이 통과되었을 때 _무엇을 할 수 있었을지_를 생각하기 전까지는 말이죠.
그 답은 '무엇이든 가능하다'였습니다. ~/.ssh/id_rsa. DROP TABLE users. rm -rf /. 에이전트는 sudo 권한을 가지고 있었고, 아무도 그것에 투표한 적이 없었습니다.
그래서 저는 **AgentPerms**를 만들었습니다 — 이는 다른 프로세스를 잠그는 방식과 동일하게 MCP 에이전트에게 최소 권한(least-privilege permissions)을 부여하는 CLI입니다. 즉, 실제로 필요한 최소한의 것을 파악하고, 고정(pin)하고, 증명하며, 강제(enforce)하는 방식입니다.
pip install agentperms
아무도 채우지 않았던 간극
MCP (Model Context Protocol)는 조용히 AI 툴링의 USB-C가 되어가고 있습니다. Claude Desktop, Cursor, VS Code, Windsurf, Gemini CLI — 이들은 모두 MCP를 사용합니다. 이는 멋진 일이지만, 동시에 당신의 에이전트가 설정 파일 하나만으로 당신의 파일 시스템, 리포지토리(repos), 편지함, 그리고 운영 환경(prod)에 접근할 수 있음을 의미합니다.
기존 도구들은 각각 작업의 _일부_만을 수행합니다:
- **스캐너(Scanners)**는 무언가 위험해 _보인다_고 알려줍니다. 그러고 나면 떠납니다. 당신에게는 여전히 위험한 요소가 남아 있습니다.
- **방화벽(Firewalls) / 허용 목록(allowlists)**은 에이전트가 실제로 무엇을 사용할지 알기도 전에 미리 YAML 파일을 직접 작성하게 만듭니다.
그 어느 것도 루프를 완성하지 못합니다. 제가 원했던 것은 우리가 다른 모든 것에 이미 사용하고 있는 지루하지만 검증된 보안 워크플로우였습니다: 실제 동작 관찰(observe real behavior) → 최소 권한 도출(derive least privilege) → 강제 적용(enforce it) → CI에서 정직하게 유지(keep it honest in CI).
이것이 파이프라인으로서의 AgentPerms의 전체 논지입니다:
기록(record) → 추론(infer) → 잠금(lock) → 재생(replay) → 강제(enforce)
30초 만에 확인하기 (설정 불필요, 네트워크 불필요)
AgentPerms에는 의도적으로 과도한 권한을 부여한 데모 MCP 서버가 포함되어 있어, 아무것도 연결하지 않고도 실제 정책 결정 과정을 지켜볼 수 있습니다:
# 위험한 설정 탐지: ~/.ssh 마운트 및 고정되지 않은 npx 서버
agentperms scan --path examples/vulnerable-mcp-demo
...
출력 결과:
8/8 attacks blocked.
SSH 키 유출 (SSH-key exfiltration), .env 파일 읽기, rm -rf /, 승인되지 않은 이메일 발송, 강제 푸시 (force-push), 리포지토리 삭제, 파괴적인 SQL — 이 모든 공격이 서버에 도달하기 _전_에 거부되거나 사람의 승인 단계로 라우팅되었습니다.
핵심 전략: 프록시 (proxy)가 되는 것
제가 가장 자랑스럽게 생각하는 부분입니다. AgentPerms는 에이전트에게 협조를 요청하지 않으며, 클라이언트를 패치하지도 않습니다. 대신 MCP 클라이언트의 설정을 재작성하여 모든 서버가 **투명한 stdio 프록시 (transparent stdio proxy)**를 통해 실행되도록 합니다:
Agent → AgentPerms proxy → MCP server
│
├─ record: 모든 tools/call을 기록한 후 전달
...
프록시는 실제 서버를 서브프로세스 (subprocess)로 생성하고 양방향으로 줄바꿈으로 구분된 JSON-RPC를 펌핑합니다. 프록시는 tools/call 요청을 가로채고 tools/list 응답을 캡처합니다. 그게 전부입니다. 에이전트는 프록시가 존재한다는 사실조차 알 수 없습니다.
서버 엔트리는 다음과 같이 변경됩니다:
{ "command": "python3", "args": ["server.py"] }
다음과 같이 변경됩니다 (원래 명령은 -- 뒤에 보존되며, 롤백할 수 있도록 .agentperms.bak 파일이 생성됩니다):
{
"command": "/usr/bin/python3",
"args": ["-m", "agentperms", "_proxy",
...
record 모드에서는 기록하고 전달합니다. enforce 모드에서는 먼저 평가를 수행하며, 거부(DENY) 시 서버로 전달하지 않고 클라이언트에 합성된 (synthetic) JSON-RPC 에러를 반환합니다. 거부된 호출은 서버에 절대 닿지 않습니다.
실제 동작을 기록하고, 최소 권한을 추론하라
정책을 직접 작성할 필요는 없습니다. 기록 기능을 켠 상태로 한동안 에이전트를 평소처럼 사용하면 됩니다:
agentperms record --client cursor
# ... 에이전트 사용 ...
agentperms infer # traces -> mcp.policy.yaml
infer는 핵심적인 명령어입니다. 이 명령어는 트레이스 (traces)를 읽어 에이전트가 실제로 수행했던 작업은 허용하면서도, 권한은 최소화한 정책을 생성합니다:
- 에이전트가 호출한 도구들은
allowed_tools가 됩니다. - 에이전트가 접근한 디렉토리들은 가장 작은 범위의
allowed_paths집합으로 압축됩니다. - 알려진 위험 카테고리 (shell, 리포지토리 삭제, 이메일 발송, DB 쓰기)는 즉시
denied_tools또는 사람의 승인 단계로 배정됩니다.
그 결과물은 마치 보안 검토 전문가가 당신을 위해 작성한 것처럼 보입니다:
당신의 에이전트는 읽기 전용 (read-only) GitHub 호출과 로컬
./src접근만 사용했습니다. 셸 (shell), 홈 디렉토리 (home directory), 비밀 정보 (secrets), Gmail 전송 (Gmail send), 또는 데이터베이스 쓰기 (database write) 권한은 필요하지 않습니다.
단일 결정 권한
무엇을 하든, 허용/거부/승인을 결정하는 곳은 반드시 단 하나여야 합니다. 그렇지 않으면 오프라인 테스트와 실제 실행 환경에서의 강제 적용 (enforcement)이 서로 어긋나게 되며, 당신은 거짓을 테스트하게 됩니다.
AgentPerms에서는 이것이 단일 evaluate(policy, server, tool, args) 함수로 구현되어 있으며, 실제 프록시 (proxy)와 오프라인 replay 모두에 의해 호출됩니다. 먼저 일치하는 규칙이 우선합니다 (First-match-wins):
- 사람 승인 목록에 있는 경우 → 승인 필요 (require approval)
denied_tools에 있는 경우 → 거부 (deny)- 경로 인자 (path argument)가
denied_paths/denied_patterns에 걸리는 경우 → 거부 (deny) allowed_tools가 설정되어 있고 도구가 그 안에 없는 경우 → 거부 (deny) (기본 거부 정책, default-deny)allowed_paths가 설정되어 있고 경로가 그 범위를 벗어나는 경우 → 거부 (deny)- 그 외의 경우 → 허용 (allow)
빈 정책은 모든 것을 허용합니다. 어떤 서버라도 제약이 걸리는 순간, 알 수 없는 서버들은 기본적으로 거부 (default-deny)됩니다. replay에서 테스트하는 것은 프로덕션에서 실행되는 것과 바이트 단위로 동일합니다. 왜냐하면 동일한 코드 경로 (code path)를 사용하기 때문입니다.
정책 자체는 작고 검토 가능한 상태로 유지됩니다:
version: 1
servers:
github:
...
도구 오염 (Tool poisoning): 신원 고정
당신이 신뢰한 이후에 서버가 도구의 설명 (description) 또는 _스키마 (schema)_를 몰래 변경하는 교묘한 MCP 공격 유형이 있습니다. 모델은 이를 다시 읽고 조용히 다시 지시를 받게 됩니다. 따라서 AgentPerms는 도구의 신원 (identity)도 잠급니다:
agentperms lock # 모든 도구의 이름/설명/스키마를 해시 (hash) 처리
agentperms lock --check # 변경 사항이 있으면 실패 처리
CI에 lock --check를 포함시키면, 오염된 도구가 사용자에게 도달하기 전에 빌드를 실패시킵니다.
코드베이스의 일부로 만들기
agentperms init # .github/workflows/agentperms.yml 스캐폴딩 (scaffolds)
모든 push/PR 시 다음이 실행됩니다:
agentperms scan --path . # 위험한 설정 노출
agentperms lock --check # 도구 오염 시 실패 처리
agentperms replay # 정책이 공격을 차단하지 못하게 되면 실패 처리
mcp.policy.yaml과 mcp.lock을 커밋하면, 에이전트의 권한은 다른 보안 태세 (security posture)의 일부와 마찬가지로 검토 가능하고, 버전 관리가 되며, 강제 적용 가능한 산출물 (artifact)이 됩니다.
아직 지원하지 않는 기능
과장하기보다는 솔직하게 말씀드리겠습니다:
- 전송 (Transport): 현재는 로컬 stdio MCP 서버만 지원합니다. HTTP/SSE는 로드맵에 포함되어 있습니다.
- 승인 (Approvals): 터미널에서 프롬프트가 나타납니다. 개발 단계에서는 괜찮지만, 아직 대규모 운영 (fleet-grade) 워크플로우 수준은 아닙니다.
- 라이브 대시보드와 Node 래퍼 (wrapper)가 다음 개발 예정 사항입니다.
사용해 보기
pip install agentperms
agentperms scan --path examples/vulnerable-mcp-demo
agentperms replay --policy examples/policies/example.mcp.policy.yaml
실제 시스템에 대한 실제 접근 권한을 가진 에이전트를 운영 중이시라면, 여러분의 피드백을 진심으로 기다리고 있습니다. 특히 정책 모델 (policy model)과 리플레이 팩 (replay pack)에 어떤 형태의 공격 (attack shapes)을 포함하고 싶은지에 대해 의견을 주시면 감사하겠습니다. 이슈 (Issues)와 풀 리퀘스트 (PRs)는 언제나 환영합니다.
당신의 에이전트에게는 sudo 권한이 필요 없습니다. 이제 그 권한을 회수합시다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기