구독해서 새 게시물에 대한 알림을 받으세요.

동적이고 신원 인식이 가능하며 안전한 샌드박스 인증

2026-04-13

7분 읽기
이 게시물은 English日本語로도 이용할 수 있습니다.

본 콘텐츠는 사용자의 편의를 고려해 자동 기계 번역 서비스를 사용하였습니다. 영어 원문과 다른 오류, 누락 또는 해석상의 미묘한 차이가 포함될 수 있습니다. 필요하시다면 영어 원문을 참조하시기를 바랍니다.

AI 대규모 언어 모델 과 OpenCode 및 Claude Code와 같은 도구의 기능이 점점 더 향상됨에 따라, 채팅 메시지, 칸반 업데이트, 바이브 코딩 UI, 터미널 세션, GitHub 댓글 등에 대한 응답으로 샌드박스 에이전트를 시작하는 사용자가 증가하고 있습니다.

샌드박스는 다음과 같은 몇 가지 사항을 제공하기 때문에 단순한 컨테이너를 넘어선 중요한 단계입니다.

  • 보안: 신뢰할 수 없는 최종 사용자(또는 악성 LLM)는 모두 샌드박스에서 실행될 수 있으며, 함께 실행되는 호스트 시스템 또는 다른 샌드박스를 손상시킬 수 없습니다. 이는 전통적으로 (항상 그런 것은 아니지만) 마이크로 VM으로 수행됩니다.

  • 속도: 최종 사용자는 신속하게 새로운 샌드박스를 시작하고 이전에 사용한 샌드박스 상태를 빠르게 복구할 수 있어야 합니다.

  • 제어: 신뢰할 수 있는 플랫폼은 샌드박스의 신뢰할 수 없는 도메인 내에서 작업을 수행할 수 있어야 합니다. 이는 샌드박스에 파일을 탑재하거나, 어떤 요청이 파일에 액세스할지 제어하거나, 특정 명령을 실행하는 것을 의미할 수 있습니다.

오늘, Cloudflare는 샌드박스 와 모든 컨테이너에 제어의 또 다른 핵심 구성 요소를 추가하게 되어 기쁩니다. 바로 아웃바운드 Workers입니다. 이는 샌드박스를 실행하는 사용자가 다양한 서비스에 쉽게 연결하고 관찰 가능성을 추가하며, 중요한 에이전트의 경우에 유연하고 안전한 인증을 추가할 수 있도록 하는 프로그래밍 방식 송신 프록시입니다.

작동 방식

다음은 outbound Worker를 사용하여 헤더에 비밀 키를 추가하는 방법을 간략하게 살펴보겠습니다.

class OpenCodeInABox extends Sandbox {
  static outboundByHost = {
    "github.com": (request, env, ctx) => {
      const headersWithAuth = new Headers(request.headers);
      headersWithAuth.set("x-auth-token", env.SECRET);
      return fetch(request, { headers: headersWithAuth });
    }
  }
}

샌드박스에서 실행 중인 코드가 "github.com"에 요청할 때마다 요청은 핸들러를 통해 프록시됩니다. 이렇게 하면 각 요청에 대해 로깅, 수정, 취소 등 원하는 모든 작업을 수행할 수 있습니다. 이 경우 비밀을 안전하게 주입하고 있습니다(자세한 내용은 나중에 설명합니다). 이 프록시는 샌드박스와 동일한 시스템에서 실행되고 분산 상태에 액세스할 수 있으며 간단한 JavaScript로 쉽게 수정할 수 있습니다.

BLOG-3199 2

이로 인해 샌드박스에 추가되는 모든 가능성, 특히 에이전트 인증의 가능성에 대해 기대가 큽니다. 세부 사항으로 들어가기 전에 먼저 기존 형태의 인증을 살펴보고 Cloudflare에서 더 나은 방식이 있다고 생각하는 이유를 간단히 살펴보겠습니다.

에이전트형 워크로드에 대한 공통 인증

