엔지니어들이 실제로 던지는 질문
LLM 접근 제어(access controls) 및 모니터링에 대한 검색 트래픽은 대부분 이미 에이전트를 배포했고, 이제 무엇을 로깅해야 할지 알고 싶어 하는 사람들입니다. 이것은 문제의 잘못된 끝단에 초점을 맞추고 있습니다. 로깅은 무슨 일이 일어났는지 알려줍니다. 접근 제어는 무슨 일이 일어날 수 있는지 결정합니다. 만약 제어가 잘못된 위치에 있다면, 로그는 단지 피해를 기록한 것에 불과합니다.
이 글은 제어가 어디에 속해야 하는지, 그것이 잘못 배치되었을 때 무엇이 깨지는지, 그리고 reskSecure와 ReskPoints로 어떻게 구현할 수 있는지에 관한 것입니다.
여기서 AI 에이전트 보안이란 무엇인가
AI 에이전트 보안은 자율적이거나 반자율적인 LLM 시스템이 보유한 자격 증명(credentials)으로 무엇을 할 수 있도록 제약하는 학문입니다. 이것은 프롬프트 필터링이 아닙니다. 모델 정렬(model alignment)도 아닙니다. 이는 다른 모든 특권 통합(privileged integration)과 같은 문제입니다. 토큰을 가진 행위자(actor)가 요청을 보내고, 당신은 어떤 요청이 합법적인지 결정해야 합니다.
차이점은 그 행위자가 비결정적(non-deterministic)이라는 것입니다. 전통적인 서비스는 자신의 코드가 이름을 붙인 엔드포인트들을 호출합니다. 에이전트는 신뢰할 수 없는 출처에서 올 수 있는 텍스트를 기반으로, 모델이 실행 시간에 엔드포인트를 호출한다는 것입니다.
공격 표면(attack surface), 구체적으로
세 가지 도구(고객 기록 읽기, 환불 처리, 이메일 보내기)를 가진 지원 에이전트를 가정해 봅시다. 이 통합은 세 가지 모두를 할 수 있는 서비스 토큰으로 한 번 인증합니다.
이제 에이전트가 고객 메시지를 읽습니다. 그 메시지에는 모델이 자신의 작업의 일부로 취급하는 지침이 포함되어 있습니다. 모델은 해당 메시지에서 가져온 금액과 계좌 번호로 환불 도구를 호출합니다.
토큰은 유효했습니다. 호출은 잘 구성되었습니다. 요청 경로의 어떤 것도 잘못되지 않았습니다. 단지 잘못된 것은, 모델에게 호출자가 결코 호출할 권한이 없었던 도구를 선택하도록 허용했다는 것입니다.
이것은 가상의 버그 클래스가 아닙니다. 이것은 에이전트에게 필요한 모든 기능을 포괄하는 하나의 자격 증명을 부여함으로써 발생하는 직접적인 결과입니다. 단일 주입된 명령어의 폭발 반경(blast radius)은 그 자격 증명의 범위와 같습니다.
일반적인 배치가 실패하는 이유
대부분의 구현체는 도구 핸들러 내부에서 권한을 확인합니다. 흐름은 다음과 같습니다:
- 에이전트 인증.
- 모델에 도구 정의 전송.
- 모델이 도구를 선택하고 인수를 생성합니다.
- 핸들러가 호출자를 검증하고 실행합니다.
4단계는 너무 늦습니다. 핸들러가 실행될 때쯤이면, 이미 도구가 선택되었고 인수들은 모델 출력으로부터 구성되었습니다. 호출을 거부할 수는 있지만, 이미 신뢰할 수 없는 텍스트가 도구 선택을 주도하도록 내버려 두었습니다. 검사 이전에 발생하는 모든 부작용(downstream calls를 포함하여 핸들러가 검증하는 동안 수행하는 호출)은 당신의 통제 밖에 있습니다.
순서 자체가 취약점입니다.
이를 막는 메커니즘
결정을 모델보다 앞당기세요. 제어는 식별자 해석(identity resolution)과 도구 노출 사이에 존재해야 합니다.
- 요청으로부터 호출자의 식별자를 가져오고, 모델로부터 가져오지 마십시오.
- 그 식별자를 명시적인 허용 목록(allowlist)의 도구 이름에 매핑합니다.
- 허용된 도구만 모델에 노출합니다.
- 인수가 평가되기 전에 목록에 없는 모든 도구 이름을 거부합니다.
- 결정, 도구 이름, 인수, 그리고 결과를 기록합니다.
두 가지 속성이 중요합니다. 첫째, 허용 목록은 호출자로부터 파생되므로 모델이 자체 범위를 넓힐 수 없습니다. 둘째, 거부는 인수 평가 이전에 발생하므로 잘못되었거나 적대적인 인수가 핸들러에 도달하는 것을 막습니다.
모니터링은 이것 위에 놓입니다. 모든 허용 및 거부 결정은 이벤트입니다. '거부'는 흥미로운 것입니다. 이는 무언가가 자신의 범위를 벗어나려고 시도했음을 의미합니다. 한 식별자로부터의 거부 급증(spike)은 경고할 가치가 있는 신호입니다.
RESK를 사용한 구현
reskSecure는 툴 정의가 모델에 전달되기 전에 경계(boundary)에서 허용 목록(allowlist)을 강제합니다. 각 ID가 어떤 툴을 호출할 수 있는지 선언하며, reskSecure는 그 집합 밖에 있는 모든 것을 거부합니다. 따라서 모델은 자신이 호출할 권한이 없는 툴을 절대 보지 못하므로 선택할 수도 없습니다.
ReskPoints는 의사 결정 흐름(decision stream)을 기록합니다. 각 항목에는 ID, 툴 이름, 인자, 그리고 호출이 허용되었는지 거부되었는지가 포함됩니다. 이를 통해 사고 발생 후 애플리케이션 로그에서 의도를 재구성할 필요 없이 감사 추적(audit trail)과 경고 표면(alerting surface)을 한 곳에서 얻을 수 있습니다.
이 둘은 문제의 두 절반을 다룹니다: reskSecure가 결정하고, ReskPoints가 기록합니다. 둘 중 어느 것도 단독으로는 유용하지 않습니다. 거부 기록이 없는 허용 목록은 맹목적입니다. 강제(enforcement)가 없는 로그는 일기장일 뿐입니다.
체크리스트
- 요청으로부터 호출자 ID를 확인하고, 모델 출력으로부터는 절대 확인하지 마십시오.
- 전역 에이전트 설정에서가 아니라 ID로부터 툴 허용 목록을 도출하십시오.
- 인자가 평가되기 전에 허용되지 않은 툴 이름은 거부하십시오.
- 모델에게는 허용된 툴만 노출시키십시오.
- ID, 툴 이름, 인자, 결과와 함께 모든 허용 및 거부를 기록하십시오.
- ID별 거부 급증(deny spikes)에 대해 경고를 설정하십시오.
- 다른 모든 특권 접근과 동일한 주기로 허용 목록을 검토하십시오.
에이전트에게 최소 권한 원칙(least privilege)을 강제하세요: https://resk.fr/projects/resksecure.html