# 보안

kstack의 목표 중 하나는 AI 에이전트가 Kubernetes 모니터링, 문제 해결, 감사 작업을 평소보다 안전하게 수행할 수 있도록 돕는 것입니다. kstack은 신뢰할 수 없는 데이터로 처리해야 할 입력과 수행 전 사용자 허가가 필요한 후속 조치를 에이전트에게 알리는 보호 장치를 설정하여 이를 달성합니다. 이 페이지에서는 신뢰 경계, kstack이 신뢰할 수 없는 데이터를 에이전트 컨텍스트에서 격리하기 위해 취하는 조치, 그리고 의도적으로 해당 경계를 넘는 두 가지 스킬(`/exec`, `/logs`)에 대해 설명합니다.

---

## 신뢰 경계

AI 에이전트를 사용한 클러스터 상호작용에는 세 주체가 관여합니다:

- **사용자** — 프롬프트, `kubeconfig`, 클러스터에 대한 작업 권한을 제공합니다. 파괴적이거나 위험한 작업에 대한 허가를 부여할 수 있는 유일한 주체입니다.
- **에이전트** — 프롬프트를 해석하고, 호출할 스킬을 결정하며, 스킬이 반환하는 모든 출력을 읽습니다.
- **클러스터** — Kubernetes API 및 관련 도구를 통해 데이터를 반환합니다. 해당 데이터는 **신뢰할 수 없는** 입력입니다. 최악의 경우 파드 이름, 로그 라인, 어노테이션, 이벤트 메시지는 모두 공격자가 제어할 수 있으며, 이를 무비판적으로 읽는 에이전트는 그에 의해 조종될 수 있습니다.

kstack의 역할은 신뢰할 수 없는 클러스터 데이터가 에이전트의 동작을 주도하지 않도록 하면서 에이전트의 유용성을 유지하는 것입니다.

---

## kstack이 제공하는 보호

### 1. 명확하게 정의된 응답 엔벨로프