에이전트형 인증의 핵심 문제는 워크로드를 완전히 신뢰할 수 없다는 것입니다. LLM이 악의적이지 않은 것은 아니지만(적어도 아직까지는 아님), LLM이 데이터를 부적절하게 사용하거나 해서는 안 되는 조치를 취하지 않도록 보호를 적용할 수 있는 기능은 여전히 필요합니다.

에이전트에 인증을 제공하는 일반적인 방법이 몇 가지 있으며, 각 방법에는 다음과 같은 단점이 있습니다.

Standard API 토큰 은 가장 기본적인 인증 방법으로, 일반적으로 환경 변수를 통해 애플리케이션에 삽입되거나 탑재된 비밀 파일에 삽입됩니다. 이 방법이 가장 간단한 방법이지만, 보안 수준은 가장 낮습니다. 샌드박스가 요청하는 동안 어떤 방식으로든 손상되거나 토큰이 실수로 유출되지는 않을 것임을 신뢰해야 합니다. 에이전트를 완전히 신뢰할 수 없으므로 토큰 만료 및 순환을 설정해야 하는데, 이는 번거로울 수 있습니다.

워크로드 ID 토큰(OIDC 토큰 등)을 사용하면 이러한 문제를 일부 해결할 수 있습니다. 에이전트에 일반 권한을 가진 토큰을 부여하는 대신 ID를 증명하는 토큰을 부여할 수 있습니다. 이제 에이전트는 토큰으로 일부 서비스에 직접 액세스하는 대신 ID 토큰을 매우 수명이 짧은 액세스 토큰으로 교환할 수 있습니다. OIDC 토큰은 특정 에이전트의 워크플로가 완료된 후 무효화될 수 있으며, 만료 관리가 더 쉽습니다. 워크로드 ID 토큰의 가장 큰 단점 중 하나는 통합의 유연성이 없다는 것입니다. 많은 서비스에서 OIDC를 최고 수준으로 지원하지 않으므로 업스트림 서비스와 제대로 작동하도록 통합하려면 플랫폼에서 자체 토큰 교환 서비스를 제공해야 합니다. 따라서 채택이 어려워집니다.

사용자 지정 프록시 는 최대한의 유연성을 제공하며 워크로드 ID 토큰과 페어링할 수 있습니다. 샌드박스 송신의 일부나 전부를 신뢰할 수 있는 코드를 통해 전달할 수 있다면 필요한 규칙을 삽입할 수 있습니다. 에이전트가 통신하는 업스트림 서비스에 나쁜 RBAC 사례가 있어 세분화된 권한을 제공하지 못할 수 있습니다. 문제 없습니다. 제어와 권한을 직접 작성하세요! 이는 에이전트를 세밀하게 제어하여 차단할 수 있는 훌륭한 옵션입니다. 하지만 샌드박스의 모든 트래픽을 어떻게 가로챌 수 있을까요? 동적이고 쉽게 프로그래밍할 수 있는 프록시를 설정하려면 어떻게 해야 할까요? 트래픽 프록시를 어떻게 효율적으로 수행하시나요? 이는 쉽지 않은 문제입니다.

이러한 불완전한 방법을 고려할 때 이상적인 인증 메커니즘은 어떤 모습일까요?

이상적으로는 다음과 같습니다.

  • Zero Trust. 어떤 기간 동안도 신뢰할 수 없는 사용자에게 토큰이 제공되지 않습니다.

  • 단순합니다. 저작하기 쉽습니다. 토큰 발행, 교체, 해독과 같은 복잡한 시스템을 사용하지 않습니다.

  • 유연함. Cloudflare는 업스트림 시스템에 의존하여 필요한 세분화된 액세스를 제공하지 않습니다. 우리는 우리가 원하는 어떤 규칙이든 적용할 수 있습니다.

  • ID 인식. 호출을 수행하는 샌드박스를 식별하고 이에 대한 특정 규칙을 적용할 수 있습니다.

  • Observable. 우리는 어떤 전화가 걸려왔는지에 대한 정보를 쉽게 수집할 수 있습니다.

  • 성능. 우리는 중앙 집중식 또는 느린 진실의 소스까지 왕복하지 않습니다.

  • 투명한. 샌드박스를 적용한 워크로드는 이에 대해 알 필요가 없습니다. 모든 것이 잘 작동합니다.

  • 동적. 즉석에서 규칙을 변경할 수 있습니다.

저희는 Outbound Workers for Sandbox가 이 모든 면에서 적합하다고 믿습니다. 그 방법을 살펴보겠습니다.

아웃바운드 근무자의 실제 사례

기본 사항: 제한과 관찰 가능성

먼저 요청을 기록하고 특정 작업을 거부하는 아주 기본적인 예를 살펴보겠습니다.

이 경우 샌드박스에서 나가는 모든 HTTP 요청을 가로채는 아웃바운드 기능을 사용합니다. 자바스크립트 몇 줄만 있으면 GET만 수행되었는지 확인한 후 허용되지 않는 메서드를 기록하여 거부할 수 있습니다.

class MySandboxedApp extends Sandbox {
  static outbound = (req, env, ctx) => {
    // Deny any non-GET action and log
    if (req.method !== 'GET') {
      console.log(`Container making ${req.method} request to: ${req.url}`);
      return new Response('Not Allowed', { status: 405, statusText: 'Method Not Allowed'});
    }

    // Proceed if it is a GET request
    return fetch(req);
  };
}

이 프록시는 Workers에서 실행되며 샌드박스를 적용한 VM과 동일한 컴퓨터에서 실행됩니다. Workers는 빠른 응답 시간을 위해 구축되었으며, 종종 캐시된 CDN 트래픽 앞에 위치하므로 추가 대기 시간이 극히 최소화됩니다.

이는 Workers에서 실행되므로 즉시 사용할 수 있는 관찰 가능성을 얻습니다. 로그 및 아웃바운드 요청을 Workers 대시보드에서 보거나 원하는 애플리케이션 성능 모니터링 도구로 내보낼 수 있습니다.

Zero Trust 자격 증명 주입

이를 사용하여 에이전트에 Zero Trust 환경 을 적용하려면 어떻게 해야 할까요? 비공개 GitHub 인스턴스에 요청을 하지만, LLM이 비공개 토큰에 액세스하는 것은 절대 원하지 않는다고 가정해 보겠습니다.

outboundByHost 를 사용하여 특정 도메인이나 IP에 대한 함수를 정의할 수 있습니다. 이 경우 도메인이 “my-internal-vcs.dev”이면 보호된 자격 증명이 삽입됩니다. 샌드박스를 적용한 에이전트는 이러한 자격 증명에 절대 액세스할 수 없습니다.

class OpenCodeInABox extends Sandbox {
  static outboundByHost = {
    "my-internal-vcs.dev": (request, env, ctx) => {
      const headersWithAuth = new Headers(request.headers);
      headersWithAuth.set("x-auth-token", env.SECRET);
      return fetch(request, { headers: headersWithAuth });
    }
  }
}

컨테이너의 ID에 따라 응답 조건도 쉽게 설정할 수 있습니다. 모든 샌드박스 인스턴스에 동일한 토큰을 삽입할 필요는 없습니다.

 static outboundByHost = {
  "my-internal-vcs.dev": (request, env, ctx) => {
    // note: KV is encrypted at rest and in transit
    const authKey = await env.KEYS.get(ctx.containerId);

    const requestWithAuth = new Request(request);
    requestWithAuth.headers.set("x-auth-token", authKey);
    return fetch(requestWithAuth);
  }
}

Cloudflare 개발자 플랫폼 사용

마지막 예에서 알아차렸을 수도 있지만, 아웃바운드 Workers를 사용할 때의 또 다른 주요 이점은 Workers 생태계로 더 쉽게 통합할 수 있다는 것입니다. 이전에는 사용자가 R2에 액세스하려면 R2 자격 증명을 삽입한 다음 컨테이너에서 공개 R2 API를 호출해야 했습니다. KV, 에이전트, 기타 컨테이너, 기타 Worker 서비스, 도 동일합니다.

