Pod security
French version: ../pod-security.md.
Context applied by the chart
Every chart pod (control plane, worker, migration, portal, LiteLLM, vLLM, multimodal workers) uses the eai.podSecurityContext and eai.containerSecurityContext helpers:
runAsNonRoot: true,runAsUser: 10001,runAsGroup: 10001,fsGroup: 10001;seccompProfile: RuntimeDefault;readOnlyRootFilesystem: true, with anemptyDirmounted on/tmp;allowPrivilegeEscalation: false;capabilities.drop: [ALL],NET_RAWincluded: a compromised pod cannot forge ARP or DNS packets to spoof a neighbour;hostNetwork,hostPID,hostIPCexplicitlyfalse, nohostPathvolume, nohostPort;- CPU and memory requests and limits on every container;
enableServiceLinks: false(no environment variables revealing the other Services).
automountServiceAccountToken: false on every pod and ServiceAccount, except the control plane Deployment: it creates the sandbox pods and their NetworkPolicies, so it needs its token. It is also the only pod allowed to reach the Kubernetes API (eai-deny-kube-apiserver).
Documented GPU exceptions
| Exception | Workload | Justification |
|---|---|---|
emptyDir medium: Memory on /dev/shm | vLLM | NCCL and tensor parallelism exchange through shared memory; the size is bounded (sizeLimit) |
| model cache PVC | vLLM | weights preloaded, HF_HUB_OFFLINE=1, no download at runtime |
eai-gpu namespace at baseline | third-party GPU images | some vendor images (model servers, CUDA based images such as dcgm-exporter) run as UID 0 and cannot declare runAsNonRoot, which restricted refuses. baseline still forbids privileged containers, hostPath, host namespaces, hostPort and added dangerous capabilities. audit and warn stay at restricted |
gpu-operator namespace at privileged | NVIDIA operator | the driver, toolkit and device plugin install the kernel module and expose /dev/nvidia*; this namespace runs no platform code |
The chart vLLM and worker pods keep the full restricted context; test_platform_security_manifests.py rejects any other exception.
Pod Security Admission
deploy/cilium/namespaces.yaml (synced by Argo CD with deploy/cilium) labels the namespaces: pod-security.kubernetes.io/enforce=restricted for enterprise-ai, eai-data, eai-security, openbao, apisix; the sandbox namespace (eai-sandbox) is created by the chart at restricted.
Kyverno policies
deploy/policies/kyverno/pod-network-security.yaml, in Enforce mode:
| Policy | Rules |
|---|---|
eai-pod-security | drop-all-capabilities, disallow-added-capabilities (never NET_RAW, only NET_BIND_SERVICE tolerated), require-seccomp, disallow-privileged, disallow-host-namespaces, disallow-host-path, disallow-host-ports |
eai-service-account-tokens | a pod on the default ServiceAccount must set automountServiceAccountToken: false |
eai-image-provenance | outside the Harbor eai and mirror projects (verified by cosign in cluster-policies.yaml and pinned by mutateDigest), an image must be referenced by digest |
eai-restrict-service-exposure | no externalIPs (CVE-2020-8554), no NodePort outside ingress and apisix |
These policies complement cluster-policies.yaml (signatures, non root, read only root filesystem, limits, labels). Test cases live in deploy/policies/kyverno/tests:
kyverno test deploy/policies/kyverno/tests
helm template eai deploy/helm/enterprise-ai -f deploy/helm/enterprise-ai/values-onprem-gpu.yaml > /tmp/r.yaml
kyverno apply deploy/policies/kyverno/pod-network-security.yaml --resource /tmp/r.yaml