Metadata-Version: 2.4
Name: agent-k8s-harden-check
Version: 0.1.0
Summary: Read-only checker for Kubernetes AI-agent workloads: flags missing gVisor/Kata runtime class, token automount, root or privileged containers, host namespaces, missing limits and missing metadata/RFC1918 egress NetworkPolicy.
Author: Digital Fortress
License-Expression: MIT
Project-URL: Homepage, https://github.com/digitalfortressaudit/agent-k8s-harden-check
Project-URL: Source, https://github.com/digitalfortressaudit/agent-k8s-harden-check
Project-URL: Issues, https://github.com/digitalfortressaudit/agent-k8s-harden-check/issues
Project-URL: Changelog, https://github.com/digitalfortressaudit/agent-k8s-harden-check/releases
Project-URL: Full pack, https://fortressaudit.gumroad.com/l/ngouvf?utm_source=pypi&utm_medium=package&utm_campaign=agent-k8s-harden-check
Keywords: kubernetes,k8s-security,kubernetes-security,ai-agent-security,agent-sandbox,gvisor,kata-containers,networkpolicy,cloud-metadata,devsecops,llm-security
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Information Technology
Classifier: Intended Audience :: System Administrators
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Security
Classifier: Topic :: System :: Systems Administration
Classifier: Topic :: Software Development :: Quality Assurance
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: PyYAML>=6.0
Dynamic: license-file

# agent-k8s-harden-check: Kubernetes Agent Workload Hardening Checker

Read local Kubernetes YAML and flag AI-agent workloads that are missing isolation. One Python script. PyYAML is the only dependency.

Use it on manifests you own or are explicitly allowed to review.

## Why it matters

Agent workloads often run with a tool that can open HTTP connections. Three public write-ups are the reason this checker exists:

- [Zenity AgentCorruption](https://labs.zenity.io/post/agentcorruption-how-a-single-prompt-collapsed-the-entire-cloud-security-model) describes an agent HTTP tool that could reach the instance metadata service.
- [Anthropic's report on unintended model actions](https://www.anthropic.com/research/investigating-unintended-model-actions) describes agent actions the product limits did not contain.
- The [agent-sandbox secure-by-default ValidatingAdmissionPolicy](https://agent-sandbox.sigs.k8s.io/docs/use-cases/examples/secure-sandbox-vap/) describes the isolation Kubernetes SIG Apps publishes for Sandbox workloads: a gVisor runtime class, no service-account token, no privileged or root process, no host namespaces, and a NetworkPolicy that blocks RFC1918 and cloud-metadata egress.

Those are links to the public pages. This repository does not restate procedures from them. It reads the YAML you already have and tells you which of those controls are missing from the text.

## Quickstart

Requires Python 3.9 or newer.

```bash
pip install agent-k8s-harden-check
```

To match CI exactly:

```bash
pip install -r requirements.txt
```

`requirements.txt` pins PyYAML. The script imports that package and the standard library only.

From this directory, the script and the installed command take the same path:

```bash
python3 agent_k8s_harden_check.py examples/bad-agent-pod.yaml
agent-k8s-harden-check examples/bad-agent-pod.yaml

python3 agent_k8s_harden_check.py examples/good-agent-pod.yaml examples/egress-networkpolicy.yaml
agent-k8s-harden-check examples/good-agent-pod.yaml examples/egress-networkpolicy.yaml

python3 agent_k8s_harden_check.py examples --json
agent-k8s-harden-check examples --json
```

`PATH` is a YAML file, or a directory. A directory is scanned for `.yaml` and `.yml` files. Hidden directories are skipped. Multi-document YAML is read. The examples are fictional and are there for a local offline check.

`examples/bad-agent-pod.yaml` is a pod with no runtime class, a service-account token automount, a privileged root container, host networking, and no limits. That run exits `1`:

```text
Kubernetes agent workload hardening check

examples/bad-agent-pod.yaml
  FAIL  runtime-class                         Pod/fictional-unisolated-agent  ns=agent-lab
        runtimeClassName is not set
  FAIL  automount-service-account-token       Pod/fictional-unisolated-agent  ns=agent-lab
        pod automountServiceAccountToken is true
  PASS  projected-service-account-token       Pod/fictional-unisolated-agent  ns=agent-lab
        no projected volume mounts a serviceAccountToken
  FAIL  privileged                            Pod/fictional-unisolated-agent  ns=agent-lab
        privileged is true on container agent
  FAIL  run-as-non-root                       Pod/fictional-unisolated-agent  ns=agent-lab
        root is set: container agent (runAsUser is 0)
  FAIL  host-namespaces                       Pod/fictional-unisolated-agent  ns=agent-lab
        host namespace enabled: hostNetwork
  WARN  resource-limits                       Pod/fictional-unisolated-agent  ns=agent-lab
        cpu or memory limits are missing: container agent (cpu, memory)
  WARN  egress-metadata-rfc1918               Pod/fictional-unisolated-agent  ns=agent-lab
        no NetworkPolicy with policyTypes Egress was found for namespace agent-lab. Manifest text only; this does not show the cluster enforces it.

summary: pass=1 warn=2 fail=5 errors=0
A pass is a reading of the local YAML. It is not cluster enforcement.
```

`examples/good-agent-pod.yaml` sets `runtimeClassName: gvisor`, turns automount off, runs as a non-root user, and sets cpu and memory limits. Scanned on its own, the egress check warns, because no NetworkPolicy was in that file. Exit `0`. Pass the egress example on the same command line and that warning clears. Exit stays `0`.

`--json` prints the same findings as JSON.

## What it checks

The script reads these kinds: Pod, Deployment, StatefulSet, DaemonSet, Job, CronJob, ReplicaSet, NetworkPolicy, plus Sandbox and SandboxTemplate. A document whose `apiVersion` contains `agent-sandbox` is read as a workload too. For Deployments and the other owners, the pod spec is `spec.template.spec`. For a CronJob it is `spec.jobTemplate.spec.template.spec`. For Sandbox and SandboxTemplate it is `spec.podTemplate.spec` (or `spec.template.spec` when that is where the fields are).

| Check | Pass | Otherwise |
| --- | --- | --- |
| `runtime-class` | `runtimeClassName` contains `gvisor` or `kata`, case-insensitive | fail when it is missing or names something else |
| `automount-service-account-token` | the pod, or the ServiceAccount it names in the same scan, sets `automountServiceAccountToken: false` | fail when it is true, or unset (Kubernetes defaults that to true) |
| `projected-service-account-token` | no projected volume source has `serviceAccountToken` | fail when one is present |
| `privileged` | `privileged` is not true on the pod or on any container, init container, or ephemeral container | fail when it is true |
| `run-as-non-root` | `runAsNonRoot: true` and `runAsUser` is not `0` | fail when a container is clearly root (`runAsUser: 0` or `runAsNonRoot: false`); warn when neither field says |
| `host-namespaces` | `hostNetwork`, `hostPID`, and `hostIPC` are false or absent | fail when any is true |
| `resource-limits` | every container has cpu and memory limits | warn when one is missing |
| `egress-metadata-rfc1918` | NetworkPolicy text in the same namespace does not allow `169.254.169.254/32`, `10.0.0.0/8`, `172.16.0.0/12`, or `192.168.0.0/16` | warn when no egress policy was in the scan, or the text is unclear |

The egress check looks for `policyTypes` containing `Egress`. Empty egress is read as default-deny text. An allow rule passes this check only when the four destinations above are outside the allow, including when they appear in an `except` list. Policies in one namespace are unioned, because Kubernetes unions allows. A pod or namespace selector is unclear for the RFC1918 ranges, since those selectors name pods rather than CIDRs. A `podSelector` with `matchLabels` is applied only when those labels are on the pod, or on the pod template. If the selector is not a clear match, that policy is not counted as coverage.

A pass on the egress check means those four destinations were excluded or omitted in the files you scanned. Other destinations may still be allowed. An empty egress list is the case where the text allows no destinations.

Every egress line says the same thing in prose: this is a reading of manifest text. It is not evidence that a cluster enforces the policy.

## What it does

It parses the files you name, prints a pass / warn / fail line per object and check, and returns the exit code below. `--json` prints `summary`, `findings`, and `errors`.

## What it does not do

- It does not connect to a cluster, run kubectl, or apply, create, or edit a resource.
- It does not decide that a cluster is safe. A clean file can still be absent from the cluster, and a failing file can describe a workload you have not deployed.
- It does not review admissions controllers, runtime installation, or identity systems that are not in the YAML you passed.
- It does not follow Helm or Kustomize. Give it rendered YAML.
- It does not treat a warning as success-of-the-control. Warnings are gaps the text did not settle. They do not fail the process exit code.

## Authorized use

This repository is [MIT licensed](https://github.com/digitalfortressaudit/agent-k8s-harden-check/blob/main/LICENSE). It is for **defensive checks only**.

- Review manifests you own or are authorized to assess.
- Keep the examples as local fixtures. They are fictional and are not a deployment guide.
- Do not point the script at files you are not allowed to read.

## Exit codes

| Code | Meaning |
| --- | --- |
| `0` | No check failed. Warnings are allowed. |
| `1` | One or more checks failed. |
| `2` | A path, flag, or YAML document could not be used (missing path, unknown flag, invalid YAML, or a directory with no `.yaml` / `.yml` files). |

## Tests

From this directory, with PyYAML installed:

```bash
python3 -m unittest discover -s tests -v
```

The workflow in `.github/workflows/test.yml` installs `requirements.txt` and runs that command. It does not contact a cluster.

## Examples

| File | What it is |
| --- | --- |
| `examples/bad-agent-pod.yaml` | Fictional pod missing the isolation fields: no runtime class, automount on, privileged root, host network, no limits |
| `examples/good-agent-pod.yaml` | Fictional pod with `runtimeClassName: gvisor`, automount off, non-root, no host namespaces, and limits |
| `examples/egress-networkpolicy.yaml` | Illustrative NetworkPolicy text that excludes the metadata address and the three RFC1918 ranges. Checker fixture, not an apply guide |
| `examples/sandbox-like.yaml` | Fictional Sandbox and SandboxTemplate documents using the public `podTemplate.spec` field names |

## For more from Digital Fortress

This checker reads a handful of fields in local YAML. The paid packs are the longer review set: prompts, templates, and checklists for the same kinds of systems.

For more from Digital Fortress:

- **[$99 Agent Runtime Containment Pack](https://fortressaudit.gumroad.com/l/ngouvf)**, the pack closest to this script: agent egress, identity, Kubernetes sandboxing, and tool-call authorization.
- **[$99 AI Security & Infrastructure Prompt Pack](https://fortressaudit.gumroad.com/l/myyeen)**
- **[$79 MCP & Multi-Agent Authorization Security Pack](https://fortressaudit.gumroad.com/l/wphmlq)**
- **[$149 Multi-Agent Orchestration Blueprint](https://fortressaudit.gumroad.com/l/cvxfw)**

Free siblings:

- [AI Security Starter Checklist](https://github.com/digitalfortressaudit/ai-security-starter-checklist)
- [MCP Tool Definition Pinning Checker](https://github.com/digitalfortressaudit/mcp-tool-pin-check)

## Sources

- [Zenity AgentCorruption](https://labs.zenity.io/post/agentcorruption-how-a-single-prompt-collapsed-the-entire-cloud-security-model)
- [Anthropic: Investigating unintended model actions](https://www.anthropic.com/research/investigating-unintended-model-actions)
- [agent-sandbox: Secure Sandbox Admission Policy](https://agent-sandbox.sigs.k8s.io/docs/use-cases/examples/secure-sandbox-vap/)

## License

[MIT](https://github.com/digitalfortressaudit/agent-k8s-harden-check/blob/main/LICENSE) © 2026 Digital Fortress · github.com/digitalfortressaudit. Authorized defensive use only, as described above.
