
로컬 AI Gateway에 Execution Control을 구현했습니다
요약
로컬 AI Gateway에 LLM의 툴 호출을 안전하게 제어하기 위한 Execution Control 계층을 구현했습니다. Resolver, Execution Policy, Executor를 통해 LLM의 명령이 허가된 범위 내에서만 실행되도록 관리합니다.
핵심 포인트
- LLM의 툴 호출(Tool Use) 시 발생할 수 있는 보안 리스크 방지
- Resolver를 통해 가공되지 않은 커맨드를 정형화된 operation 명으로 변환
- Execution Policy를 통한 allowlist 기반의 실행 권한 제어
- 허가되지 않은 명령은 실행을 차단하여 프롬프트 인젝션 등 위험 최소화
지난 기사에서는 로컬 AI Gateway에 Provider Adapter를 구현했습니다.
이번에는 해당 게이트웨이에
Execution Control
을 추가로 구현한 내용을 소개합니다.
참고로, LLM의 툴 호출 (Tool Use) 자체는 이전에 이 기사에서 테스트해 보았습니다.
왜 Execution Control이 필요한가
최근의 LLM은 텍스트를 반환하는 것에 그치지 않습니다.
툴 호출 (Anthropic의 Tool Use / OpenAI의 Function Call)
을 반환함으로써, AI가 커맨드 실행이나 파일 조작 등을 지시할 수 있게 되었습니다.
이는 AI 에이전트의 기반이 되는 메커니즘이지만, 동시에 새로운 리스크이기도 합니다.
- LLM의 출력은 반드시 신뢰할 수 있는 것은 아니다
- 프롬프트 인젝션 (Prompt Injection)으로 인해 의도하지 않은 커맨드가 유발될 가능성이 있다
- 실행되는 조작의 권한이 과도해지기 쉽다
LLM이 "실행하고 싶다"라고 말한 것을
그대로 실행해도 되는지는 별개의 문제
입니다.
문제는 "LLM의 툴 호출이 그대로 실행되는 것"
툴 호출을 제어 없이 실행하면 다음과 같은 상태가 됩니다.
git status와 같은 안전한 조작도, git push와 같이 외부로 영향을 미치는 조작도
구분 없이 실행되어 버립니다.
필요한 것은 LLM의 출력과 실행 사이에
"실행해도 되는가"를 판단하는 계층
을 두는 것입니다.
구현한 내용
LLM의 툴 호출을 실행 전에 평가하는 Execution Control을 구현했습니다.
구현한 것은 다음 세 가지입니다.
- Resolver: 툴 호출의 입력을 operation 명으로 변환한다
- Execution Policy: operation을 allowlist로 평가한다
- Executor: 허가된 operation만을 실행한다
엔드포인트는 /v1/gateway/chat 그대로 유지하며, Gateway가 내부적으로 2턴의 에이전트 루프 (Agent Loop)를 처리합니다.
아키텍처
처리 흐름은 다음과 같습니다.
- 클라이언트의 요청을 LLM으로 전달한다
- LLM이 툴 호출을 반환하면, Resolver가 operation 명으로 변환한다
- Execution Policy가 allow / deny를 판정한다
- allow라면 Executor가 실행하고, 툴 실행 결과를 LLM에 반환한다 (deny라면 거부 메시지를 반환한다)
- LLM의 최종 응답을 클라이언트에 반환한다
deny의 경우, 외부 커맨드는 실행되지 않습니다.
툴 정의
툴 정의는 YAML로 기술합니다.
name: bash
description: "Execute a shell command after execution policy evaluation."
input_schema:
...
이 정의는 기동 시에 읽히며, LLM으로의 요청에 자동으로 부가됩니다.
프로바이더 고유의 형식으로의 변환은 지난번에 구현한 각 Adapter가 수행합니다.
Resolver를 통한 operation 해결
LLM이 반환하는 툴 호출은 가공되지 않은 커맨드 문자열입니다.
이를 그대로 정책 평가에 사용하면, 커맨드의 변형(variation)마다 규칙이 필요하게 됩니다.
따라서 Resolver가
커맨드의 프리픽스 (Prefix)를 operation 명으로 변환합니다.
mappings:
- prefix: "git status"
operation: git.status
...
예를 들어 git status -s도 git status --short도 동일한 git.status로 취급됩니다.
매칭되는 규칙이 없는 경우에는 unknown이 됩니다.
Execution Policy를 통한 실행 판단
operation별 실행 가부를 YAML로 정의합니다.
yool: bash
category: git
enabled: true
...
여기서 중요한 것은
allowlist 방식
이라는 점입니다.
executions에 존재하지 않는 operation은 모두 deny가 됩니다.
git push 규칙을 쓰는 것을 잊어버려도, 거부 쪽으로 처리됩니다.
감사 로그(Audit Log)에 기록
도구 호출 (Tool Call)이 발생하면, 감사 로그 (Audit Log)에 execution 필드가 추가됩니다.
allow의 예시입니다.
{
"action": "forwarded",
"execution": {
...
deny의 예시입니다.
{
"execution": {
"tool": "bash",
...
LLM이 무엇을 실행하려고 했는지, 그리고 Gateway가 어떻게 평가하고 판단했는지를 나중에 추적할 수 있습니다.
구현 시 고려한 점
페일세이프 (Fail-safe)
allowlist 방식이기 때문에, 정의되지 않은 operation은 기본적으로 deny 됩니다.
이는 Policy Engine의 프로바이더 모델 제어 (Provider-model control)와 동일한 개념입니다.
책임의 분리 (Separation of Concerns)
Resolver는 "무엇을 실행하려고 하는가"를 해결하고, Execution Policy는 "실행해도 되는가"를 판단합니다.
기밀 정보 탐지에서의 Detector와 Policy Engine의 관계와 동일한 구조입니다.
설정의 코드 분리
도구 정의와 실행 규칙 모두 YAML로 관리합니다.
허용할 operation을 추가하거나 변경할 때, 코드 수정은 필요하지 않습니다.
SSK 설계 패턴과의 대응
이번 구현은 SSK에서의 AI Gateway가 "출력을 제어하는" 구현 사례입니다.
LLM의 출력인 도구 호출을 신뢰하지 않는다는 전제하에 다루며,
실행 전에 검증 및 제어하는
설계를 실현했습니다.
요약
- LLM의 도구 호출을 그대로 실행하면 과도한 권한에 의한 조작 리스크가 있음
- LLM의 출력과 실행 사이에 실행 가능 여부를 판단하는 Execution Control을 구현함
- Resolver가 명령어를 operation 명으로 변환하고, Execution Policy가 allowlist로 평가함
- 정의되지 않은 operation은 페일세이프로서 deny 처리됨
- 감사 로그에 execution을 기록하여 무엇을 실행하려 했고 어떻게 판단했는지 추적 가능하게 함
Discussion

AI 자동 생성 콘텐츠
본 콘텐츠는 Zenn AI의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기