Skip to content

feat: security fixes, GKE/AKS support, telemetry, dashboard improvements - #13

Merged
atharvaunde merged 19 commits into
mainfrom
development
Jun 15, 2026
Merged

feat: security fixes, GKE/AKS support, telemetry, dashboard improvements#13
atharvaunde merged 19 commits into
mainfrom
development

Conversation

@atharvaunde

Copy link
Copy Markdown
Contributor

What's in this PR

This brings development up to date with main, covering four areas of work shipped since the last merge.


Security fixes

Three vulnerabilities identified in a security review and patched:

  • SSRF — cluster connect & upload routes: apiEndpoint from the POST body and kubeconfig server fields from uploaded files were passed directly to the Kubernetes client without being checked against the existing isBlockedServerUrl blocklist. An attacker could supply http://169.254.169.254 to hit the cloud instance metadata endpoint. Fixed by calling isBlockedServerUrl in both connect/route.jsx and upload/route.jsx before any outbound connection is made.

  • Arbitrary file read — kubeconfig cert paths: fileToBase64 in lib/k8s/client.js called readFileSync on file paths taken directly from user-supplied kubeconfigs (the certificate-authority, client-certificate, and client-key fields). A crafted kubeconfig could read any file accessible to the Node.js process and return its contents in the API response. Fixed by restricting reads to an allowlist of legitimate cert directories (~/.kube/, /etc/kubernetes/, /var/lib/kubelet/).

  • SSRF — request header forwarding: getClientsFromRequest forwarded x-cluster-server to the Kubernetes client without a blocklist check, meaning all ~15 API proxy routes were unprotected. isBlockedServerUrl was only being called in 2 of those routes. Fixed by moving the check into getClientsFromRequest itself so protection is applied centrally and can't be missed on new routes.


GKE and AKS compatibility

  • GKE exec auth: serializeKubeConfig now resolves exec-based tokens (e.g. gke-gcloud-auth-plugin) via applyToFetchOptions after validateConnection warms the cache, then extracts the resolved Bearer token for header forwarding.
  • Docker TLS / AKS: caFile, certFile, and keyFile paths are now inlined as base64 at serialize time so TLS credentials are not lost when forwarded via request headers.
  • Parallel context safety: isolateContext clones a single-context KubeConfig from a shared multi-context one. The upload and auto-detect routes now use it instead of calling setCurrentContext on a shared object across parallel Promise.all branches, which was corrupting Docker TLS state mid-flight.

Anonymous telemetry

  • Payload: app version, cluster count, provider types, k8s versions, namespace counts — no names or identifiable data.
  • Anti-abuse: HMAC-SHA256 signing + SHA256 proof-of-work (difficulty 16).
  • Scheduling: fires once per hour from AppShell, covers all pages without duplicating pings.
  • Privacy: disabled by default (TELEMETRY_DISABLED=true); opt-out via env var. NEXT_TELEMETRY_DISABLED=1 also set.
  • Settings → About shows enabled status, install ID, last ping time, and last payload.
  • Docker build: TELEMETRY_HMAC_SECRET, TELEMETRY_ENDPOINT, and TELEMETRY_POW_DIFFICULTY passed as build-args from GitHub Actions secrets.

Dashboard & workload improvements

  • KPI and topology cards are now clickable with redirects to the relevant listing page.
  • Cluster Health Report dialog updated to a two-column layout with a collapsible score breakdown.
  • Deployment detail: removed revision/replica/pods cards; added a Logs tab with pod and container selectors, tail/since filters, search, and live mode.
  • All workload pages (DaemonSets, StatefulSets, Jobs, ReplicaSets, ReplicationControllers) migrated to SharedLogsTab.
  • DaemonSet list columns now match the Deployment style.
  • Pod detail: logs viewport fits within viewport height; Resources tab uses shadcn Table with CPU/memory columns; DNS Policy formatted via formatLabel; memory displayed in GB.
  • Appearance tab: non-functional table density and navigation style sections hidden.
  • Cost estimation disabled by default; developer mode enabled by default.

Build & config

  • App version sourced from package.json at build time via NEXT_PUBLIC_APP_VERSION — Settings → About always shows the correct version without manual updates.
  • GitHub link in Settings → About corrected to https://github.com/CodeScapes-dev/k8lens-app.
  • Dockerfile: build warnings resolved; TELEMETRY_HMAC_SECRET restored as a build-arg with # check=skip directives for intentional inline secret baking.
  • Next.js bumped to 16.2.9, lucide-react to 1.18.0, shadcn to v4.11.0.
  • CONTRIBUTING.md added with setup, branch workflow, PR conventions, and telemetry env var documentation.

…S policy formatting, memory in GB

- Logs tab fits within viewport height without page scroll
- Resources tab uses shadcn Table with CPU/memory columns
- DNS Policy uses formatLabel() in Overview and Networking tabs
- formatMemory canonical in lib/k8s/utils, re-exported from dashboard utils
- Header stats renamed to CPU Req / Mem Req
…s tab with pod selector

- Remove Revision quick stat from header
- Apply formatLabel to Strategy in header and Overview info panel
- Remove Replica Status and Pods panels from Overview tab
- Add Logs tab: pod selector + container selector, tail/since filters, search, live mode
- Collect app version, cluster count, provider types, k8s versions
- 3h ping interval via instrumentation.js startup hook + dashboard re-trigger
- HMAC-SHA256 signed + SHA256 proof-of-work (difficulty 16) for anti-forgery
- Telemetry endpoint and secret baked at Docker build time via ARGs
- TELEMETRY_DISABLED=true env var for honest opt-out
- Settings → About tab shows enabled status, install ID, last ping, last payload
- GitHub Actions passes secrets as Docker build-args
- serializeKubeConfig: resolve exec-based tokens (GKE gke-gcloud-auth-plugin)
  via applyToFetchOptions after validateConnection caches the result
- serializeKubeConfig: normalize caFile/certFile/keyFile to inline base64 so
  file paths are not lost when credentials are forwarded via request headers
- isolateContext: new helper that clones a single-context KubeConfig from a
  shared multi-context one to prevent race conditions in Promise.all
- auto-detect + upload routes: use isolateContext per context instead of
  mutating shared KubeConfig with setCurrentContext across parallel promises;
  the shared object mutation was corrupting Docker TLS state when GKE exec
  auth awaited mid-flight
@atharvaunde
atharvaunde merged commit 9074a1a into main Jun 15, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant