Kite (Kubernetes dashboard)
Not to be confused with the Zerodha Kite MCP server (
k8s/zerodha-kite), an unrelated trading-API server. This page is thekite-org/kiteKubernetes dashboard.
Kite is a modern Kubernetes dashboard. It gives a web view of the cluster resources, live logs, a web terminal, and a kubectl console. Kite runs on the k3s cluster under k8s/kite/.
Kite has full control of the cluster. Its ServiceAccount uses a ["*"] ClusterRole. A user who signs in can create, change, and delete every resource. For this reason Kite gates itself with GitHub OAuth. Only the mapped GitHub user gets in. The public host therefore does not need a Cloudflare Access gate in front, unlike the auth-less tools (esphome, ledger, onvif-console).
Architecture
flowchart TB
user[Browser] -->|"kite.rithviknishad.dev"| tunnel[cloudflared]
tunnel --> traefik[Traefik :80]
traefik --> kite[kite :8080]
kite -->|GitHub OAuth| github[github.com]
kite -->|in-cluster ServiceAccount| api[k3s API server]
kite --> pvc[PVC kite-data 1Gi - SQLite]
| Component | Value | Role |
|---|---|---|
kite Deployment | ghcr.io/kite-org/kite:latest | Dashboard server on :8080 |
kite ServiceAccount | ["*"] ClusterRole | Full cluster access |
kite-config ConfigMap | config.yaml | Declarative OAuth, RBAC, and super user |
kite-secret Secret | sops | Keys, GitHub OAuth app, break-glass password |
kite-data PVC | 1 Gi, local-path | SQLite database (/data/kite.db) |
Key decisions:
- The configuration is declarative. The
KITE_CONFIG_FILEenvironment variable points at the mountedconfig.yaml. Kite writes this file into its SQLite database on every startup. The OAuth and RBAC sections become read-only in the user interface. To change them, edit the ConfigMap ink8s/kite/kite.yamland deploy again. - Secrets stay out of the committed file. Kite expands
${VAR}placeholders inconfig.yamlfrom the pod environment. The GitHub client id and secret, and the break-glass password, come from the sops-backedkite-secret. - Single writer. The Deployment uses a
Recreatestrategy on one ReadWriteOnce PVC. Two pods cannot mount the SQLite volume at the same time. - One cluster for now. Kite uses the in-cluster ServiceAccount to reach avocado’s own k3s. Multi-cluster support comes later.
Authentication (GitHub OAuth)
Kite uses a GitHub OAuth app for login. A new login has no permissions until RBAC maps it to a role. The config.yaml maps the GitHub user rithviknishad to the built-in admin role. GitHub OAuth apps do not return groups, so the map uses the username.
Create the GitHub OAuth app
Do these steps one time. They take about two minutes.
- Open https://github.com/settings/developers.
- Select OAuth Apps. Then select New OAuth App.
- In Application name, type a name. For example, type
Kite avocado. - In Homepage URL, type
https://kite.rithviknishad.dev. - In Authorization callback URL, type
https://kite.rithviknishad.dev/api/auth/callback. - Select Register application.
- Copy the Client ID.
- Select Generate a new client secret. Then copy the secret value.
The callback URL must match exactly. If the URL is wrong, the login fails.
To change the admin user
Edit the roleMapping block in the kite-config ConfigMap (k8s/kite/kite.yaml). Add the GitHub username to the admin role. Then run just kite-deploy.
Secrets
The kite-secret Secret holds five keys. The real values live sops-encrypted at secrets/kite.enc.yaml. just kite-deploy applies them. This Secret is not part of the kustomize build. See k8s/kite/secret.example.yaml for the shape.
| Key | Purpose |
|---|---|
JWT_SECRET | Signs the Kite session tokens |
KITE_ENCRYPT_KEY | Encrypts sensitive database columns. Keep it stable. |
GITHUB_CLIENT_ID | The GitHub OAuth app client id |
GITHUB_CLIENT_SECRET | The GitHub OAuth app client secret |
KITE_SUPERUSER_PASSWORD | The break-glass admin password |
To set the secret values:
just kite-secrets # opens secrets/kite.enc.yaml in sops
Paste a kite-secret manifest with real values. Generate each random value with openssl rand -hex 32. Save and close the editor.
Keep
KITE_ENCRYPT_KEYstable. If the key changes, Kite cannot read the values that it encrypted before.
Deploy
just kite-deploy # kubectl apply -k k8s/kite + the sops secret, then restart
just kite-status # pods, service, ingress, PVC
just kite-logs # tail the server logs
just kite-deploy applies the manifests, applies the decrypted secret, and restarts the pod. The restart is necessary because the environment from the Secret does not reload on its own.
Exposure
The public host is kite.rithviknishad.dev. To make it live:
- Create the GitHub OAuth app (see above).
- Set the secret values with
just kite-secrets. - Add the route:
cloudflared tunnel route dns avocado kite.rithviknishad.dev. - Deploy the tunnel change:
just deploy(modules/cloudflared.nixalready lists the host). - Deploy Kite:
just kite-deploy.
The Tailnet also reaches Kite. Send the host header over Tailscale:
curl -H 'Host: kite.avocado.local' http://avocado/healthz
Monitoring
Gatus probes https://kite.rithviknishad.dev/healthz in the public group. The /healthz path has no auth, so the probe measures the full public path and the certificate expiry. The GitHub OAuth login sits on the application routes, not on /healthz, so it does not hide a dead backend. See monitoring.
Break-glass login
The config.yaml also creates a super user named admin. Kite always gives the super user the admin role. Use this account if the GitHub OAuth login breaks. The password is KITE_SUPERUSER_PASSWORD in the sops secret. Read it back with just kite-secrets.