PAIPAI

Sandbox operations dashboard

Add a private dashboard to inspect live sandboxes, runtime logs and workspace files.

The optional dashboard shows sandbox allocation and readiness, requested CPU and memory, Kubernetes events, container logs and workspace files. It runs as one small Pod in your existing sandbox cluster. Viewing a sandbox does not create one or extend its lifetime.

PAI owns the dashboard source, published image, immutable version, Deployment, Service, service account and namespace-scoped Kubernetes permissions. Your infrastructure owns the cluster, resource sizing, authentication and any external routing. There is no additional cluster, database or public load balancer in the dashboard installation.

Enable the dashboard

First prepare a compatible cluster and runtime using the self-hosting guide. Add dashboard to the same Terraform module call that installs your runtimes:

module "sandbox" {
  source        = "./path-to-installed-package/terraform"
  runtime_image = var.runtime_image
  applications  = var.sandbox_applications

  dashboard = {
    enabled = true
  }
}

Review and apply the plan through your normal deployment workflow. PAI publishes the dashboard image publicly and pins its immutable digest in the module. There is no image input, override or consumer build step. The cluster needs network access to the registry; no image-pull credentials or organization membership are required. Public image distribution does not expose your running dashboard. Upgrading the module selects the dashboard version that accompanies it. Omitting dashboard, or setting enabled = false, installs no dashboard resources.

With the default module name, connect using your administrator kubeconfig:

kubectl --context my-established-sandbox-cluster -n pai-sandbox-dashboard \
  port-forward service/dashboard 8080:8080

Open http://127.0.0.1:8080. The module's dashboard output supplies { namespace, service, port } when enabled and is null otherwise.

Configure access and resources

The dashboard is an administrative view of every application namespace in this module. It has no built-in end-user authentication. Its Service is private, and pod-network ingress is denied by default. For ongoing access through your own authenticated proxy, admit that proxy explicitly:

dashboard = {
  enabled       = true
  namespace     = "sandbox-operations"
  allowed_hosts = ["dashboard.example.com"]
  allow_from = [{
    namespace  = "gateway"
    pod_labels = { app = "authenticated-proxy" }
  }]
  resources = {
    requests = { cpu = "250m", memory = "512Mi", "ephemeral-storage" = "1Gi" }
    limits   = { memory = "512Mi", "ephemeral-storage" = "1Gi" }
  }
}

allow_from also accepts a reviewed CIDR for an external caller, using the same peer shape as application daemon callers. Authentication and any ingress or load-balancer charges remain with the consumer.

allowed_hosts names the hostnames used to reach your proxy. Preserve the browser's Host header when forwarding requests. Supply exact hostnames without schemes, ports or wildcards; localhost, 127.0.0.1 and [::1] are always allowed for administrator port-forwarding. Host validation protects that local access path from DNS rebinding; it does not authenticate users.

The default requests are 100m CPU, 256Mi memory and 1Gi ephemeral storage. Memory and storage have matching limits; CPU has no limit so it can burst. Supplied requests and limits maps replace their respective defaults. GKE Autopilot may raise admitted requests to its supported minimums. One Pod stays running while enabled, including when no browser is connected. An image update briefly interrupts access while that Pod is replaced.

The cluster controls scheduling tolerations; the module does not select a CPU architecture. Terraform preserves tolerations added by admission and GKE's cloud.google.com/neg Service annotation, which GKE can inject automatically. Image, resource, security and Service configuration remain managed by the module. These narrow ownership rules prevent the perpetual admission diff described in Google's Terraform quickstart and retain the GKE-managed NEG annotation.

What the view tells you

The browser polls while the page is visible and retains up to one hour of observations in memory. Refresh starts a new chart; gaps mean the browser did not observe the cluster during that period. Resource figures are configured requests, not measured CPU utilization or billing data.

Workspace inspection reads files through the existing runtime daemon. It does not adopt a sandbox handle or send keepalive requests, so a sandbox may expire while you are viewing it. Container logs are runtime logs, not a transcript of every command an agent executed. Commands normally return their output directly to the application that called them.

The dashboard's Kubernetes identity can only read the listed resource kinds in its configured namespaces. It cannot read Secrets, exec into Pods or mutate claims. Its application exposes GET inspection endpoints only. However, admitting the dashboard to the daemon REST listener grants network access to a protocol that also supports writes; this is a trusted administrative connection, not a daemon-enforced read-only credential.

That allowance is a separate NetworkPolicy selecting the dashboard namespace and pod labels. It does not change application allow_from inheritance or replacement. Dashboard outbound traffic remains allowed; consumers may apply cluster-specific egress controls that retain access to the Kubernetes API and runtime REST listener on TCP 8080.

Disabling the dashboard removes its Pod, Service, identity, Kubernetes grants and runtime network allowances. Application namespaces and sandboxes remain. The observer boundary is recorded in ADR 0060 and PAI's image distribution ownership in ADR 0061.

On this page