admin-guide

Orbit Console administrator guide

Documentation home · User guide

Service model and access

Orbit Console serves a FastAPI backend and browser UI on port 8080. The server loads a registered kubeconfig for each Kubernetes operation. It does not automatically use an in-cluster service account or a mounted default kubeconfig; configurations must be registered in its registry.

The application provides no built-in authentication, user management, per-user registry isolation, or application-level authorisation. All users reaching an instance can select any registered configuration and operate with its credentials. Kubernetes RBAC remains the enforcement point for cluster operations. Treat the console as a shared privileged administration tool.

Place authentication and TLS termination in an upstream proxy or ingress and restrict direct backend access. Protect /api/* and /ws/* as well as the UI. The application currently configures permissive CORS; it is not an access-control boundary. Browser shell traffic uses /ws/object/exec, so the proxy must support WebSocket upgrades, authentication on that path, and suitable session timeouts. The frontend uses root-relative paths and expects to be served at /.

Runtime configuration

Variable Default Effect
ORBIT_CONFIG_DIR /configs Writable registry directory holding kubeconfig files and index.json.
ORBIT_CONFIG_DIR_FALLBACK .local-configs Used if creating the primary directory raises an exception. Relative paths resolve from the process working directory.
CONTEXTS_READONLY false Disables kubeconfig registration and removal in the API and UI. True values are 1, true, yes, on, ignoring case and surrounding whitespace.

These values are read at application startup; restart the process after changing them. CONTEXTS_READONLY does not prevent context selection, patching or deleting Kubernetes resources, reading logs, or opening shells. Use restricted kubeconfig credentials when Kubernetes operations need to be read-only.

Fallback occurs only when creating the primary directory fails. It does not handle later failures to read or write an existing directory. In production, confirm that the intended persistent path is writable and in use: a fallback to container-local storage can make registrations disappear after replacement.

Run locally

Run from the repository root, because static files and templates use relative paths. For a local Python environment:

python3 -m venv .venv
. .venv/bin/activate
python -m pip install fastapi uvicorn kubernetes jinja2 python-multipart websockets
ORBIT_CONFIG_DIR="$PWD/.local-configs" \
  python -m uvicorn app.main:app --host 127.0.0.1 --port 8080

Open http://127.0.0.1:8080 and register a kubeconfig. This installs runtime dependencies for local use; the repository's Dockerfile defines the Alpine package set used for its container build.

To run an approved release from the project's GitLab registry, replace <approved-tag> and the host storage path below:

docker run --rm --name orbit-console \
  -p 127.0.0.1:8080:8080 \
  -e ORBIT_CONFIG_DIR=/configs \
  -v /path/to/persistent/configs:/configs \
  registry.gitlab.com/tak-os-platform/tak-os-containers/orbit-console:<approved-tag>

Ensure the mounted directory is writable by the container's runtime user. The existing test.sh helper builds a local image and mounts .local-configs at /configs; it also mounts a kubeconfig under /root/.kube/config, but that mount does not register it in the application.

Kubernetes and Orbit Deploy

The companion tak-os-orbit-deployments/orbit-console project contains the Orbit Deploy templates. Its deployment README specifies a Global Orbit Deployment in kube-system:

apiVersion: k8s.tlspu.com/v1
kind: OrbitDeployment
metadata:
  name: orbit-console
  namespace: kube-system
spec:
  source: https://gitlab.com/tak-os-platform/tak-os-orbit-deployments/orbit-console.git

The companion templates currently define:

Resource Configuration
Deployment orbit-console One replica; container port 8080; ORBIT_CONFIG_DIR=/configs.
PVC orbit-console-configs 1Gi, ReadWriteOnce, mounted at /configs.
Service orbit-console ClusterIP, port 8080 to container port 8080.
Ingress orbit-console Root path on orbit-console.<domain>, TLS and long proxy timeouts; authentication annotations conditional on the oauth2-proxy Orbit Deployment.
Readiness and liveness HTTP GET /api/health on port 8080.

Review the rendered ingress and verify authentication before exposing it. The templates contain Orbit Deploy substitution and conditional syntax, so they must be rendered by Orbit Deploy before use as ordinary Kubernetes manifests.

Use one application process writing the registry at a time. The registry uses a JSON file with atomic replacement, but has no lock around read-modify-write operations. Multiple writers can lose updates. The companion rolling update allows a surge pod; account for overlapping writers and ReadWriteOnce volume attachment constraints when choosing rollout procedures. A stop-then-start rollout avoids concurrent registry writers at the cost of downtime.

Allow outbound connections from the console to every registered Kubernetes API server, with DNS and certificate validation working from the pod. Browser access to cdn.jsdelivr.net supplies xterm.js 5.3.0, its CSS, and the fit addon 0.8.0. Restricted environments must account for those external terminal assets.

Provision and maintain kubeconfigs

Use kubeconfigs from trusted administrators. They can contain credentials and authentication commands executed by the Kubernetes client on the console server. Prefer self-contained configurations with embedded certificate data where appropriate. Referenced files must exist at paths usable inside the runtime; exec authentication also requires its helper executable and environment there. The base image does not include every cloud provider's authentication tools.

Start with the permissions needed by the intended operators:

Operation Kubernetes access needed
Populate the tree API discovery and list on resource kinds in the selected scope.
Populate namespace choices list on core namespaces.
Read details and owners get on selected resources and their owners.
Read logs get on pods for details/container selection and on pods/log.
Open shell Pod read access and get on pods/exec, matching the client's GET exec connection.
Edit patch on the target resource; optional list on CRDs for schema lookup.
Delete delete on the target resource.
Resolve Orbit Deploy provenance list on orbit-deployments in API group k8s.tlspu.com, in the searched namespaces or across the cluster.

These are operation requirements, not a recommendation to grant all of them. The UI is designed for cluster administrators; limited credentials may produce partial trees, missing namespace choices or incomplete ownership results.

Register configurations through the UI, or POST a JSON object with name and kubeconfig to /api/configs through the authenticated service. Provision approved entries before enabling CONTEXTS_READONLY=true, then restart. The lock rejects registration and removal with HTTP 403; it does not make the filesystem read-only.

Each successful registration creates a separate <config_id>.kubeconfig file and a corresponding entry in index.json, including its contexts and default context. Copying a kubeconfig into /configs alone does not register it. Context names are extracted at registration, so replacing a file directly can leave the index stale; use removal and registration for routine replacement. There is no in-place update endpoint. Register and verify a replacement before removing the old entry when continuity matters.

The application writes kubeconfigs as ordinary files without application-level encryption or explicit restrictive file modes. Restrict directory permissions, control the process umask, and protect the volume and backups as credential stores. A failed registration can leave an unindexed file because the file is written before validation; inspect and remove confirmed orphan files during maintenance. Do not delete files referenced by the index.

Removing a registration deletes its stored file and index entry. Revoke or rotate the underlying credential separately when removing access. Upstream sign-out does not revoke a stored Kubernetes credential.

Backup, restore and upgrades

Back up the entire active registry directory, including index.json and all referenced kubeconfig files. Include any external credential files separately. Record runtime settings, the deployed image tag, and proxy/ingress configuration. The registry backup contains no Kubernetes workload data; back up managed clusters through their own procedures.

For a consistent backup, stop the application or otherwise quiesce registration and removal while taking the copy or volume snapshot. Store it with restricted access and encryption appropriate for cluster credentials.

To restore:

  1. Stop the application and preserve the current registry if present.
  2. Restore the directory contents together, preserving index-to-file relationships.
  3. Set ownership and permissions so the runtime can read and write the directory.
  4. Mount it at ORBIT_CONFIG_DIR and restart with the intended settings.
  5. Check /api/health, list registrations, then test a context with a harmless read operation. Confirm no fallback directory was used.

Before upgrading, back up the registry and record the previous image. Verify the new release using health, persisted registrations, resource browsing and, if required, logs and shell access. The companion Deployment has revisionHistoryLimit: 0, so retain the previous image/configuration explicitly instead of relying on Deployment revision history for rollback. Restore the prior image through the deployment's source configuration if rollback is needed.

Health and troubleshooting

curl --fail http://127.0.0.1:8080/api/health

Expected response: {"status":"ok"}. This is process health only: it does not validate stored credentials, registry writes, Kubernetes connectivity or browser shell access. Uvicorn logs go to the process/container output. No application metrics endpoint or per-user audit trail is implemented; use proxy and Kubernetes audit facilities where needed.

For the companion deployment, these commands inspect state without modifying it:

kubectl -n kube-system get deployment,pods,service,ingress,pvc
kubectl -n kube-system logs deployment/orbit-console
Symptom Investigation
Startup fails Check the working directory, installed dependencies, registry permissions and valid index.json.
Registrations disappear after restart Verify the mounted volume, ORBIT_CONFIG_DIR and whether fallback storage was used.
Kubeconfig registers but cannot connect Registration parses contexts only. Check API endpoint reachability from the runtime, CA data, credentials, external files and exec helpers.
Namespace list or tree is incomplete Check discovery and list permissions. Resource listing exceptions are skipped; namespace-list failures yield no namespace choices.
Browsing takes a long time Discovery lists each eligible resource type, and does not use a watch. Try a specific namespace and inspect API availability and cluster size.
Configuration POST/DELETE returns 403 Check CONTEXTS_READONLY; other object-operation failures may originate in Kubernetes RBAC.
Shell fails Check WebSocket proxying and authentication, browser terminal asset loading, pods/exec access, selected container state and /bin/sh.
Ownership lookup is incomplete Check owner access and discovery. Unknown kinds fall back to heuristic pluralisation. Orbit Deploy lookup also needs its API and list permissions.
Edit fails or has unexpected results Check Kubernetes validation and patch permissions. The generated form is limited; use normal Kubernetes tooling for complex patches.

API reference

FastAPI exposes generated API documentation at /docs and an OpenAPI document at /openapi.json. Protect those routes with the rest of the service. The repository's docs/ directory contains these Markdown guides and is not mounted as web content.

Method Path Purpose
GET /api/health Process health.
GET /api/configs Registrations and contexts_readonly.
POST /api/configs Register { "name": "...", "kubeconfig": "..." }.
DELETE /api/configs/{config_id} Remove a registration and its file.
GET /api/resources/populated Populated kinds and object summaries for scope=ALL, CLUSTER or a namespace.
GET /api/objects List one resource type.
GET /api/object Read a full object.
PATCH /api/object Apply { "object": { ... } } as a merge patch.
DELETE /api/object Delete a Kubernetes object.
GET /api/object/edit-schema CRD schema or a generic fallback.
GET /api/object/owners Owner tree and linear provenance chain.
GET /api/object/logs Plain-text pod logs; tail_lines defaults to 300.
WebSocket /ws/object/exec Interactive pod shell using text input/output.

Cluster operations use config_id and optional context query parameters. Resource operations use api_version and the API resource's plural; single-object operations also require name and a namespace for namespaced objects. Listing supports all_namespaces. Logs and exec use namespace, pod_name, and optional container. Exec's WebSocket route is not included in the generated OpenAPI documentation.