본문 바로가기
서버구축 (WEB,DB)

LLM 생성 코드 실행의 위협 모델과 방어 설계: 탈출·유출·DoS 통제

by 날으는물고기 2026. 2. 25.

LLM 생성 코드 실행의 위협 모델과 방어 설계: 탈출·유출·DoS 통제

728x90

LLM이 만든 코드는 “우리 코드”가 아니라 외부 입력(External Input) 과 동일하게 취급해야 합니다.
즉, LLM 생성 코드를 실행하는 순간부터는 서버가 ‘코드 실행 플랫폼’이 되며, 공격자 관점에서 아래가 모두 가능합니다.

  • 악성 코드 실행: 파일 삭제/변조, 데이터 유출, 채굴 등
  • 샌드박스 탈출: 커널/런타임/설정 실수로 호스트·클러스터 권한 획득
  • 리소스 고갈(DoS): 무한 루프/메모리·디스크 폭주로 노드/네임스페이스 장애
  • 네트워크 악용: 내부망 스캔, C2 통신, 데이터 외부 반출
300x250

따라서 핵심은 단일 기법이 아니라 “다단계 격리 + 최소권한 + 정책 강제 + 감시/증적” 조합입니다.

(A) LLM/에이전트
→ 코드/입력/리소스 한도/필요 권한(capabilities)을 “선언”
(B) Code Execution Gateway(API)
→ 정적 검증(길이/금칙어/의존성/출력 제한) + 실행 요청 서명/감사로그
(C) Sandbox Orchestrator
→ K8s에 ephemeral Pod/Job 생성(요청당 1개) 후 실행
(D) 다단계 격리(Defense-in-Depth)

  • K8s 정책(PSA/PSS, RBAC, Quota, NetworkPolicy)
  • 컨테이너 하드닝(seccomp, AppArmor/SELinux, non-root, read-only, drop caps)
  • (선택) 런타임 격리 gVisor/Kata
    (E) 결과 수집
    → stdout/stderr + 지정된 output 디렉터리(아티팩트)만 회수 후 Pod 삭제

이 구조 자체가 “언트러스트드 실행”의 표준 패턴에 가깝습니다.

K8s에서 가장 중요한 보안 설계 포인트 12가지

아래 12가지는 “기본값으로 강제”가 목표입니다. (사용자가 선택하는 옵션이 되면 운영 중 틈이 생깁니다)

네임스페이스 분리 + 전용 노드 풀(권장)

  • sandbox-exec 전용 namespace
  • 가능하면 전용 node pool(taint/toleration)로 일반 워크로드와 분리

ServiceAccount 최소권한(RBAC) “생성 전용”

  • 실행 Pod는 클러스터 API 접근이 필요 없도록(기본 목표)
  • Orchestrator만 Pod/Job 생성 권한 보유
  • 실행 Pod에는 automountServiceAccountToken: false 권장(기본 토큰 차단)

Pod Security Admission(PSA)로 “Restricted” 강제

Kubernetes의 Pod Security Standards(PSS)는 Privileged/Baseline/Restricted 3단계이며, 실행 샌드박스는 원칙적으로 Restricted를 목표로 합니다.

컨테이너 보안 컨텍스트 “3종 세트”

  • runAsNonRoot: true
  • allowPrivilegeEscalation: false
  • readOnlyRootFilesystem: true

Linux capabilities “ALL drop” 기본

  • 기본적으로 capabilities.drop: ["ALL"]
  • 정말 필요한 경우만 최소 추가

seccomp: RuntimeDefault 기본 + 필요시 커스텀

  • 일단 RuntimeDefault는 거의 필수(기본 syscall 면적 축소)
  • 커스텀은 운영 성숙도 올라간 뒤 단계적으로(차단 로그 기반)

NetworkPolicy: 기본 egress/ingress 모두 deny

K8s는 기본이 “모든 egress 허용”이기 때문에, 정책이 없으면 내부망 스캔/외부 유출이 가능합니다.

  • 원칙: sandbox Pod는 네트워크 0
  • 예외: “허용된 프록시”로만 egress 허용(도메인/목적지 통제)

리소스 한도: CPU/Mem/Ephemeral storage + 시간 제한

  • resources.limitsephemeral-storage까지 포함
  • 실행 시간 timeout(예: 10~30초)
  • 파일 개수/출력 크기 제한(게이트웨이에서 stdout/stderr 상한)

Quota/LimitRange로 네임스페이스 전체 폭주 방지

  • 동시 실행 Pod 수, 총 CPU/Mem 상한을 namespace 단위로 묶기

이미지/의존성 전략

  • “인터넷 없이” 실행이 기본이면: 미리 빌드된 런타임 이미지 + 내부 패키지 레지스트리 사용
  • pip install 같은 동적 설치는 보안·재현성·성능 모두 악화

감사(Audit)와 증적

K8s Audit 로그는 “누가 무엇을 만들고/exec 했는지”를 추적하는 핵심 증적입니다.

  • sandbox namespace의 create pods/jobs, exec, portforward 같은 이벤트를 반드시 로깅

(선택) 런타임 격리: gVisor / Kata

컨테이너만으로는 커널 공격면이 남습니다. 더 강한 격리가 필요하면

  • gVisor: userspace kernel로 격리 강화(특히 멀티테넌트/고위험 실행에 유리)
  • Kata Containers: 경량 VM 계열 격리(보다 강한 경계)

llm-sandbox(vndee)로 K8s Ephemeral 실행 구성하기

도구 위치

vndee/llm-sandbox는 Docker/Kubernetes/Podman 같은 백엔드에서 세션 기반으로 코드를 실행하도록 설계된 런타임입니다. K8s 백엔드 및 Pod manifest 커스터마이징 예시도 제공합니다.

