> ## Documentation Index
> Fetch the complete documentation index at: https://docs.coreweave.com/llms.txt
> Use this file to discover all available pages before exploring further.

# 샌드박스 정책 설정하기

> 클러스터의 샌드박스가 요청할 수 있는 범위를 제한하는 제약 조건과 샌드박스가 상속하는 기본값을 설정합니다.

이 페이지에서는 클러스터의 샌드박스에 적용할 정책을 작성하는 방법을 설명합니다. 컴퓨트, 이미지, 네트워크 액세스, 보안 태세의 허용 범위를 제한하고 모든 샌드박스가 상속하는 기본값을 설정합니다. 러너를 관리하는 관리자를 위한 문서입니다.

정책은 러너에 포함되므로 러너를 업데이트하여 작성합니다. 별도의 정책 리소스나 정책 엔드포인트는 없습니다. 정책에 따라 샌드박스 설정이 결정되는 방식은 [정책 개요](/ko/products/sandboxes/profiles/profiles)를 참조하세요.

<h2 id="before-you-begin">
  시작하기 전에
</h2>

조직에서 **Sandbox Admin** 역할을 가지고 있어야 합니다. 이 역할 없이 정책을 조회하거나 작성하면 `PermissionDenied`가 반환됩니다.

CLI 예시를 사용하려면 [CoreWeave Intelligent CLI](https://github.com/coreweave/cwic)를 설치하고 인증하세요. REST 예시를 사용하려면 CoreWeave API 토큰이 필요합니다. 예시에서는 해당 토큰에 `$TOKEN`을, 러너에 `prod-us-east-1`을 사용합니다.

모든 러너는 정확히 하나의 정책을 가지고 있으며, 정책은 필수입니다. base와 제약 조건이 없는 정책은 유효하며 전체 허용 보안 태세를 선언하므로, operator는 항상 보안 태세를 명시적으로 지정해야 하며 우연히 상속받지 않습니다.

<h2 id="read-the-current-policy">
  현재 정책 조회
</h2>

러너가 현재 가지고 있는 것부터 시작하세요. 빈 문서에서 시작하는 대신입니다.

<Tabs>
  <Tab title="CLI">
    ```bash theme={"system"}
    cwic sandbox runner policy get prod-us-east-1
    ```

    상세 뷰를 확인하려면 `describe`를 추가하세요. 이 옵션은 러너에 정책이 없을 때 설정되지 않은 상태를 명시적으로 표시합니다.

    ```bash theme={"system"}
    cwic sandbox runner policy describe prod-us-east-1
    ```

    `-o json`을 사용하면 한 번도 설정되지 않은 러너는 `{}` 대신 `null`을 반환하므로, 자동화에서 "never configured"와 "configured and permissive"를 구분할 수 있습니다.
  </Tab>

  <Tab title="curl">
    ```bash title="러너와 해당 정책 조회" theme={"system"}
    curl https://api.coreweave.com/v1/sandbox/managedRunners/prod-us-east-1 \
      -H "Authorization: Bearer $TOKEN"
    ```
  </Tab>
</Tabs>

<h2 id="update-a-policy">
  정책 업데이트
</h2>

정책은 러너의 필드이므로, `policy` 업데이트 마스크를 사용하여 러너를 업데이트함으로써 설정합니다.

**정책 업데이트는 항상 전체 문서를 대체합니다.** `policy`만 업데이트 마스크 경로로 구현되어 있으므로, 하나의 제약 조건 그룹을 패치하고 나머지는 그대로 둘 수 없습니다. 현재 정책을 조회하고, 필요한 부분을 변경한 후 전체 문서를 다시 전송하세요.

<Tabs>
  <Tab title="CLI">
    러너의 현재 문서로 시드된 `$EDITOR`에서 정책을 편집합니다:

    ```bash theme={"system"}
    cwic sandbox runner policy edit prod-us-east-1
    ```

    파일에서 또는 `-`로 stdin에서 문서를 적용합니다:

    ```bash theme={"system"}
    cwic sandbox runner policy edit prod-us-east-1 -f policy.yaml
    ```

    `-f`를 사용하면 `cwic`는 제출 시점에 러너의 현재 리비전을 조회합니다. 따라서 이전에 조회한 내용을 기준으로 편집한 파일이 다른 관리자의 변경 사항을 덮어쓸 수 있습니다. 파일의 기준이 된 리비전을 고정하려면 러너를 한 번만 조회하여 정책과 해당 `etag`를 함께 캡처하세요:

    ```bash theme={"system"}
    cwic sandbox runner get prod-us-east-1 -o json > runner.json
    jq '.[0].policy' runner.json > policy.json
    ```

    `policy.json`을 편집한 후, 같은 조회에서 얻은 `etag`와 함께 제출합니다:

    ```bash theme={"system"}
    cwic sandbox runner policy edit prod-us-east-1 -f policy.json \
      --etag "$(jq -r '.[0].etag' runner.json)"
    ```

    `etag`는 반드시 문서를 가져온 바로 그 조회에서 얻어야 하며, 그 이후의 조회에서 가져와서는 안 됩니다. `policy get`은 `etag` 없이 정책을 내보내며, 내보낸 후에 `policy describe`를 실행하면 더 새로운 토큰이 반환될 수 있습니다. 이 토큰은 검사를 통과하기 때문에, 그 사이에 이루어진 변경 사항을 파일이 덮어쓰게 됩니다. curl 탭과 [정책 교체](/ko/products/sandboxes/operations/managed-runners#example-replace-the-policy)에서도 같은 방식으로 하나의 응답에서 두 값을 모두 캡처합니다.

    편집기 모드에서는 편집기를 시드할 때 조회한 `etag`를 그대로 전송하므로 플래그가 필요 없습니다.

    현재 문서가 아닌 스캐폴드에서 시작하려면 템플릿을 출력합니다:

    ```bash theme={"system"}
    cwic sandbox runner policy edit prod-us-east-1 --print-template
    ```

    전송하기 전에 문서를 확인합니다:

    ```bash theme={"system"}
    cwic sandbox runner policy validate -f policy.yaml
    ```
  </Tab>

  <Tab title="curl">
    `[ETAG]`를 이 편집의 기준이 된 조회에서 얻은 `etag` 값으로 교체합니다. 오래된 값은 `FAILED_PRECONDITION` 오류와 함께 실패하며 아무것도 변경하지 않습니다. [정책 교체](/ko/products/sandboxes/operations/managed-runners#example-replace-the-policy)를 참조하세요.

    ```bash title="러너에 정책 설정" theme={"system"}
    curl -X PATCH "https://api.coreweave.com/v1/sandbox/managedRunners/prod-us-east-1?updateMask=policy" \
      -H "Authorization: Bearer $TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
        "policy": {
          "displayName": "Shared agent pool",
          "constraints": {
            "resources": { "maxCpu": "8", "maxMemory": "32Gi", "requireLimits": true },
            "lifecycle": { "defaultLifetimeSeconds": 3600 }
          }
        },
        "etag": "[ETAG]"
      }'
    ```
  </Tab>
</Tabs>

모든 정책 쓰기에는 세 가지 규칙이 적용됩니다:

* **수명은 정책이 아닌 플랫폼에 의해 제한됩니다.** 정책은 생성 요청에서 수명을 생략할 때 사용되는 `constraints.lifecycle.defaultLifetimeSeconds`만 제공합니다. 플랫폼은 생성 시점에 최대값(현재 30일)을 초과하는 수명을 거부합니다. 이전 정책 버전에는 `maxLifetimeSeconds` 한도가 포함되어 있었으나, 현재 `cwic`는 이를 포함한 문서를 거부합니다.
* **설정된 정책은 지울 수 없습니다.** 삭제 오퍼레이션이 없으며, API는 정책을 null로 설정하는 업데이트를 거부합니다. 보안 태세를 완화하려면 더 관대한 문서로 교체하세요.
* **정책 문서는 인코딩 후 256 KiB로 제한됩니다.**

<Warning>
  정책 쓰기는 읽기-수정-쓰기 방식으로 이루어지며, 편집의 기준이 된 러너 조회에서 얻은 `etag`를 기준으로 검사됩니다. 해당 조회 이후 다른 관리자가 정책을 업데이트했다면, API는 `FAILED_PRECONDITION` 오류와 함께 쓰기를 거부하며 아무것도 변경하지 않습니다. 이 경우 러너를 다시 조회하고, 반환된 문서에 변경 사항을 다시 적용한 후 새 `etag`와 함께 다시 제출하세요. 새 `etag`만 가져와서 기존 문서를 그대로 다시 전송하면 검사는 통과하지만, 쓰기는 여전히 전체 문서를 대체하므로 다른 관리자가 편집한 내용이 사라집니다.
</Warning>

수명 예시와 Serverless 및 CKS 간의 차이는 [장기 실행 샌드박스 실행](/ko/products/sandboxes/long-running-sandboxes)을 참조하세요.

정책 변경은 업데이트 이후에 생성된 샌드박스에 적용됩니다. 실행 중인 샌드박스는 시작 시점에 확인된 정책을 유지하며, 게이트웨이의 캐시된 복사본은 잠시 지연될 수 있으므로, 쓰기 직후에 이루어진 배치는 이전 정책을 기준으로 확인될 수 있습니다.

<Note>
  정책 명령어는 v1 API를 사용해 조회 및 쓰기를 수행하지만, 다른 `cwic sandbox runner` 및 `cwic sandbox profile` 명령어는 여전히 v1beta2를 사용합니다. 두 API 모두 동일한 `--api-url`을 통해 접근합니다.
</Note>

<h2 id="set-a-default-policy-for-new-runners">
  새 러너에 대한 기본 정책 설정
</h2>

CoreWeave는 호스팅 서비스에서 새 러너에 대한 기본 정책을 설정합니다. 다른 배포에서는 자체 기본 정책을 정의할 수 있습니다. 게이트웨이는 러너가 연결될 때 또는 v1 배치가 정책이 없는 러너를 처음 선택할 때 해당 정책을 기록합니다. 이미 정책이 있는 러너는 기존 정책을 그대로 유지합니다.

기본 정책은 게이트웨이 인프라 설정의 `gateway.infraConfig.default_runner_policy`에 있으며, 이를 변경하려면 게이트웨이를 재시작해야 합니다. 내장된 기본값은 없습니다. 설정이 없거나 null이면 아무것도 기록되지 않으며, 샌드박스는 여전히 `CWSANDBOX_POOL_POLICY_NOT_CONFIGURED` 오류와 함께 거부됩니다.

이 기능을 사용하기 전에 알아두어야 할 두 가지 동작이 있습니다.

* **기본값은 연결이 아닌 스냅샷입니다.** 러너에 한 번 적용되면 해당 정책은 일반 러너 정책이 됩니다. 이후 `default_runner_policy`를 변경해도 이미 정책이 있는 러너에는 반영되지 않습니다. 이러한 러너는 `UpdateManagedRunner`로 업데이트하세요.
* **기본값이 유효하지 않으면 샌드박스를 생성할 수 없습니다.** 게이트웨이는 시작 시 설정된 정책을 검증합니다. 검증에 실패해도 게이트웨이는 시작되지만, 샌드박스 생성은 `CWSANDBOX_SERVERLESS_MISCONFIGURED` 오류와 함께 실패합니다.

<h2 id="constrain-compute">
  컴퓨트 제한
</h2>

`resources`는 컨테이너가 요청할 수 있는 범위를 제한하고, 샌드박스가 아무것도 요청하지 않을 때 적용할 기본값을 제공합니다.

```json theme={"system"}
{
  "constraints": {
    "resources": {
      "minCpu": "500m",
      "maxCpu": "8",
      "defaultCpu": "2",
      "minMemory": "1Gi",
      "maxMemory": "32Gi",
      "defaultMemory": "4Gi",
      "maxGpuCount": "2",
      "requireLimits": true
    }
  }
}
```

`requireLimits`를 `true`로 설정하여 CPU와 메모리 제한을 모두 선언하지 않는 샌드박스를 거부합니다. `cpuCeiling`과 `memoryCeiling`을 사용하여 샌드박스의 resolved total을 한도로 제한하세요. 이는 기본 레이어가 자체 컨테이너를 제공할 때 중요합니다.

`maxGpuCount`는 한 샌드박스가 요청할 수 있는 GPU 수를 한도로 제한합니다. 생략하면 한도를 적용하지 않습니다. `0`으로 설정하면 모든 GPU 요청을 거부하며, 이는 GPU-free pool을 표현하는 방법입니다. 한도를 초과하는 요청은 `CWSANDBOX_RESOURCE_CEILING_EXCEEDED` 오류로 실패합니다.

<h2 id="constrain-images">
  이미지 제한
</h2>

`image`는 샌드박스 이미지의 출처를 제한합니다. 빈 그룹은 모든 이미지를 허용합니다. `[GITHUB-ORG]`를 GitHub Container Registry 조직 이름 또는 사용자 이름으로 바꾸세요.

```json theme={"system"}
{
  "constraints": {
    "image": {
      "allowedRegistries": ["ghcr.io/[GITHUB-ORG]"],
      "allowedImages": ["ghcr.io/[GITHUB-ORG]/agent-base:2024.11"]
    }
  }
}
```

<h2 id="constrain-network-access">
  네트워크 액세스 제한
</h2>

네트워크 제약 조건은 엔벨로프처럼 작동합니다. 샌드박스가 이그레스를 선언하면 정책은 해당 선언의 범위를 넓히지 않고 허용하거나 거부합니다. 샌드박스가 이그레스를 선언하지 않으면 정책은 자체 이그레스 기본값을 적용합니다. 단, 샌드박스가 `deny_egress`를 설정한 경우는 예외입니다.

두 설정은 별도의 작업을 수행합니다:

* `allowedEgress`는 이그레스 허용 목록이며, 샌드박스가 생성될 때 확인됩니다. 비어 있지 않은 경우, 샌드박스가 선언하는 모든 규칙은 그 안에 맞아야 하며, 범위를 벗어나는 규칙은 거부되며 좁혀지지 않습니다. 비어 있으면 무엇이든 선언할 수 있습니다.
* `defaultEgress`는 요청이 없을 때의 의미입니다. 샌드박스가 자체 이그레스를 선언하지 않고 `deny_egress`도 설정하지 않은 경우에만 적용됩니다. 어떤 선언이든 이를 완전히 대체합니다.

규칙은 하나의 대상을 지정합니다. `cidr`을 선택적 `except` carve-outs와 함께 사용하거나, 다른 샌드박스와의 관계를 위한 `tenant`, 레이블로 선택한 워크로드를 위한 `selector`, HTTPS 호스트 이름을 위한 `httpsHostname`, 또는 `any`를 사용합니다. 선택적 `ports`는 규칙을 더 좁힙니다. 호스트 이름 규칙은 TCP 443만 허용하며, 이를 지원하는 러너가 필요합니다. 이러한 규칙은 `defaultEgress`가 아닌 `allowedEgress`와 샌드박스 요청에 지정해야 합니다.

```json theme={"system"}
{
  "constraints": {
    "network": {
      "allowedEgress": [
        { "cidr": { "cidr": "0.0.0.0/0", "except": ["10.0.0.0/8", "169.254.169.254/32"] } },
        { "tenant": "TENANT_SCOPE_SAME_ORG" }
      ],
      "defaultEgress": [
        { "tenant": "TENANT_SCOPE_SAME_ORG" }
      ]
    }
  }
}
```

예시는 공개 인터넷을 허용하면서 비공개 공간과 인스턴스 메타데이터 주소를 제외하고, 샌드박스가 동일한 조직 내 다른 샌드박스에 액세스할 수 있도록 허용합니다. 아무것도 선언하지 않은 샌드박스는 동일 조직 액세스만 받습니다.

테넌트 범위는 `TENANT_SCOPE_SAME_USER`와 `TENANT_SCOPE_SAME_ORG`입니다. 세 번째 값인 `TENANT_SCOPE_SANDBOX_NETWORK`은 아직 지원되지 않으며, 이를 사용하는 이그레스 규칙은 거부됩니다.

Ingress는 공개 범위가 `CUSTOM`인 포트에 대해 `allowedIngress`와 `defaultIngress`를 사용합니다. 허용 목록이 비어 있지 않으면 선언된 모든 ingress 규칙이 이 목록의 제한을 받습니다. 샌드박스가 ingress 규칙을 선언하지 않고 `CUSTOM` 포트를 노출하면 `defaultIngress`가 적용됩니다. 단, 샌드박스에 `deny_ingress`가 설정된 경우는 예외입니다. ingress 규칙을 명시적으로 선언하면 이 기본값을 대체합니다. Ingress 규칙은 `cidr`, `tenant` 또는 `any`를 허용하며, 이름 기반 소스는 허용하지 않습니다.

호스트 이름 기반 HTTPS 규칙을 거부하려면 `denyHttpsHostnameRules`를 설정하세요. 이 설정은 DNS 쿼리나 CIDR 규칙으로 허용된 HTTPS 트래픽은 차단하지 않습니다. 아웃바운드 UDP/TCP 포트 53을 차단하려면 `dnsEgress`를 `DNS_EGRESS_MODE_DENY`로 설정하세요. 이 값을 생략하면 플랫폼 리졸버에 대한 DNS 액세스가 허용됩니다. 플랫폼 DNS 및 저장소 액세스는 대상 규칙과 별도로 부여됩니다. 포함 규칙과 DNS 동작에 대한 자세한 내용은 [네트워크 제약 조건](/ko/products/sandboxes/reference/profile#networkconstraints)을 참조하세요.

<h2 id="constrain-security-posture">
  보안 태세 제한
</h2>

`security`는 게스트 내부 권한과 샌드박스가 실행되는 격리 환경을 제어합니다.

```json theme={"system"}
{
  "constraints": {
    "security": {
      "allowPrivileged": false,
      "allowedCapabilities": ["NET_BIND_SERVICE"],
      "allowedSeccompProfiles": ["RuntimeDefault"],
      "allowedRuntimeClasses": ["kata-qemu"],
      "defaultCpuRuntimeClass": "kata-qemu"
    }
  }
}
```

`allowedRuntimeClasses`는 기본적으로 접근을 차단합니다. 목록이 비어 있거나 없으면 런타임 클래스를 전혀 고정할 수 없으므로, 샌드박스는 목록에 명시적으로 지정된 클래스만 선택할 수 있습니다. 샌드박스가 클래스를 고정하지 않을 때 사용할 클래스를 선택하려면 `defaultCpuRuntimeClass`와 `defaultGpuRuntimeClass`를 설정하세요.

<h2 id="constrain-instances-lifetime-metadata-and-volumes">
  인스턴스, 수명, 메타데이터, 볼륨 제한
</h2>

나머지 그룹은 규모가 작습니다.

| 그룹 | 필드 | 효과 |
| - | - | - |
| `instance` | `allowedInstanceTypes` | 샌드박스를 배치할 수 있는 노드 인스턴스 유형을 제한합니다. |
| `lifecycle` | `defaultLifetimeSeconds` | 샌드박스가 수명을 지정하지 않을 때 적용되는 수명입니다. 모든 샌드박스에는 플랫폼의 최대 수명(현재 30일)이 적용됩니다. `maxLifetimeSeconds`는 정책 문서에서 제거되었으며, 지정하면 거부됩니다. |
| `metadata` | `deniedAnnotationPrefixes`, `maxAnnotationCount` | 접두사를 기준으로 어노테이션 키를 거부하고, 샌드박스에 설정할 수 있는 어노테이션 수에 한도를 둡니다. `0`은 제한 없음을 의미합니다. |
| `volumes` | `allowedMedia`, `maxSize` | 저장소 매체를 제한하고 볼륨별 크기에 한도를 설정합니다. RAM 기반 볼륨을 금지하려면 `STORAGE_MEDIUM_MEMORY`를 제외하세요. |

```json theme={"system"}
{
  "constraints": {
    "lifecycle": { "defaultLifetimeSeconds": 3600 },
    "volumes": { "allowedMedia": ["STORAGE_MEDIUM_DISK"], "maxSize": "100Gi" }
  }
}
```

<h2 id="the-base-layer">
  기본 레이어
</h2>

제약 조건은 샌드박스가 요청할 수 있는 항목을 제한합니다. `base` 레이어는 요청 없이 모든 샌드박스가 받는 항목을 제공합니다: 기본값과 스케줄러, 노드 셀렉터, 톨러레이션, 서비스 계정, 이미지 풀 시크릿 같은 첨부 항목입니다. 그 형태는 러너 런타임에 따라 달라지며, Kubernetes 러너에서는 파드 사양 조각입니다.

<h2 id="next-steps">
  다음 단계
</h2>

* [정책 개요](/ko/products/sandboxes/profiles/profiles): 샌드박스가 정책에 따라 어떻게 해결되는지, 그리고 프로필에서 변경된 사항.
* [러너 배포 및 관리](/ko/products/sandboxes/operations/managed-runners): 러너 라이프사이클과 나머지 러너 설정.
* [컨트롤 플레인 API 개요](/ko/products/sandboxes/reference/control-plane-api): 인증, 필드 마스크, 그리고 엔드포인트 계약.
