Skip to main content
This page covers sandbox security posture and how to configure it via the API.

Non-root execution

  • pod_non_root (boolean, default false): Run the Pod as non-root (UID/GID/FSGroup 65532). Applies pod-wide filesystem ownership.
  • container_non_root (boolean, default false): Run the main container as non-root (UID 65532) and disallow privilege escalation.
Guidance:
  • Enable both flags for consistent non-root behavior and fewer permission surprises when writing to volumes.
  • Some package managers (e.g., Alpine apk add) require root. To run apk add inside the container, you have options:
    • Use before_script with a base image that already includes needed tools, or
    • Temporarily run the main container with root by leaving container_non_root disabled for setup, or
    • Build a custom image with dependencies pre-installed (recommended for production reproducibility).
Example (non-root):
Example (install packages first as root, then lock down egress):

Linux capabilities

Default policy: drop ALL capabilities. Add back only what you need. If you specify cap_drop explicitly, you override the default; to keep drop ALL and add back minimal caps, leave cap_drop unset and only use cap_add.
  • cap_drop (string[]): Capabilities to drop. If omitted, ALL is dropped by default.
  • cap_add (string[]): Capabilities to add back.
  • allow_privilege_escalation: always set to false.
  • Seccomp profile: RuntimeDefault.
Examples: Minimal add-back while still dropping ALL by default:
Override drop policy (not recommended unless you know why):

Common capability requirements

When you encounter permission errors in before_script or during container execution, you may need to add specific capabilities. Here are common use cases: Package managers (apt-get, yum, dnf):
  • SETUID/SETGID: Required for package managers to drop privileges during installation
  • CHOWN: Needed for changing file ownership during package installation
  • DAC_OVERRIDE: Allows bypassing file permission checks (needed for installing packages)
Alpine package manager (apk):
File operations requiring ownership changes:
Network operations (raw sockets, packet capture):
Adding NET_RAW or NET_ADMIN significantly reduces isolation. Only use when absolutely necessary for network debugging or specialized tools. Best practice: pre-build custom images with dependencies installed rather than installing packages at runtime. This improves security, reproducibility, and startup time.

Network isolation and egress lockdown

Ingress isolation (Default: Enabled)

All inter-VM communication is blocked by default to prevent sandbox-to-sandbox access. This provides strong isolation between different sandboxes running in the same cluster. Key points:
  • Ingress blocking: VM sandboxes cannot communicate with each other by default
  • Administrative access preserved: kubectl exec and k7 shell still work normally (they use the Kubernetes API, not pod networking)
  • System services allowed: Traffic from kube-system namespace is permitted for cluster functionality
  • No configuration needed: This security feature is enabled by default for all sandboxes

Egress lockdown and whitelisting

Use egress_whitelist to control outbound traffic. The policy is applied after the container becomes Ready so before_script runs with open egress. Behavior:
  • Omit egress_whitelist: egress open (external internet allowed).
  • []: full egress block (no DNS resolution; no outbound IPs).
  • ["CIDR", ...]: allow only listed CIDR blocks; DNS is blocked.
Examples: Full isolation (no inter-VM communication, no external access):
Partial isolation (no inter-VM communication, but external internet allowed):
Whitelist specific external services (avoid public DNS resolvers):
Network Policy Details:
  • Ingress: Blocked by default (inter-VM isolation) - system services and kubectl exec still work
  • DNS: When egress is locked down, DNS resolution is blocked by default (no CoreDNS exception)
  • Administrative access: kubectl exec, k7 shell, and API operations bypass network policies
Do not whitelist public DNS resolver IPs (e.g., 1.1.1.1, 8.8.8.8). A CIDR allowlist has no L7/port filter, so those IPs re-enable outbound DNS (UDP/TCP 53) and DNS-over-HTTPS (443) and can be used for exfiltration. Prefer your own egress proxy IP, or use FQDN allowlists. Cilium is the default CNI, so egress_whitelist: ["api.openai.com", "*.huggingface.co"] works without extra setup. See Networking.

Mitigations when DNS is blocked

  • Use IP/CIDR whitelisting only (no domains post-lockdown)
  • Pre-resolve/fetch in before_script (runs before lockdown with open egress)
  • If you must allow DNS temporarily, consider an operational override at cluster level (not provided by K7 config)

API key namespace scope

k7 generate-api-key NAME -n team-a stores an optional namespaces list on the key. The API enforces it on every namespace-bearing endpoint:
  • Listed namespaces only — another namespace returns 403 Forbidden.
  • All-namespaces list / GC (namespace omitted or all_namespaces=true) is denied for scoped keys.
  • Keys without a scope keep full cross-namespace access.

Image registry allowlist (SSRF)

When the control plane inspects a sandbox image (entrypoint/cmd resolution), the registry host is resolved before any fetch. Hosts must be on the allowlist (registry-1.docker.io, ghcr.io, quay.io, public.ecr.aws, plus K7_REGISTRY_ALLOWLIST) and every A/AAAA must be a public unicast address. Loopback, private, link-local, metadata, and reserved ranges are rejected. Redirects are not followed.