이제 아웃바운드 Workers에서 모든 바인딩 을 호출하기만 하면 됩니다.

class MySandboxedApp extends Sandbox {
  static outboundByHost = {
    "my.kv": async (req, env, ctx) => {
      const key = keyFromReq(req);
      const myResult = await env.KV.get(key);
      return new Response(myResult);
    },
    "objects.cf": async (req, env, ctx) => {
      const prefix = ctx.containerId
      const path = pathFromRequest(req);
      const object = await env.R2.get(`${prefix}/${path}`);
      const myResult = await env.KV.get(key);
      return new Response(myResult);
    },
  };
}

토큰을 구문 분석하고 정책을 설정하는 대신 코드와 원하는 로직을 사용하여 액세스 조건을 쉽게 설정할 수 있습니다. 또한 R2 예제에서는 샌드박스의 ID를 사용하여 쉽게 액세스 범위를 넓힐 수 있었습니다.

제어를 동적으로 만들기

네트워킹 제어도 동적이어야 합니다. 많은 플랫폼에서 컨테이너 및 VM 네트워킹 구성은 다음과 같이 정적입니다.

{
  defaultEgress: "block",
  allowedDomains: ["github.com", "npmjs.org"]
}

없는 것보다는 낫지만, 더 잘할 수 있습니다. 많은 샌드박스의 경우 시작 시 정책을 적용하면서 특정 작업이 수행된 후에는 다른 정책으로 재정의하고 싶을 수 있습니다.

예를 들어, 샌드박스를 부팅하고, NPM과 Github를 통해 종속성을 가져온 다음, 그 후에 송신을 잠글 수 있습니다. 이렇게 하면 가능한 한 짧은 시간 동안 네트워크를 개방할 수 있습니다.

이를 위해 outboundHandlers를 사용할 수 있습니다. 이는 setOutboundHandler 메서드를 사용하여 프로그래밍 방식으로 적용할 수 있는 임의의 아웃바운드 핸들러를 정의할 수 있도록 해줍니다. 각각 params를 사용하므로 코드에서 동작을 사용자 지정할 수도 있습니다. 이 경우 Cloudflare는 사용자 지정 “allowHosts” 정책을 통해 일부 호스트 이름을 허용한 다음 HTTP를 끌 것입니다.

class MySandboxedApp extends Sandbox {
  static outboundHandlers = {
    async allowHosts(req, env, { params }) {
     const url = new URL(request.url);
     const allowedHostname = params.allowedHostnames.includes(url.hostname);

      if (allowedHostname) {
        return await fetch(newRequest);
      } else {
        return new Response(null, { status: 403, statusText: "Forbidden" });
      }
    }
    
    async noHttp(req) {
      return new Response(null, { status: 403, statusText: "Forbidden" });
    }
  }
}

async setUpSandboxes(req, env) {
  const sandbox = await env.SANDBOX.getByName(userId);
  await sandbox.setOutboundHandler("allowHosts", {
    allowedHostnames: ["github.com", "npmjs.org"]
  });
  await sandbox.gitClone(userRepoURL)
  await sandbox.exec("npm install")
  await sandbox.setOutboundHandler("noHttp");
}

더 확장할 수도 있습니다. 에이전트가 최종 사용자에게 "Cloudflare.com에 대한 POST 요청을 허용하시겠습니까?"와 같은 질문을 할 수 있습니다. 작업을 수행할 수 있습니다. 동적 아웃바운드 Workers를 사용하면 샌드박스 규칙을 즉석에서 쉽게 수정하여 이러한 수준의 제어를 제공할 수 있습니다.

MITM 프록시를 통한 TLS 지원

요청을 허용하거나 거부하는 것 외에 요청에 유용한 다른 일을 하려면, 콘텐츠에 액세스할 수 있어야 합니다. 즉, HTTPS 요청을 할 경우 Workers 프록시가 해독해야 합니다.

