에이전트 아키텍처의 보안 경계
에이전틱 아키텍처에서 보안 경계를 설정하기 위한 프레임워크입니다. 대부분의 에이전트는 에이전트 자체와 에이전트가 생성한 코드 사이에 어떤 격리도 없이 실행됩니다. 시크릿 주입부터 전체 애플리케이션 샌드박싱까지, 보안 경계를 어디에 설정해야 하는지 알아보세요.
오늘날 대부분의 에이전트는 생성한 코드를 실행할 때, 여러분의 시크릿에 무제한으로 접근할 수 있는 상태로 동작합니다.
파일 시스템을 읽고, 셸 명령을 실행하고, 코드를 생성하는 코딩 에이전트 패턴을 채택하는 에이전트가 점점 늘어나면서, 에이전트는 각기 다른 수준의 신뢰가 필요한 다중 컴포넌트 시스템으로 진화하고 있습니다.
기본 도구가 그렇게 작동하기 때문에 대부분의 팀은 이 모든 컴포넌트를 하나의 보안 컨텍스트에서 실행하지만, 보안 경계에 대해서는 다른 관점으로 접근할 필요가 있습니다.
이 글에서 다루는 내용은 다음과 같습니다:
에이전트 시스템의 구성 주체
각 주체 사이에 보안 경계를 어디에 설정해야 하는지
에이전트와 생성된 코드를 별도의 컨텍스트에서 실행하는 아키텍처
모든 에이전트가 코딩 에이전트를 닮아가고 있다
코딩 에이전트 아키텍처를 채택하는 에이전트가 점점 많아지고 있습니다. 이러한 에이전트는 파일 시스템을 읽고 쓰며, bash나 Python 같은 프로그램을 실행해 주변 환경을 탐색합니다. 그리고 특정 문제를 해결하기 위해 직접 코드를 생성하는 경우도 갈수록 늘고 있습니다.
"코딩 에이전트"로 마케팅되지 않는 에이전트도 코드 생성을 가장 유연한 도구로 활용합니다. 계정 데이터를 조회하기 위해 SQL을 생성하고 실행하는 고객 지원 에이전트도 같은 패턴이며, 단지 파일 시스템 대신 데이터베이스를 대상으로 할 뿐입니다. 스크립트를 직접 작성하고 실행할 수 있는 에이전트는 고정된 도구 호출만 가능한 에이전트보다 훨씬 넓은 범위의 문제를 해결할 수 있습니다.
경계가 없으면 어떤 일이 벌어지는가
프로덕션 장애를 디버깅하는 에이전트를 생각해 봅시다. 에이전트가 로그 파일을 읽는데, 그 안에 의도적으로 삽입된 프롬프트 인젝션(prompt injection)이 포함되어 있습니다.
인젝션은 에이전트에게 ~/.ssh와 ~/.aws/credentials의 내용을 외부 서버로 전송하는 스크립트를 작성하라고 지시합니다. 에이전트는 그 스크립트를 생성하고 실행하며, 인증 정보는 그대로 유출됩니다.
이것이 코딩 에이전트 패턴의 핵심 위험입니다. 프롬프트 인젝션을 통해 공격자가 에이전트에 영향력을 행사하고, 코드 실행이 그 영향력을 인프라에 대한 임의의 행동으로 전환합니다. 에이전트는 자체 컨텍스트에서 데이터를 유출하거나, 악성 소프트웨어를 생성하거나, 둘 다 하도록 조작될 수 있습니다. 이렇게 생성된 악성 소프트웨어는 인증 정보를 탈취하거나, 데이터를 삭제하거나, 에이전트가 실행되는 머신에서 접근 가능한 모든 서비스를 침해할 수 있습니다.
이 공격이 성립하는 이유는 에이전트, 에이전트가 생성한 코드, 인프라가 모두 동일한 수준의 접근 권한을 공유하기 때문입니다. 올바른 위치에 경계를 설정하려면, 각 컴포넌트가 무엇이고 어느 수준의 신뢰를 부여해야 하는지 이해해야 합니다.
에이전트 시스템의 네 가지 주체
에이전트 시스템에는 네 가지 주체가 존재하며, 각각 신뢰 수준이 다릅니다.
에이전트
에이전트는 컨텍스트, 도구, 모델로 정의되는 LLM 기반 런타임입니다. 에이전트는 에이전트 하네스(harness) 안에서 실행되는데, 하네스란 표준 SDLC를 통해 빌드하고 배포하는 오케스트레이션 소프트웨어, 도구, 외부 서비스 연결을 말합니다. 하네스는 다른 백엔드 서비스와 동일한 수준으로 신뢰할 수 있지만, 에이전트 자체는 프롬프트 인젝션과 예측 불가능한 동작의 대상입니다. 정보는 알 필요가 있는 범위에서만 공개해야 합니다. 예를 들어, SQL을 실행하는 도구를 사용하는 에이전트에게 데이터베이스 인증 정보를 직접 보여줄 필요는 없습니다.
에이전트 시크릿
에이전트 시크릿은 시스템이 작동하는 데 필요한 인증 정보로, API 토큰, 데이터베이스 인증 정보, SSH 키 등이 해당됩니다. 하네스가 이러한 시크릿을 책임감 있게 관리하지만, 다른 컴포넌트가 직접 접근할 수 있게 되면 위험해집니다. 아래에서 논의하는 아키텍처의 핵심은 결국 어떤 컴포넌트가 이 시크릿에 접근할 수 있는 경로를 갖느냐에 달려 있습니다.
생성된 코드 실행
에이전트가 만들고 실행하는 프로그램은 가장 예측 불가능한 요소입니다. 생성된 코드는 언어 런타임이 허용하는 모든 것을 할 수 있기 때문에, 네 가지 주체 중 위험을 판단하기 가장 어렵습니다. 이 프로그램이 외부 서비스와 통신하려면 인증 정보가 필요할 수 있지만, 생성된 코드에 시크릿 직접 접근 권한을 주면 프롬프트 인젝션이나 모델 오류 하나만으로도 인증 정보 탈취로 이어질 수 있습니다.
파일 시스템
파일 시스템과 그 외 실행 환경은 시스템이 동작하는 기반으로, 노트북, VM, 또는 Kubernetes 클러스터가 될 수 있습니다. 실행 환경은 하네스를 신뢰할 수 있지만, 에이전트가 전체 접근 권한을 갖거나 보안 경계 없이 임의의 프로그램을 실행하는 것까지 신뢰해서는 안 됩니다.
이 네 가지 주체는 모든 에이전트 시스템에 존재합니다. 문제는 이들 사이에 보안 경계를 설정하느냐, 아니면 모두 동일한 신뢰 도메인에서 실행하느냐입니다.
이러한 신뢰 수준에서 도출되는 설계 원칙은 다음과 같습니다:
하네스는 자체 인증 정보를 에이전트에 직접 노출해서는 안 됩니다
에이전트는 범위가 한정된 도구 호출을 통해 기능에 접근해야 하며, 해당 도구는 가능한 한 좁은 범위로 설계해야 합니다. 특정 고객을 지원하는 에이전트라면, 고객 ID 파라미터를 받는 범용 도구가 아니라 해당 고객의 데이터로 범위가 제한된 도구를 제공해야 합니다. 파라미터는 프롬프트 인젝션의 대상이 되기 때문입니다.
생성된 프로그램에 자체 인증 정보가 필요한 경우는 별도의 문제이며, 아래의 아키텍처에서 다룹니다
이 주체들과 원칙을 바탕으로, 실제 현장에서 사용되는 아키텍처를 보안 수준이 낮은 순서부터 높은 순서로 살펴보겠습니다.
경계 없음: 현재의 기본값
Claude Code와 Cursor 같은 코딩 에이전트에는 샌드박스 기능이 내장되어 있지만, 기본적으로 꺼져 있는 경우가 많습니다. 실제로 많은 개발자가 보안 경계 없이 에이전트를 실행합니다.
이 아키텍처에서는 네 가지 주체 사이에 아무런 경계가 없습니다. 에이전트, 에이전트의 시크릿, 파일 시스템, 생성된 코드 실행이 모두 하나의 보안 컨텍스트를 공유합니다. 개발자의 노트북에서는 에이전트가 .env 파일과 SSH 키를 읽을 수 있다는 뜻이고, 서버에서는 환경 변수, 데이터베이스 인증 정보, API 토큰에 접근할 수 있다는 의미입니다. 생성된 코드는 이 모든 것을 탈취하고, 데이터를 삭제하고, 실행 환경에서 접근 가능한 모든 서비스에 도달할 수 있습니다. 하네스가 특정 작업 전에 사용자에게 확인을 요청할 수는 있지만, 도구가 실행되고 나면 강제되는 경계는 존재하지 않습니다.
샌드박싱 없는 시크릿 주입
시크릿 주입 프록시(secret injection proxy)는 메인 보안 경계 바깥에 위치하여 아웃바운드 네트워크 트래픽을 가로채고, 요청이 의도된 엔드포인트로 향할 때만 인증 정보를 주입합니다. 하네스가 프록시에 인증 정보와 도메인 규칙을 설정하지만, 생성된 코드는 시크릿 원본 값을 절대 볼 수 없습니다.
프록시는 유출을 방지합니다. 시크릿은 실행 컨텍스트 밖으로 복사되어 재사용될 수 없습니다. 하지만 프록시가 활성 런타임 중의 오용까지 막지는 못합니다. 생성된 소프트웨어는 시스템이 실행되는 동안 주입된 인증 정보를 사용해 예상치 못한 API 호출을 여전히 수행할 수 있습니다.
시크릿 주입은 경계 없는 아키텍처에서 하위 호환성을 유지하며 전환할 수 있는 방법입니다. 컴포넌트의 실행 방식을 재구성하지 않고도 프록시를 추가할 수 있습니다. 다만 시크릿 자체를 제외하면 에이전트와 생성된 코드가 여전히 동일한 보안 컨텍스트를 공유한다는 트레이드오프가 있습니다.
모든 것을 함께 샌드박싱하는 것만으로는 부족한 이유
자연스러운 발상은 에이전트 하네스와 생성된 코드를 하나의 공유 VM이나 샌드박스로 감싸는 것입니다. 공유 샌드박스는 둘 다 외부 환경으로부터 격리하며, 이 점 자체는 분명히 유용합니다. 생성된 프로그램이 더 넓은 인프라에 침투하는 것을 막아주기 때문입니다.
그러나 공유 샌드박스 안에서는 에이전트와 생성된 프로그램이 여전히 동일한 보안 컨텍스트를 공유합니다. 생성된 코드는 여전히 하네스의 인증 정보를 탈취할 수 있고, 시크릿 주입 프록시가 있다 해도 프록시를 통해 인증 정보를 오용할 수 있습니다. 샌드박스는 환경을 에이전트로부터 보호하지만, 에이전트를 에이전트 자신이 생성한 코드로부터 보호하지는 못합니다.
에이전트 컴퓨팅과 샌드박스 컴퓨팅의 분리
빠져 있는 퍼즐 조각은 에이전트 하네스와 에이전트가 생성한 프로그램을 독립된 컴퓨팅 환경에서 실행하는 것입니다. 즉, 별도의 VM 또는 샌드박스에서 서로 다른 보안 컨텍스트로 분리하는 것입니다. 하네스와 하네스의 시크릿은 하나의 컨텍스트에 존재하고, 파일 시스템과 생성된 코드 실행은 에이전트 시크릿에 접근할 수 없는 별도의 컨텍스트에서 동작합니다.
Claude Code와 Cursor 모두 샌드박스 실행 모드를 제공하고 있지만, 데스크톱 환경에서의 도입률은 낮은 편입니다. 샌드박싱이 호환성 문제를 일으킬 수 있기 때문입니다. 클라우드에서는 이러한 분리가 훨씬 현실적입니다. 에이전트가 실행해야 하는 소프트웨어 유형에 맞게 최적화된 VM을 생성된 코드에 제공할 수 있어, 오히려 호환성이 개선될 수도 있습니다.
실제로 이 분리는 간단한 변경만으로 구현할 수 있습니다. 에이전트는 추상화 레이어를 통해 도구를 호출하는데, 이 추상화 덕분에 에이전트 자체를 재작성하지 않고도 코드 실행을 별도의 환경으로 라우팅하는 것이 자연스럽습니다.
두 워크로드는 컴퓨팅 특성이 매우 다르기 때문에, 분리하면 각각을 독립적으로 최적화할 수 있습니다. 에이전트 하네스는 대부분의 시간을 LLM API 응답을 기다리는 데 소비합니다. Vercel에서는 Fluid compute가 이 워크로드에 적합합니다. I/O 대기 중에는 과금이 멈추고 실제 CPU 활성 시간만 과금되므로, 유휴 시간이 아닌 실제 작업량에 비례한 비용 구조를 유지할 수 있습니다.
생성된 코드의 특성은 정반대입니다. 에이전트가 만든 프로그램은 수명이 짧고, 예측 불가능하며, 신뢰할 수 없습니다. 각 실행에는 깨끗하고 격리된 환경이 필요하여, 한 프로그램이 다른 프로그램이 남긴 시크릿이나 상태에 접근할 수 없어야 합니다. Vercel Sandbox 같은 샌드박스 제품은 실행 단위로 생성되었다가 종료 후 삭제되는 임시 Linux VM을 통해 이를 구현합니다. VM 경계가 보안 컨텍스트 분리를 강제하는 핵심이며, 샌드박스 내부의 생성된 코드는 하네스의 시크릿에 대한 네트워크 경로도, 호스트 환경에 대한 접근 권한도 갖지 않습니다.
샌드박스는 양방향으로 작동합니다. 생성된 코드로부터 에이전트의 시크릿을 보호하는 동시에, 생성된 코드가 하는 모든 행동으로부터 외부 환경을 보호합니다.
애플리케이션 샌드박스 + 시크릿 주입
가장 강력한 아키텍처는 애플리케이션 샌드박스와 시크릿 주입을 결합하는 것입니다. 이 조합은 어느 한쪽만으로는 달성할 수 없는 두 가지 속성을 제공합니다:
에이전트 하네스와 생성된 프로그램 간의 완전한 격리 — 각각 독립된 보안 컨텍스트에서 실행
생성된 코드의 인증 정보 직접 접근 차단 — 실행 중에는 주입 프록시를 통해 시크릿을 사용할 수 있지만, 직접 읽거나 유출할 수는 없습니다. 주입된 헤더는 샌드박스 코드가 동일한 이름으로 설정한 헤더를 덮어써서 인증 정보 치환 공격을 방지합니다.
프로덕션 에이전트 시스템에는 두 가지를 모두 결합하는 것을 권장합니다. 에이전트 하네스는 표준 컴퓨팅 환경에서 신뢰할 수 있는 소프트웨어로 실행합니다. 생성된 코드는 격리된 샌드박스에서 실행합니다. 시크릿은 네트워크 레벨에서 주입하며, 생성된 코드가 직접 접근할 수 있는 곳에는 절대 노출하지 않습니다.
에이전트 컴퓨팅과 샌드박스 컴퓨팅의 분리는 에이전트 시스템의 표준 아키텍처가 될 것입니다. 아직 대부분의 팀이 이 전환을 하지 않은 이유는 기본 도구가 이를 강제하지 않기 때문입니다. 지금 이 경계를 설정하는 팀은, 에이전트가 더 민감한 워크로드를 맡게 되었을 때 확실한 보안 우위를 갖게 될 것입니다.
안전한 시크릿 주입이 이제 Vercel Sandbox에서 사용 가능합니다.