kstack 스킬이 내부적으로 사용하는 모든 스크립트는 정확히 하나의 JSON 객체를 stdout("응답 엔벨로프")에 씁니다. 객체의 스키마는 버전이 지정되어 있으며 [사전 정의된 형식](https://github.com/kubetail-org/kstack/blob/main/src/schemas/response.schema.json)에 대해 유효성이 검사됩니다:

```jsonc
{
  "kstack":        "1",
  "status":        "ok" | "error",
  "render":        "verbatim" | "agent",   // ok only
  "content":       string,                 // ok only; JSON-escaped
  "agent_context": string,                 // ok only; optional side-channel
  "kind":          "user" | "infra",       // error only
  "message":       string,                 // error only
  "kube_context":  string,                 // optional; pinned cluster
  "notice":        string                  // optional; operator banner
}
```

이 계약의 보안 관련 속성은 다음과 같습니다:

<dl>
  <dt>`render`</dt>
  <dd>`content`의 의도된 대상을 에이전트에게 알리는 열거형(`verbatim` 또는 `agent`)입니다. `render: verbatim`은 에이전트에게 `content`를 그대로 출력하고 재포맷이나 후속 추론 없이 턴을 종료하도록 지시합니다. `render: agent`는 `content`를 에이전트가 추론할 수 있는 도구 출력으로 표시합니다.</dd>

  <dt>`content`</dt>
  <dd>에이전트에 대한 페이로드를 담는 JSON 이스케이프 문자열 필드입니다.</dd>

  <dt>`agent_context`</dt>
  <dd>스크립트가 에이전트의 후속 작업에 활용할 수 있는 컨텍스트 데이터(예: 캐시 경로, 개수, 확인된 식별자)를 제공하는 데 사용하는 JSON 이스케이프 문자열 필드입니다. 에이전트만 읽으며 사용자에게는 표시되지 않아 `render: verbatim` 시 `content`를 깔끔하게 유지하고 메타데이터가 터미널로 누출되는 것을 방지합니다.</dd>

  <dt>`message`</dt>
  <dd>스크립트에서 생성된 유형화된 오류를 전달하는 JSON 이스케이프 문자열 필드입니다.</dd>
</dl>

비정상 종료는 예기치 않은 충돌을 위해 예약되어 있으며, 이 경우 에이전트는 의도를 추측하는 대신 stderr를 출력하고 중단하도록 지시받습니다.

### 2. 대량 클러스터 데이터는 디스크에 유지되며 `jq`를 통해 읽힙니다

kstack 없이는 AI 에이전트가 모든 파드, 노드, 이벤트를 컨텍스트로 스트리밍하여, 관련 없는 데이터로 컨텍스트가 낭비되고, 공격자가 영향을 줄 수 있는 텍스트 덩어리에서 필드와 지시문을 구분하는 일을 모델에 맡기게 됩니다. kstack은 응답을 컨텍스트별 `cache_dir`에 기록하고 캐시된 JSON에 대해 `jq`를 실행하여 후속 질문에 답할 수 있도록 에이전트에 위치를 전달함으로써 이를 방지합니다.

이 접근 방식의 두 가지 이점은 다음과 같습니다:

- **산문 해석 대신 구조적 파싱.** `jq '.items[].metadata.name'`은 알려진 스키마를 탐색하고 문자열 값을 반환합니다. 파드 어노테이션에 있는 프롬프트 인젝션 페이로드는 알려진 JSON 경로의 문자열 값으로 남아 있으며, 모델이 지시문으로 이해하도록 요청받는 텍스트가 아닙니다.

- **제한된 컨텍스트 증가.** 전체 파드별/노드별 테이블은 모델의 컨텍스트 창에 들어가지 않습니다. kstack 스킬이 제공하는 결정론적 요약은 클러스터 크기에 관계없이 수백 토큰이며, 후속 턴에서는 질문에 필요한 특정 필드만 가져옵니다.

### 3. 파괴적이거나 민감한 작업은 사용자 확인이 필요합니다

kstack 스킬이 수행하는 클러스터 작업은 읽기 전용이며 설계상 안전하지만, 에이전트에게 클러스터 상태를 변경하거나 사용자를 대신하여 권한 있는 정보를 요청하는 후속 작업을 수행하도록 요청할 수 있습니다. 에이전트가 허가 없이 이러한 작업을 수행하지 않도록 각 스킬은 에이전트와의 명확한 경계를 설정하고, 클러스터 상태를 변경하는 작업(리소스 삭제, `ConfigMaps` 수정)이나 자격 증명을 노출하는 작업(`Secrets` 읽기)을 수행하기 전에 확인을 요청하도록 지시합니다.

### 4. 클러스터 컨텍스트는 세션별로 고정됩니다

세션의 첫 번째 kstack 스킬이 `kube_context`를 확인하여 반환합니다. 후속 스킬은 사용자가 명시적으로 다른 클러스터를 요청할 때까지 모든 kubectl/kubetail 호출에 `--context=<value>`를 전달하도록 지시받습니다. 이를 통해 한 클러스터를 위한 작업을 실수로 다른 클러스터에 수행하는 것을 방지합니다.

### 5. RBAC를 준수합니다

kstack은 홈 디렉토리에 설치된 셸 스크립트와 `SKILL.md` 파일로 제공됩니다. 모든 Kubernetes 호출은 각 컨텍스트에 구성된 `user`에 대해 이미 가지고 있는 자격 증명 및 RBAC 바인딩을 사용하여 로컬 `kubeconfig`를 통해 이루어집니다.

---

## 라이브 클러스터 데이터를 에이전트로 스트리밍할 수 있는 스킬

kstack에는 사용자와 에이전트 모두가 상호작용할 수 있는 tmux 창 내에서 실행되는 두 가지 스킬(`/exec`, `/logs`)이 포함되어 있습니다. 창은 클러스터 데이터가 가장 쉽게 에이전트의 추론 컨텍스트에 들어갈 수 있는 곳이므로, 실행 전에 신중히 생각해야 하는 스킬입니다.

### 창 기반 스킬의 신뢰 모델

기본적으로 에이전트는 tmux 세션(명령 입력, 쿼리 범위 지정)을 제어할 수 있지만, 사용자가 지시하지 않는 한 창 내용을 읽지 않습니다(예: "마지막 로그 세트에서 오류를 파싱해줘"). 이는 신뢰할 수 없는 데이터가 실수로 에이전트의 추론 컨텍스트에 들어가는 것을 방지하도록 설계되었습니다. 두 가지 플래그로 이 동작을 제어할 수 있습니다:

- **`--trust-pane`** — 에이전트가 매 턴마다 창을 읽고 내용을 요약하거나 연관 짓거나 모델 API에 전송할 수 있습니다. 에이전트가 무슨 일이 일어나고 있는지 추론하기를 명시적으로 원할 때 사용하십시오(예: "이것을 보고 충돌루프가 해소되면 알려줘").
- **`--detach`** — 에이전트가 창에 전혀 연결되지 않습니다. 읽거나 입력할 수 없습니다. 수동으로 연결하며, 모델에서 세션 내용으로의 경로가 없습니다. 이는 에이전트의 자율적 준수가 아니라 kstack이 구조적으로 강제하는, 기본 동작과 짝을 이루는 보호책입니다.

창 읽기 동작은 프롬프트 수준 계약입니다.

### `/exec`

`/exec` 스킬은 파드, 임시 디버그 컨테이너, 또는 노드의 권한 있는 파드로의 대화형 셸을 엽니다.

주의할 사항:

- **노드 및 디버그 컨테이너 모드는 권한이 있습니다.** 노드 모드는 `hostPID`, `hostNetwork`, 그리고 `/host`에 마운트된 호스트 파일 시스템을 가진 단기 파드를 생성합니다. 디버그 컨테이너 모드는 대상 파드의 프로세스 네임스페이스에 조인합니다. 둘 다 일반적인 `exec`보다 훨씬 넓은 접근 권한을 부여합니다. 에이전트는 셸을 열기 전에 확인된 대상과 모드를 설명하므로 진행하기 전에 확인할 수 있습니다.
- **세션은 명시적으로 종료할 때까지 계속 실행됩니다.** 에이전트는 권한 있는 노드 파드를 자체적으로 삭제하지 않으며 사용자의 요청을 기다립니다.

### `/logs`

`/logs` 스킬은 클러스터에 대해 Kubetail 쿼리를 실행하고 일치하는 로그 라인을 창으로 스트리밍합니다.

주의할 사항:

- **로그에는 민감한 데이터가 자주 포함됩니다.** `Authorization` 헤더의 토큰, PII가 포함된 요청 본문, 시크릿을 포함하는 스택 트레이스는 모두 흔합니다. `--trust-pane` 설정 여부와 관계없이 쿼리를 좁게 범위 지정하십시오: 특정 워크로드, 짧은 시간 범위, 대상화된 grep 패턴.
- **Kubetail의 노드 측 grep이 도움이 됩니다.** 필터를 클러스터로 푸시하면 처음부터 와이어를 통해 전송되는 라인이 줄어듭니다. 즉, 창(그리고 `--trust-pane`의 경우 에이전트)에 도달하는 라인도 줄어듭니다. 광범위하게 가져와서 머릿속으로 필터링하는 것보다 필터를 구체적으로 사용하십시오.

---

## 보안 테스트

kstack의 테스트 전략은 의미 있는 가장 낮은 계층에서 위의 각 보호 기능을 검증하므로, 회귀가 현장에서 예기치 않은 문제가 아닌 테스트 실패로 나타납니다. 프로젝트에는 네 가지 테스트 계층이 있습니다 — [`tests/unit`](https://github.com/kubetail-org/kstack/tree/main/tests/unit), [`tests/integration`](https://github.com/kubetail-org/kstack/tree/main/tests/integration), [`tests/e2e`](https://github.com/kubetail-org/kstack/tree/main/tests/e2e), [`tests/evals`](https://github.com/kubetail-org/kstack/tree/main/tests/evals) — 보안 커버리지는 다음과 같이 분산되어 있습니다:

- **단위(`bats`).** [`src/lib/response.sh`](https://github.com/kubetail-org/kstack/blob/main/src/lib/response.sh)의 이스케이프 루틴과 엔벨로프 빌더를 직접 검증합니다. 따옴표, 백슬래시, 개행 문자, 제어 문자, 혼합 바이너리 모양 페이로드를 `response::_escape` 및 `response::ok_*`에 입력하고, 방출된 각 엔벨로프를 `jq`로 JSON으로 다시 파싱해 형식이 올바른지 검증합니다. `","`를 포함하는 파드 이름, `\n"render":"agent"`를 포함하는 어노테이션 등 인젝션 형태의 문자열이 `content` 값으로 처리되며 형제 키를 도입하지 않는지 확인합니다. `--detach`에 대한 플래그 파싱은 타이포나 리팩터링으로 인해 자동으로 비활성화될 수 없도록 단위 테스트됩니다.
- **통합(`bats`).** 각 스킬이 `PATH`의 가짜 `kubectl`을 사용하여 엔드투엔드로 호출되며, 방출된 엔벨로프는 [`src/schemas/response.schema.json`](https://github.com/kubetail-org/kstack/blob/main/src/schemas/response.schema.json)의 JSON 스키마에 대해 검증됩니다. `kube_context` 고정은 다중 스킬 흐름을 실행하고 모든 다운스트림 호출이 `--context=<resolved>`를 전달하는지 확인하여 검증됩니다.
- **엔드투엔드(kind 기반).** `kind`로 실제 클러스터를 구성하고 스킬을 실행합니다. 이 테스트는 실제 Kubernetes API 서버에서 구조적 보호가 유지되는지 확인합니다: RBAC 거부 시 stderr 누출이 아닌 유형화된 `error` 엔벨로프가 생성되고, `/exec`의 권한 있는 모드(노드, 디버그 컨테이너)가 확인 경로 이전에 예상 파드 사양으로 확인됩니다.
- **평가(Claude 기반).** 프롬프트 수준 계약에는 에이전트 루프 테스트가 필요하므로 여기에 배치됩니다. 시나리오는 다음을 포함합니다: 파드 어노테이션, 로그 라인, 이벤트 메시지에 심어진 프롬프트 인젝션 페이로드가 에이전트에게 지시문이 아닌 데이터로 처리되는지 확인; 확인 없이 에이전트가 클러스터 상태를 변경하거나 `Secret`을 읽도록 시도; 에이전트를 속여 유형화된 오류를 다른 명령으로 재시도하도록 시도; `--trust-pane` 없이 기본 읽기 금지 동작이 유지되는지 확인하는 창 기반 테스트. 평가는 확률적이므로 평가 기준은 바이너리 결과가 아닌 통과율을 기록하며, 사후 검토를 위해 아티팩트가 보존됩니다.

`shellcheck` 린트 패스는 모든 PR에서 실행되어 구조적 보장을 훼손할 수 있는 셸 버그 클래스(인용되지 않은 확장, 신뢰할 수 없는 입력의 `eval`)를 포착합니다. 단위 및 통합 계층은 `amd64` 및 `arm64` 모두에서 Linux, macOS, Windows의 모든 PR에서 실행됩니다; e2e 계층은 Linux에서 실행됩니다; 평가 계층은 CI에서 요청 시 트리거됩니다.

위 섹션에서 해당 테스트가 없는 보증을 발견했다면, 그것은 보고할 가치가 있는 버그입니다.

---

보안 문제를 발견하신 경우 [GitHub 저장소](https://github.com/kubetail-org/kstack)를 통해 신고하십시오.