이를 위해 각 샌드박스 인스턴스마다 고유한 임시 인증 기관(CA)과 개인 키가 생성되고, 해당 CA가 샌드박스에 배치됩니다. 기본적으로 샌드박스 인스턴스는 이 CA를 신뢰하지만, 표준 컨테이너 인스턴스는 sudo update-ca-certificates를 호출하여 이 CA를 신뢰하도록 선택할 수 있습니다.

export class MyContainer extends Container {
  interceptHttps = true;
}

MyContainer.outbound = (req, env, ctx) => {
  // All HTTP(S) requests will trigger this hook.
  return fetch(req);
};

TLS 트래픽은 Cloudflare의 격리 네트워크 프로세스에서 TLS 핸드셰이크를 수행하여 프록시됩니다. 임시적이고 고유한 개인 키에서 리프 CA를 생성하고 ClientHello에서 추출된 SNI를 사용합니다. 그런 다음 동일한 컴퓨터에서 HTTPS 요청을 처리하도록 구성된 Worker를 호출합니다.

Cloudflare의 임시 개인 키와 CA는 절대로 컨테이너 런타임 사이드카 프로세스를 벗어나지 않으며, 다른 컨테이너 사이드카 프로세스와 공유하지 않습니다.

이를 통해 아웃바운드 Workers는 진정으로 투명한 프록시 역할을 합니다. 샌드박스는 특정 프로토콜이나 도메인을 인식할 필요가 없습니다. 모든 HTTP 및 HTTPS 트래픽은 필터링 또는 수정을 위해 아웃바운드 처리기를 거칩니다.

내부 구조

ContainerSandbox 모두에서 위에 표시된 기능을 활성화하기 위해 ctx.container 개체에 interceptOutboundHttp 및 interceptOutboundHttps라는 새로운 메서드를 추가했습니다. 이 메서드는 특정 호스트 이름(기본 글로브 패턴 일치 포함) 및 IP 범위에서 나가는 요청을 가로채며, 모든 아웃바운드 요청을 가로채는 데 사용될 수 있습니다. 이러한 메서드는 WorkerEntrypoint와 함께 호출되며, 이는 아웃바운드 Worker의 현관문으로 설정됩니다.

export class MyWorker extends WorkerEntrypoint {
 fetch() {
   return new Response(this.ctx.props.message);
 }
}

// ... inside your container DurableObject ...
this.ctx.container.start({ enableInternet: false });
const outboundWorker = this.ctx.exports.MyWorker({ props: { message: 'hello' } });
await this.ctx.container.interceptOutboundHttp('15.0.0.1:80', outboundWorker);

// From now on, all HTTP requests to 15.0.0.1:80 return "hello"
await this.waitForContainerToBeHealthy();

// You can decide to return another message now...
const secondOutboundWorker = this.ctx.exports.MyWorker({ props: { message: 'switcheroo' } });
await this.ctx.container.interceptOutboundHttp('15.0.0.1:80', secondOutboundWorker);
// all HTTP requests to 15.0.0.1 now show "switcheroo", even on connections that were
// open before this interceptOutboundHttp

// You can even set hostnames, CIDRs, for both IPv4 and IPv6
await this.ctx.container.interceptOutboundHttp('example.com', secondOutboundWorker);
await this.ctx.container.interceptOutboundHttp('*.example.com', secondOutboundWorker);
await this.ctx.container.interceptOutboundHttp('123.123.123.123/23', secoundOutboundWorker);

Workers에 대한 모든 프록시 설정은 샌드박스 VM을 실행하는 동일한 컴퓨터에서 로컬로 발생합니다. 컨테이너와 Worker 간의 통신은 “비인증”이지만, 안전합니다.

이러한 메서드는 연결이 열려 있는 동안에도 컨테이너 시작 전이나 후에 언제든지 호출할 수 있습니다. 여러 HTTP 요청을 전송하는 연결은 자동으로 새로운 진입점을 선택하므로 아웃바운드 Workers를 업데이트해도 기존 TCP 연결이 끊기거나 HTTP 요청이 중단되지 않습니다.

