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:8080Open 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.