신뢰할 수 없는 코드를 안전하게 실행하려면 호스트와의 격리만으로는 부족하다. 그 코드가 외부에서 무엇에 접근할 수 있는지까지 반드시 통제해야 한다.
AI 에이전트가 파일 읽기, 명령 실행, 패키지 설치, 코드 생성 등의 능력을 갖추면서 이 문제는 더욱 중요해졌다. 마이크로VM은 코드가 호스트나 다른 워크로드에 접근하는 것을 막을 수 있다. 하지만 그것만으로는 코드가 데이터를 외부로 유출하거나, 내부 서비스를 탐색하거나, 인터넷상의 다른 시스템을 공격하거나, 환경 내에서 사용 가능한 자격 증명을 악용하는 것까지는 막을 수 없다.
아웃바운드 트래픽 제어 없는 격리는 프로세스를 가둘 뿐, 그 결과까지 막지는 못한다.
완전한 샌드박스라면 컴퓨팅 격리와 함께 네트워크를 통해 행사할 수 있는 권한, 즉 코드가 어디에 연결할 수 있는지, 어떤 자격 증명을 사용할 수 있는지, 워크로드 실행 중 이 권한이 어떻게 변하는지까지 모두 통제해야 한다. 이런 통제 장치들은 보안 경계의 핵심이지, 나중에 덧붙이는 부가적인 보호 수단이 아니다.
컴퓨팅 격리는 중요한 질문 하나에 답한다. 이 프로그램이 실행 중인 머신에서 무엇에 접근할 수 있는가? 네트워크 격리는 또 다른 질문에 답한다. 네트워크를 통해 무엇에 접근하거나 공격할 수 있는가?
저장소를 읽고 생성된 코드를 실행하는 에이전트를 생각해보자. 이슈, 로그 항목, 의존성, 소스 파일 어딘가에 숨겨진 프롬프트 인젝션이 에이전트에게 개인 데이터를 업로드하도록 지시할 수 있다. 생성된 프로그램이 마이크로VM을 탈출할 필요는 없다. 아웃바운드 트래픽에 제한이 없다면, 읽을 수 있는 모든 것을 외부 서버로 그냥 전송하면 그만이다.
같은 방식으로 내부 네트워크를 스캔하거나, 데이터와 자격 증명을 탈취하거나, 인증된 API를 호출하는 것도 가능하다. 공격자 입장에서는 VM 경계를 넘을 필요조차 없다. 네트워크 경계가 없다면, 그것은 반쪽짜리 샌드박스일 뿐이다.
최근 보안 연구는 한 가지 패턴을 명확히 보여준다. 신뢰할 수 없는 코드가 격리를 벗어나기 위해 VM 경계를 넘을 필요는 없다는 것이다. 보안 모델이 미처 고려하지 못한 네트워크 경로 하나만 있으면 충분하다.
그 경로는 완전히 차단된 환경에서 열려 있는 DNS 리졸버일 수도 있고, 기본값이 허용인 빈 허용 목록일 수도 있으며, 정책 엔진과 프록시가 서로 다르게 해석하는 호스트명이나, 릴레이로 악용되는 신뢰할 수 있는 패키지 서비스일 수도 있다. 이 중 어느 하나만으로도 신뢰할 수 없는 코드는 데이터를 유출하고, 지령을 받고, 더 민감한 인프라로 이동하는 통로를 확보할 수 있다.
이것들은 컴퓨팅 탈출이 아니다. 커널, VM, 컨테이너 경계가 설계한 대로 정상 작동하는 중에도 격리는 실패할 수 있다. 실질적인 보안 경계에는 DNS, 프록시, 인증 서비스, 내부 네트워크, 그리고 의도적으로 허용된 모든 목적지까지 포함된다.
이를 탈출이라고 부르든 우회라고 부르든, 요구 사항은 동일하다. 샌드박스는 신뢰할 수 없는 코드가 통신할 수 있는 모든 경로를 반드시 파악하고 있어야 한다.
샌드박스를 완전히 차단하면 네트워크 경로는 막을 수 있지만, 많은 워크로드를 사실상 사용할 수 없게 만든다. 에이전트는 저장소를 클론하거나, 의존성을 설치하거나, AI 모델을 호출하거나, 데이터베이스를 조회하거나, 결과를 업로드해야 할 수 있다.
인터넷을 전면 개방하는 것만이 대안은 아니다. 실용적인 샌드박스는 워크로드에 필요한 연결만 허용해야 한다:
AI 제공업체만 허용하고, 다른 공개 목적지는 차단한다.
클라우드 네트워크 전체가 아닌, 특정 오브젝트 스토리지 버킷 하나만 허용한다.
나머지 사설 주소 공간은 차단하면서 특정 프라이빗 서비스에만 접근한다.
신뢰할 수 있는 설정 단계에서 의존성을 설치한 뒤, 생성된 코드가 실행되기 전에 레지스트리 접근 권한을 제거한다.
API 키를 샌드박스 내부에 두지 않고 API 요청을 인증한다.
실용적인 정책 모델은 완전 개방, 완전 차단, 그리고 일치하지 않는 트래픽을 기본적으로 차단하는 세밀한 정책을 모두 지원해야 한다. 이 정책들은 도메인 규칙과 허용·차단 주소 범위를 결합할 수 있어야 한다.
도메인과 CIDR은 서로 다른 문제를 해결한다. 도메인 정책은 IP 주소가 자주 바뀌거나 관련 없는 여러 호스트명을 제공하는 현대 서비스에 충분히 정밀하게 적용할 수 있다. CIDR 정책은 프로토콜에 관계없이 동작하며, 고정 인프라와 사설 네트워크에 대한 제어를 제공한다.
연결 권한은 임시적이어야 한다. 워크플로우는 패키지 레지스트리 접근으로 시작해서, 신뢰할 수 없는 코드 실행 전에 접근 범위를 좁히고, 출력 목적지를 잠시 허용한 뒤, 아웃바운드 접근을 완전히 차단하는 순서로 진행할 수 있다. 이 모든 것이 워크로드를 재시작하지 않고도 가능하다.
Vercel 샌드박스 방화벽은 마이크로VM 외부인 호스트에서 실행된다. 샌드박스 내부의 코드가 이를 수정하거나 비활성화할 수 없다.
Linux 네트워킹은 아웃바운드 TCP 연결과 DNS 쿼리를 투명하게 방화벽으로 리디렉션한다. 워크로드에서 별도로 프록시를 설정할 필요가 없으며, 방화벽은 각 연결의 원래 목적지 정보를 그대로 유지한다.
도메인이 제한된 연결의 경우, 방화벽은 TLS 핸드셰이크 초반부를 검사해 SNI(Server Name Indication, 서버 이름 표시)를 추출한다. 이를 통해 업스트림 연결을 열기 전에 요청된 호스트명을 파악한다. 이후 해당 호스트명을 샌드박스의 도메인 정책과 대조하고, 목적지 주소도 CIDR 정책과 비교 검사한다.
일반적으로 허용된 TLS 연결은 복호화 없이 그대로 통과한다. 방화벽은 정책 적용에 필요한 암호화되지 않은 핸드셰이크 정보만 읽은 뒤, 워크로드를 목적지에 직접 연결한다.
일부 정책에서는 HTTP 요청 자체를 검사하거나 수정해야 한다. 설정된 도메인에 한해서만, 헤더 인젝션과 요청 포워딩은 샌드박스 고유의 인증 기관을 사용해 선택적으로 TLS를 종료한다. 방화벽은 자격 증명을 주입하거나 요청을 신뢰할 수 있는 엔드포인트로 포워딩하기 전에, 호스트명, 경로, 메서드, 쿼리, 헤더를 기준으로 요청을 매칭한다.
DNS 트래픽도 동일한 도메인 정책으로 필터링된다. 이 레이어들을 함께 사용하면 샌드박스가 연결할 수 있는 대상과 특정 연결에 부여되는 권한을 모두 제어할 수 있다.
에이전트는 종종 인증이 필요한 서비스를 호출해야 한다. 하지만 환경 변수나 파일에 저장된 자격 증명은 누구에게나 전달 가능한 베어러(bearer) 자격 증명이다. 샌드박스 내부의 모든 프로그램이 이를 읽을 수 있으며, 악성 코드는 이를 서드파티 서비스에 복사해 둘 수 있다. 그렇게 되면 샌드박스가 종료된 후에도 해당 자격 증명이 악용될 수 있다.
Vercel 샌드박스는 대신 호스트 네트워크 경계에서 자격 증명을 주입한다. 방화벽은 샌드박스 시작 시 전용 인증 기관(CA)을 즉시 생성하고 샌드박스의 신뢰할 수 있는 인증서 목록에 추가한다. 설정된 목적지에 대해서는 선택적으로 TLS를 종료하고, 인증 헤더를 추가하거나 교체한 뒤, 업스트림 서비스에 새 TLS 연결을 맺는다.
자격 증명은 마이크로VM에 들어가지 않는다. 암호화되지 않은 채 호스트를 벗어나는 일도 없다. 인증 기관은 해당 샌드박스에만 사용되며, 샌드박스가 종료되면 함께 폐기된다.
주입 방식은 자격 증명을 사용할 수 있는 범위도 제한한다. 방화벽은 설정된 목적지에만 자격 증명을 전송하므로, 샌드박스의 파일이나 환경을 다른 서비스에 업로드하더라도 해당 권한은 넘어가지 않는다. 매처(matcher)를 통해 경로, 메서드, 쿼리, 요청 헤더를 기준으로 범위를 더 좁힐 수도 있다. 예를 들어 생성된 코드는 동일한 API에서 다른 리소스를 읽는 권한 없이, 특정 엔드포인트에 결과를 제출하는 권한만 받을 수 있다.
주입된 자격 증명도 최소 권한 원칙을 따라야 한다. 워크로드에 필요한 특정 작업으로만 접근을 제한해야 한다.
정적 허용 목록으로는 모든 보안 요구 사항을 충족할 수 없다. 일부 워크로드는 페이로드를 검사하거나, 비즈니스 규칙을 적용하거나, 감사 추적을 기록하거나, 운영자만 아는 컨텍스트를 바탕으로 인가(authorization) 결정을 내려야 한다.
요청 포워딩은 선택된 HTTPS 요청을 운영자가 직접 제어하는 프록시를 통해 전달한다. 프록시는 원본 요청과 함께 요청을 시작한 팀, 프로젝트, 샌드박스를 식별하는 Vercel 발급 OIDC 토큰을 받는다.
이 프록시는 프로그래밍 가능한 정책 레이어가 된다. 다음과 같은 작업이 가능하다:
요청이 환경을 벗어나기 전에 민감한 필드를 마스킹한다.
사용자 또는 샌드박스 단위로 인가를 적용한다.
패키지 다운로드를 공급망 스캐닝을 거쳐 라우팅하고, 조직 정책에 맞지 않는 아티팩트를 차단한다.
컴플라이언스 워크플로우를 위해 요청과 응답을 기록한다.
샌드박스 아이덴티티를 범위가 좁게 제한된 자격 증명으로 교환한다.
조직 정책에 맞지 않는 작업을 거부한다.
정책과 그 안의 시크릿은 제어 대상 코드가 마이크로VM 내부에서 완전한 루트 접근 권한을 가지고 있을 때도 샌드박스 외부에 유지된다. 요청 프록시에 대한 자세한 내용은 샌드박스 문서를 참고하라.
샌드박스가 신뢰할 수 없는 코드를 안전하게 처리하기 위해 결제 수단을 요구해서는 안 된다고 우리는 믿는다.
모든 Vercel 샌드박스에는 컴퓨팅 격리와 함께, 내부 코드가 통신할 수 있는 대상을 정의하는 완전한 방화벽이 기본 포함되어 있다.
목표는 모든 샌드박스를 완전히 오프라인으로 만드는 것이 아니다. 권한을 명시적으로 정의하는 것이다:
이 샌드박스가 접근할 수 있는 목적지는 어디인가?
어떤 사설 주소 범위에는 접근할 수 없는가?
어떤 요청에 자격 증명을 사용할 수 있는가?
어떤 작업이 추가 정책을 거쳐야 하는가?
모든 통신은 언제 중단되어야 하는가?
이것들은 실행 환경의 근본적인 속성이지, 워크로드가 프로덕션에 배포된 후에 추가하는 보안 장치가 아니다. 우리는 이 믿음이 너무나 확고하기 때문에 전체 아웃바운드 방화벽 기능을 모든 샌드박스에서 사용할 수 있도록 결정했다.
다음 정책은 특정 API로의 아웃바운드 연결을 허용하고, 단 하나의 작업에만 자격 증명을 주입한다. 다른 목적지는 기본적으로 차단되며, 자격 증명은 샌드박스 외부에 유지된다.
샌드박스가 실행 중인 동안에도 동일한 정책을 교체할 수 있다:
샌드박스는 코드가 어디서 실행되는지만으로 정의되지 않는다. 그 코드가 무엇에 접근할 수 있는지, 어떤 권한을 받는지, 그리고 코드 자체가 악의적일 때도 어떤 경계가 유지되는지에 의해 정의된다.
네트워크는 샌드박스의 일부다.