BLOG-3199 3

wrangler dev 를 사용한 로컬 개발 또한 송신 가로채기를 지원합니다. 이를 위해 저희는 로컬 컨테이너의 네트워크 네임스페이스 내에 사이드카 프로세스를 자동으로 생성합니다. 우리는 이 사이드카 구성 요소를 프록시. proxy-everything 이 연결되면 적절한 TPROXY nftable 규칙을 적용하여 로컬 Container에서 일치하는 트래픽을 Cloudflare의 오픈 소스 JavaScript 런타임인 workerd로 라우팅하여 아웃바운드 Worker를 실행합니다. 이를 통해 로컬 개발 경험이 프로덕션 환경에서 일어나는 일을 반영하여 테스트 및 개발이 단순하게 유지될 수 있습니다.

Outbound Workers 체험하기

Cloudflare Sandboxes를 아직 사용해 보지 않았다면 시작하기 가이드를 확인하세요. Containers 또는 Sandboxes의 현재 사용자라면, 지금 문서를 읽고 @cloudflare/[email protected] 또는 @cloudflare/[email protected]로 업그레이드하여 Outbound Workers 사용을 시작하세요.

Cloudflare TV에서 보기

Cloudflare에서는 전체 기업 네트워크를 보호하고, 고객이 인터넷 규모의 애플리케이션을 효과적으로 구축하도록 지원하며, 웹 사이트와 인터넷 애플리케이션을 가속화하고, DDoS 공격을 막으며, 해커를 막고, Zero Trust로 향하는 고객의 여정을 지원합니다.

어떤 장치로든 1.1.1.1에 방문해 인터넷을 더 빠르고 안전하게 만들어 주는 Cloudflare의 무료 애플리케이션을 사용해 보세요.

더 나은 인터넷을 만들기 위한 Cloudflare의 사명을 자세히 알아보려면 여기에서 시작하세요. 새로운 커리어 경로를 찾고 있다면 채용 공고를 확인해 보세요.
Agents Week컨테이너샌드박스에이전트Cloudflare Workers

X에서 팔로우하기

Cloudflare|@cloudflare

관련 게시물

2026년 4월 30일

이제 에이전트는 Cloudflare 계정을 생성하고, 도메인을 구매하고, 배포할 수 있습니다.

오늘부터 이제 에이전트도 Cloudflare 고객이 될 수 있습니다. 즉시 Cloudflare 계정을 만들고, 유료 구독을 시작하고, 도메인을 등록하고, API 토큰을 다시 받아 코드를 배포할 수 있습니다. 권한을 부여하기 위해 인간이 개입할 수는 있지만, 굳이 대시보드로 이동하거나, API 토큰을 복사하여 붙여넣거나, 신용카드 세부 정보를 입력할 필요가 없습니다. ...

2026년 4월 22일

Rust Workers를 안정적으로 만들기: wasm-bindgen에서의 패닉 및 중단 복구

Rust Workers에서의 패닉은 역사적으로 치명적이었으며 전체 인스턴스를 중독시켰습니다. Rust Workers는 이제 Wasm-bindgen 프로젝트에서 업스트림과 협업하여 WebAssembly 예외 처리를 사용한 패닉 상태를 해결하는 등 탄력적인 중요 오류 복구를 지원합니다....

2026년 4월 20일

당사가 제공하는 플랫폼을 기반으로 직접 구축한 사내 AI 엔지니어링 스택

Cloudflare는 배송하는 제품과 동일한 제품에 내부 AI 엔지니어링 스택을 구축했습니다. 즉, AI Gateway를 통해 라우팅된 2천만 건의 요청, 2,410억 개의 토큰이 처리되었으며, Workers AI에서 실행되는 추론은 3,683명 이상의 내부 사용자에게 제공됨을 의미합니다. 그 비결은 다음과 같습니다. ...