파이썬 실행 예시(개념)

아래는 “K8s 백엔드 + Pod 보안옵션을 강제”하는 형태의 전형적인 코드 골격입니다.

from llm_sandbox import SandboxSession
from llm_sandbox.backends import SandboxBackend

pod_manifest = {
  "apiVersion": "v1",
  "kind": "Pod",
  "metadata": {"namespace": "sandbox-exec", "labels": {"app": "llm-sandbox"}},
  "spec": {
    "automountServiceAccountToken": False,
    "securityContext": {
      "runAsNonRoot": True,
      "runAsUser": 1000,
      "seccompProfile": {"type": "RuntimeDefault"},
    },
    "containers": [{
      "name": "py",
      "image": "python:3.12-slim",
      "securityContext": {
        "allowPrivilegeEscalation": False,
        "readOnlyRootFilesystem": True,
        "capabilities": {"drop": ["ALL"]},
      },
      "resources": {
        "limits": {"cpu":"500m","memory":"512Mi","ephemeral-storage":"1Gi"},
        "requests": {"cpu":"100m","memory":"128Mi"}
      },
      "volumeMounts": [{"name":"tmp","mountPath":"/tmp"}],
    }],
    "volumes": [{"name":"tmp","emptyDir": {}}],
    "restartPolicy": "Never",
  }
}

with SandboxSession(
    backend=SandboxBackend.KUBERNETES,
    lang="python",
    pod_manifest=pod_manifest,
) as s:
    r = s.run("print(2+2)")
    print(r.stdout, r.stderr, r.exit_code)

포인트: “사용자가 실행 옵션을 바꾸게 두지 말고”, 오케스트레이터가 보안 템플릿을 강제하는 구조로 잡으셔야 합니다.

NetworkPolicy 기본 템플릿 (강추)

기본 deny (ingress+egress)

K8s 네트워크 정책은 “적용되는 순간부터 허용 목록만 통과”입니다.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: sandbox-default-deny
  namespace: sandbox-exec
spec:
  podSelector: {}
  policyTypes: ["Ingress", "Egress"]

(예외) 프록시로만 egress 허용

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: sandbox-egress-only-proxy
  namespace: sandbox-exec
spec:
  podSelector: {}
  policyTypes: ["Egress"]
  egress:
  - to:
    - namespaceSelector:
        matchLabels:
          name: proxy-ns
      podSelector:
        matchLabels:
          app: egress-proxy
    ports:
    - protocol: TCP
      port: 3128

gVisor/Kata 적용 방법(선택지)

gVisor (runtimeClassName)

K8s에서 runtimeClassName: gvisor로 샌드박스 런타임을 선택하는 패턴이 널리 쓰입니다.

spec:
  runtimeClassName: gvisor

Kata (runtimeClassName)

Kata도 RuntimeClass로 선택합니다.

spec:
  runtimeClassName: kata

선택 가이드

  • “단일테넌트 + 낮은 위험도” → 컨테이너 하드닝 + 네트워크 차단만으로 PoC 가능
  • “멀티테넌트/고위험 코드 실행/보안팀이 책임지는 플랫폼” → gVisor 또는 Kata를 2차 격리로 고려

보안 운영 가이드/점검 포인트

아래는 내부 사용자(개발/AI팀)에게 “필수 준수사항”으로 제시하기 좋은 형태입니다.

아키텍처/권한

  1. 실행 Pod에 SA 토큰 자동 마운트 금지(automountServiceAccountToken: false)
  2. 실행 Pod는 K8s API 접근 불필요(원칙)
  3. 오케스트레이터만 Pod/Job 생성 권한(RBAC 최소화)

Pod/컨테이너 하드닝

  1. Non-root 강제 + UID 고정
  2. Privilege escalation 금지
  3. Read-only root FS + /tmp만 쓰기
  4. Capabilities ALL drop
  5. seccomp RuntimeDefault 기본

네트워크/데이터 유출

  1. NetworkPolicy 기본 deny(ingress/egress)
  2. 예외 통신은 “프록시 1곳”으로만(감사·DLP·도메인 통제 가능)
  3. 내부망 대역(예: RFC1918) 접근 원천 차단 정책 포함

리소스/DoS

  1. CPU/Mem/Ephemeral storage limit 필수
  2. 실행 시간 timeout 필수(예: 10~30초)
  3. 동시 실행 수 제한(ResourceQuota)
  4. stdout/stderr 및 결과물 크기 제한

로깅/감사/탐지

  1. K8s Audit 로그 활성화 및 sandbox namespace 집중 수집
  2. “누가 어떤 코드 실행 요청을 했는지” 애플리케이션 레벨 감사로그(요청ID/사용자/해시)
  3. 비정상 행위 탐지 룰(예: privileged 시도, exec 시도, 네트워크 차단 위반 등) — SandboxEval 같은 관점의 테스트로 정기 검증

PoC에서 “최소 세트” 추천

K8s + 파이썬 위주 PoC라면, 우선순위를 이렇게 두시면 실패 확률이 확 내려갑니다.

  1. 요청당 1 Pod(또는 1 Job) 생성 → 실행 → 삭제 (ephemeral)
  2. PSA(PSS Restricted 지향) + securityContext 3종세트(non-root/RO/NoPrivEsc)
  3. NetworkPolicy 기본 deny
  4. 리소스 limit + timeout + quota
  5. Audit 로그 수집
  6. (필요 시) gVisor/Kata로 한 단계 더 격리
  7. 실행 프레임워크는 llm-sandbox로 시작(템플릿 강제 가능)
728x90
그리드형(광고전용)

댓글