From efa433fe11a829f58ab0a7443f67e996e93e1eeb Mon Sep 17 00:00:00 2001 From: Andrew Anderson Date: Thu, 2 Apr 2026 18:50:20 -0400 Subject: [PATCH 1/2] Add KubeStellar Console security self-assessment Add TAG-Security self-assessment for the KubeStellar Console project following the CNCF template. Includes actors, actions, security functions, secure development practices, and a Data Storage Summary documenting all persistence layers (backend SQLite, metrics history, browser caches, in-memory SSE cache). Signed-off-by: Andrew Anderson --- .../security-assessment/self-assessment.md | 181 ++++++++++++++++++ 1 file changed, 181 insertions(+) create mode 100644 projects/kubestellar/security-assessment/self-assessment.md diff --git a/projects/kubestellar/security-assessment/self-assessment.md b/projects/kubestellar/security-assessment/self-assessment.md new file mode 100644 index 000000000..240bd9d19 --- /dev/null +++ b/projects/kubestellar/security-assessment/self-assessment.md @@ -0,0 +1,181 @@ +# Security Self-Assessment: KubeStellar Console + +This document follows the [CNCF TAG-Security self-assessment template](https://github.com/cncf/tag-security/blob/main/assessments/guide/self-assessment.md). + +## Table of Contents + +- [Metadata](#metadata) +- [Overview](#overview) +- [Self-Assessment Use](#self-assessment-use) +- [Security Functions and Features](#security-functions-and-features) +- [Project Compliance](#project-compliance) +- [Secure Development Practices](#secure-development-practices) +- [Security Issue Resolution](#security-issue-resolution) +- [Appendix](#appendix) + - [Data Storage Summary](#data-storage-summary) + +## Metadata + +| | | +|---|---| +| **Software** | [KubeStellar Console](https://github.com/kubestellar/console) | +| **Security Provider** | No — Console is a user-facing dashboard, not a security tool | +| **Languages** | Go (backend), TypeScript/React (frontend) | +| **SBOM** | Not currently generated; planned via GoReleaser in future releases | + +## Overview + +### Background + +KubeStellar Console is an AI-powered multi-cluster Kubernetes dashboard that provides: + +- **Cluster management** — Visual overview of resources across multiple Kubernetes clusters +- **Guided install missions** — Step-by-step deployment of CNCF projects with pre-flight checks, validation, and rollback +- **AI-assisted operations** — Natural language queries about cluster state via MCP (Model Context Protocol) bridge +- **Real-time monitoring** — WebSocket-powered live event streaming from connected clusters + +### Actors + +| Actor | Description | +|-------|-------------| +| **Console User** | Authenticated (GitHub OAuth) or unauthenticated (demo mode) user accessing the web dashboard | +| **kc-agent** | Local agent running on user's machine that bridges browser to local kubeconfig and MCP servers | +| **AI Provider** | External service (Claude, OpenAI, or Gemini) that processes natural language queries via MCP | +| **Kubernetes API** | Target clusters accessed via kubeconfig contexts | +| **Netlify Functions** | Serverless backend for the hosted console.kubestellar.io deployment | + +### Actions + +| Action | Actor | Description | +|--------|-------|-------------| +| View cluster resources | Console User | Browse pods, deployments, services, events across connected clusters | +| Execute mission | Console User | Run guided install/uninstall missions on target clusters | +| AI chat query | Console User → AI Provider | Ask natural language questions about cluster state | +| Connect clusters | kc-agent | Discover and tunnel local kubeconfig contexts to hosted Console | +| Authenticate | Console User | Sign in via GitHub OAuth 2.0 | + +### Goals + +- Provide secure, authenticated access to Kubernetes cluster information +- Never store or transmit Kubernetes credentials beyond the user's local machine +- Enforce principle of least privilege — Console inherits the user's existing kubeconfig RBAC +- Protect user sessions with short-lived JWT tokens +- Prevent cross-site scripting (XSS) and other web application attacks + +### Non-Goals + +- Console does **not** manage Kubernetes RBAC policies — it inherits existing permissions +- Console does **not** provide network security or service mesh capabilities +- Console does **not** persistently store raw Kubernetes resource data on the server — pods, deployments, and services are fetched on-demand via the Kubernetes API. See [Data Storage Summary](#data-storage-summary) for details on what is persisted. +- Console is **not** a secrets management tool + +## Self-Assessment Use + +This self-assessment is created by the KubeStellar Console maintainers to perform an internal analysis of the project's security. It is intended to assist TAG-Security in their joint assessment and to identify areas for improvement. + +## Security Functions and Features + +### Critical + +| Component | Description | +|-----------|-------------| +| **GitHub OAuth 2.0** | Primary authentication mechanism; no passwords stored | +| **JWT Session Tokens** | Short-lived tokens for session management; validated on every API request | +| **kubeconfig isolation** | Kubernetes credentials never leave the user's machine; kc-agent proxies requests locally | +| **HTTPS transport** | All production traffic encrypted via TLS (Netlify/Ingress termination) | +| **WebSocket authentication** | WebSocket connections require valid JWT before data is transmitted | + +### Security Relevant + +| Component | Description | +|-----------|-------------| +| **Content Security Policy** | HTTP headers restrict script sources and frame embedding | +| **CORS configuration** | API restricts cross-origin requests to known Console origins | +| **Input sanitization** | User inputs (search queries, mission parameters) sanitized before rendering | +| **Dependency scanning** | Dependabot, npm audit, and CodeQL identify vulnerable dependencies | +| **Secret scanning** | GitHub repository-level secret scanning enabled (not yet integrated into CI/CD workflows) | + +## Project Compliance + +KubeStellar Console does not currently hold formal compliance certifications. The project follows: + +- **CNCF Code of Conduct** — Adopted and enforced +- **Apache License 2.0** — CNCF-compatible open-source license +- **DCO (Developer Certificate of Origin)** — Required for all contributions +- **OpenSSF Scorecard** — Automated weekly scoring + +## Secure Development Practices + +### Development Pipeline + +| Practice | Implementation | +|----------|---------------| +| **Static Analysis (Go)** | CodeQL with extended security queries, gosec, nilaway | +| **Static Analysis (TypeScript)** | CodeQL with extended queries, ESLint, TypeScript strict mode null checks | +| **Dependency Management** | Dependabot (Go, npm, GitHub Actions), weekly automated updates | +| **Container Scanning** | Planned — container image vulnerability scanning not yet integrated into CI/CD | +| **Secret Detection** | GitHub repository-level secret scanning enabled; CI/CD integration planned | +| **Code Review** | All changes require PR review; direct commits to main prohibited | +| **Signed Commits** | DCO sign-off required on all commits | +| **Branch Protection** | Main branch protected; CI must pass before merge | + +### Communication Channels + +| Channel | Address | +|---------|---------| +| **Internal (maintainers)** | [kubestellar-dev-private@googlegroups.com](mailto:kubestellar-dev-private@googlegroups.com) | +| **Incoming (users)** | GitHub Issues, [#kubestellar-dev Slack](https://cloud-native.slack.com/channels/kubestellar-dev) | +| **Security Announcements** | [kubestellar-security-announce@googlegroups.com](mailto:kubestellar-security-announce@googlegroups.com) | + +## Security Issue Resolution + +### Responsible Disclosure Process + +Vulnerability reports should be sent to [kubestellar-security-announce@googlegroups.com](mailto:kubestellar-security-announce@googlegroups.com). See [SECURITY.md](https://github.com/kubestellar/console/blob/main/SECURITY.md) for full details. + +### Response Timeline + +| Step | Timeline | +|------|----------| +| **Acknowledgment** | Within 3 working days | +| **Initial Assessment** | Within 5 working days | +| **Patch Development** | Critical: 72 hours; High: 7 days | +| **Public Disclosure** | After patch is available, coordinated with reporter | + +### Incident Response + +The security response team (listed in [SECURITY_CONTACTS](https://github.com/kubestellar/console/blob/main/SECURITY_CONTACTS)) triages all reports. Critical vulnerabilities trigger an immediate patch release; non-critical issues are addressed in the next scheduled release. + +## Appendix + +### Data Storage Summary + +The following table details all data persisted by KubeStellar Console, both server-side and client-side: + +| Storage | Type | What is Stored | Location | Retention | +|---------|------|----------------|----------|-----------| +| **Backend SQLite** | Relational DB | User accounts, dashboard layouts, card configurations, GPU utilization snapshots, revoked JWT tokens, user analytics events, feature requests | Server: `/data/console.db` | Indefinite | +| **Metrics History** | JSON file | Rolling cluster metrics (CPU/memory %, node counts, pod issues, GPU allocation per node) | kc-agent host: `~/.kc/metrics_history.json` | 7 days | +| **Frontend SQLite (OPFS)** | Browser DB | Cached Kubernetes resource data (pods, deployments, services) for performance | Browser OPFS: `/kc-cache.sqlite3` | Until browser cache cleared | +| **Frontend IndexedDB** | Browser DB | Same as OPFS (fallback when OPFS unavailable) | Browser IndexedDB: `kc_cache` | Until browser cache cleared | +| **localStorage** | Browser KV | User preferences, theme, AI settings, UI state | Browser localStorage | Until browser data cleared | +| **In-memory SSE cache** | Process memory | Short-lived Kubernetes API responses | Server memory | 15-second TTL; lost on restart | + +**Key points:** + +- Raw Kubernetes resource data (pods, deployments, services) is **not** stored server-side — it is fetched on-demand and cached only in browser storage and a 15-second in-memory server cache. +- Kubernetes **credentials** never leave the user's machine — the kc-agent proxies requests locally. +- The backend SQLite database stores user preferences and dashboard configuration, plus GPU utilization snapshots for historical trend analysis. +- The kc-agent's metrics history file (`~/.kc/metrics_history.json`) stores 7 days of aggregated cluster health metrics on the user's local machine for AI-assisted trend analysis. + +### Known Issues and Areas for Improvement + +1. **AI provider data flow** — Queries sent to external AI providers (Claude, OpenAI, Gemini) may include cluster resource names and metadata. Users should be aware that AI chat queries are processed by third-party services. +2. **Demo mode** — Unauthenticated demo mode uses synthetic data only; no cluster access is possible without authentication. +3. **kc-agent trust model** — The kc-agent runs with the user's local permissions. A compromised kc-agent could access any cluster the user has kubeconfig access to. This is mitigated by the agent running locally (not as a network service). + +### Related Security Documentation + +- [SECURITY.md](https://github.com/kubestellar/console/blob/main/SECURITY.md) — Vulnerability reporting process +- [SECURITY_CONTACTS](https://github.com/kubestellar/console/blob/main/SECURITY_CONTACTS) — Security response team +- [HARDCODED_URLS.md](https://github.com/kubestellar/console/blob/main/docs/security/HARDCODED_URLS.md) — Explanation of intentional hardcoded URLs From a9409e34d537c8d4921f230aadef2a00b34ec53a Mon Sep 17 00:00:00 2001 From: Andrew Anderson Date: Thu, 2 Apr 2026 20:17:13 -0400 Subject: [PATCH 2/2] =?UTF-8?q?=F0=9F=93=96=20Address=20TAG-Security=20rev?= =?UTF-8?q?iew:=20scope,=20JWT=20details,=20architecture=20diagram?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Addresses review comments from @JustinCappos and @brandtkeller: - Add scope statement: this covers kubestellar/console only, not KubeStellar Core - Replace vague "secure" with specific mechanisms (HTTPS, OAuth, JWT validation) - Add deployment architecture diagram showing data flow in both modes - Detail kubeconfig isolation: kc-agent binds 127.0.0.1, only JSON crosses network - Explain RBAC inheritance: no ServiceAccount/ClusterRole created, kubectl uses user's kubeconfig as-is, no privilege escalation possible - Expand JWT section: HS256-only via WithValidMethods, none alg rejected, secret management (crypto/rand dev, required env prod), HttpOnly+Secure+SameSite cookies, two-tier JTI revocation, 7-day lifetime with 50% refresh - Add GitHub Security Advisories as primary disclosure channel - Add post-build safety checks and post-merge Playwright verification to practices - Document kc-agent localhost-only kubeconfig import endpoints Signed-off-by: Andrew Anderson --- .../security-assessment/self-assessment.md | 84 ++++++++++++++++--- 1 file changed, 71 insertions(+), 13 deletions(-) diff --git a/projects/kubestellar/security-assessment/self-assessment.md b/projects/kubestellar/security-assessment/self-assessment.md index 240bd9d19..78c474451 100644 --- a/projects/kubestellar/security-assessment/self-assessment.md +++ b/projects/kubestellar/security-assessment/self-assessment.md @@ -2,6 +2,8 @@ This document follows the [CNCF TAG-Security self-assessment template](https://github.com/cncf/tag-security/blob/main/assessments/guide/self-assessment.md). +> **Scope:** This assessment covers **[kubestellar/console](https://github.com/kubestellar/console)** only — the multi-cluster Kubernetes dashboard and its local agent (`kc-agent`). It does **not** cover [KubeStellar Core](https://github.com/kubestellar/kubestellar), the multi-cluster orchestration control plane. Console is a standalone project that connects to any Kubernetes cluster via standard kubeconfig; it does not depend on KubeStellar Core to function. + ## Table of Contents - [Metadata](#metadata) @@ -12,6 +14,7 @@ This document follows the [CNCF TAG-Security self-assessment template](https://g - [Secure Development Practices](#secure-development-practices) - [Security Issue Resolution](#security-issue-resolution) - [Appendix](#appendix) + - [Deployment Architecture](#deployment-architecture) - [Data Storage Summary](#data-storage-summary) ## Metadata @@ -56,10 +59,10 @@ KubeStellar Console is an AI-powered multi-cluster Kubernetes dashboard that pro ### Goals -- Provide secure, authenticated access to Kubernetes cluster information -- Never store or transmit Kubernetes credentials beyond the user's local machine -- Enforce principle of least privilege — Console inherits the user's existing kubeconfig RBAC -- Protect user sessions with short-lived JWT tokens +- Provide authenticated access to Kubernetes cluster information over HTTPS (TLS 1.2+ enforced by Netlify for the hosted deployment; user-configured TLS for self-hosted). All API endpoints except `/health` and demo-mode routes require a valid JWT session token. +- Never store or transmit Kubernetes credentials to the server. In the hosted deployment (`console.kubestellar.io`), `kc-agent` runs on the user's local machine, reads `~/.kube/config` locally, executes `kubectl` commands locally, and returns only JSON-serialized resource data (pods, deployments, events, etc.) to the Console backend via an authenticated WebSocket tunnel. The kubeconfig file contents — including certificates, tokens, and private keys — never leave the user's machine. See [Deployment Architecture](#deployment-architecture) for a diagram of both hosted and self-hosted data flows. +- Enforce principle of least privilege by inheriting the user's existing Kubernetes RBAC. Console does not create its own ServiceAccount, ClusterRole, or any Kubernetes RBAC objects. The `kc-agent` executes `kubectl` using whatever kubeconfig contexts the user has configured. If a user's kubeconfig grants only `get` access to pods in namespace `default`, Console can only display those pods — it cannot escalate privileges. The Console backend itself has no Kubernetes credentials; it is exactly as privileged as the user's kubeconfig, no more. +- Protect user sessions with JWT tokens validated on every API request - Prevent cross-site scripting (XSS) and other web application attacks ### Non-Goals @@ -79,11 +82,11 @@ This self-assessment is created by the KubeStellar Console maintainers to perfor | Component | Description | |-----------|-------------| -| **GitHub OAuth 2.0** | Primary authentication mechanism; no passwords stored | -| **JWT Session Tokens** | Short-lived tokens for session management; validated on every API request | -| **kubeconfig isolation** | Kubernetes credentials never leave the user's machine; kc-agent proxies requests locally | -| **HTTPS transport** | All production traffic encrypted via TLS (Netlify/Ingress termination) | -| **WebSocket authentication** | WebSocket connections require valid JWT before data is transmitted | +| **GitHub OAuth 2.0** | Primary authentication mechanism; no passwords stored. OAuth scope is limited to `user:email` ([`auth.go:179`](https://github.com/kubestellar/console/blob/main/pkg/api/handlers/auth.go#L179)). Server-side state tokens with 10-minute expiry prevent CSRF during the OAuth redirect flow. | +| **JWT Session Tokens** | Session tokens signed with HMAC-SHA256 (HS256). Algorithm enforcement: the JWT parser accepts **only** HS256 via `jwt.WithValidMethods([]string{"HS256"})` ([`auth.go:36`](https://github.com/kubestellar/console/blob/main/pkg/api/middleware/auth.go#L36)), preventing algorithm confusion attacks. The `none` algorithm and all non-HMAC methods are rejected at parse time. Defense-in-depth: the keyfunc additionally verifies the token's signing method is `*jwt.SigningMethodHMAC` before returning the secret. **Secret management:** In production, the JWT secret must be provided via the `JWT_SECRET` environment variable — the server refuses to start without it ([`server.go:170`](https://github.com/kubestellar/console/blob/main/pkg/api/server.go#L170)). In development mode, a 32-byte (256-bit) cryptographically random secret is generated per server startup via `crypto/rand.Read()`. **Token lifetime:** 7 days (168 hours) with automatic silent refresh when 50% of the lifetime has elapsed. **Storage:** JWT is stored in an HttpOnly cookie (`kc_auth`) with `SameSite=Lax` for CSRF protection. The `Secure` flag is set when the deployment URL uses HTTPS (always true for the hosted deployment; conditional for local development on `http://localhost`). The JWT is not included in URL query parameters or redirect URLs. **Revocation:** Two-tier revocation system using JTI (JWT ID) claims — an in-memory cache for fast lookups backed by persistent SQLite storage that survives server restarts. Tokens are revoked on explicit logout and on refresh (old token revoked before new token issued). | +| **kubeconfig isolation** | Kubernetes credentials never leave the user's machine. See [Deployment Architecture](#deployment-architecture) for details. | +| **HTTPS transport** | All production traffic encrypted via TLS. Hosted deployment uses Netlify's automatic TLS (1.2+). Self-hosted deployments use user-configured TLS termination (ingress controller or reverse proxy). | +| **WebSocket authentication** | Hub WebSocket connections use first-message authentication: the client must send a `{"type":"auth","token":"..."}` JSON message within 5 seconds of connection. The token is validated via the same `ParseJWT` function used by HTTP routes (HS256-only, revocation-checked). Connections idle for more than 90 seconds are terminated. Server-side ping/pong keepalive runs every 30 seconds. | ### Security Relevant @@ -93,7 +96,7 @@ This self-assessment is created by the KubeStellar Console maintainers to perfor | **CORS configuration** | API restricts cross-origin requests to known Console origins | | **Input sanitization** | User inputs (search queries, mission parameters) sanitized before rendering | | **Dependency scanning** | Dependabot, npm audit, and CodeQL identify vulnerable dependencies | -| **Secret scanning** | GitHub repository-level secret scanning enabled (not yet integrated into CI/CD workflows) | +| **Post-build safety checks** | Automated post-build verification scans production bundles for Vite define corruption, missing critical chunks, MSW leakage, and bundle size regressions | ## Project Compliance @@ -118,6 +121,7 @@ KubeStellar Console does not currently hold formal compliance certifications. Th | **Code Review** | All changes require PR review; direct commits to main prohibited | | **Signed Commits** | DCO sign-off required on all commits | | **Branch Protection** | Main branch protected; CI must pass before merge | +| **Post-Merge Verification** | Automated Playwright E2E tests run against the deployed production site after each merge, targeted by issue labels and changed file paths | ### Communication Channels @@ -131,7 +135,7 @@ KubeStellar Console does not currently hold formal compliance certifications. Th ### Responsible Disclosure Process -Vulnerability reports should be sent to [kubestellar-security-announce@googlegroups.com](mailto:kubestellar-security-announce@googlegroups.com). See [SECURITY.md](https://github.com/kubestellar/console/blob/main/SECURITY.md) for full details. +Vulnerability reports should be submitted via [GitHub Security Advisories](https://github.com/kubestellar/console/security/advisories) (preferred) or sent to [kubestellar-security-announce@googlegroups.com](mailto:kubestellar-security-announce@googlegroups.com). See [SECURITY.md](https://github.com/kubestellar/console/blob/main/SECURITY.md) for full details. ### Response Timeline @@ -148,6 +152,60 @@ The security response team (listed in [SECURITY_CONTACTS](https://github.com/kub ## Appendix +### Deployment Architecture + +KubeStellar Console supports two deployment modes with different security boundaries: + +``` +Hosted Mode (console.kubestellar.io) +════════════════════════════════════ + + User's Local Machine Netlify CDN + ┌─────────────────────────────┐ ┌───────────────────────┐ + │ kc-agent (127.0.0.1:8585) │ WebSocket │ Console Frontend │ + │ ┌─────────────────────────┐│ (wss://) │ (React SPA) │ + │ │ Reads ~/.kube/config ││◄────────────►│ │ + │ │ Executes kubectl ││ JSON only: │ Netlify Functions │ + │ │ locally ││ pods, svcs, │ (serverless backend) │ + │ └───────────┬─────────────┘│ events, └───────────────────────┘ + │ │ │ deployments ▲ + │ ▼ │ │ HTTPS + │ ┌─────────────────────────┐│ │ + │ │ Kubernetes Clusters ││ ┌────────┴──────────────┐ + │ │ (via kubeconfig RBAC) ││ │ User's Browser │ + │ └─────────────────────────┘│ │ (dashboard UI) │ + └─────────────────────────────┘ └───────────────────────┘ + + ▲ kubeconfig credentials NEVER Only JSON resource data + cross this boundary crosses the network + + +Self-Hosted Mode (localhost:8080) +════════════════════════════════ + + ┌───────────────────────────────────────────────────┐ + │ Single Machine / Pod │ + │ ┌──────────────────────┐ ┌────────────────────┐ │ + │ │ Go Backend (:8080) │ │ kc-agent │ │ + │ │ REST API + WebSocket │◄►│ kubectl + MCP │ │ + │ │ OAuth + JWT Auth │ │ reads kubeconfig │ │ + │ └──────────────────────┘ └─────────┬──────────┘ │ + │ │ │ + │ ┌─────────▼───────────┐ │ + │ │ Kubernetes API │ │ + │ │ (user's RBAC) │ │ + │ └─────────────────────┘ │ + └───────────────────────────────────────────────────┘ + kubeconfig stays on this machine in both modes +``` + +**Key security properties:** + +- **kc-agent binds to `127.0.0.1` only** ([`server.go:466`](https://github.com/kubestellar/console/blob/main/pkg/agent/server.go#L466)) — it is not accessible from the network. +- **In hosted mode**, the WebSocket tunnel between kc-agent and the Console backend carries only JSON-serialized Kubernetes resource data (pod specs, deployment status, event lists, etc.). Kubeconfig file contents — including certificates, bearer tokens, and private keys — are never transmitted. +- **In self-hosted mode**, the Go backend and kc-agent run on the same machine. The backend reads kubeconfig via the standard `client-go` library (`clientcmd.LoadFromFile`). No credentials leave the host. +- **kc-agent does expose localhost-only endpoints** (`/kubeconfig/import`, `/kubeconfig/preview`) that accept kubeconfig YAML for importing new cluster contexts. These are bound to `127.0.0.1:8585` and are not reachable from the hosted Console or any external network. + ### Data Storage Summary The following table details all data persisted by KubeStellar Console, both server-side and client-side: @@ -170,9 +228,9 @@ The following table details all data persisted by KubeStellar Console, both serv ### Known Issues and Areas for Improvement -1. **AI provider data flow** — Queries sent to external AI providers (Claude, OpenAI, Gemini) may include cluster resource names and metadata. Users should be aware that AI chat queries are processed by third-party services. +1. **AI provider data flow** — Queries sent to external AI providers (Claude, OpenAI, Gemini) may include cluster resource names and metadata (namespace names, pod names, event messages). Users should be aware that AI chat queries are processed by third-party services subject to those providers' data handling policies. 2. **Demo mode** — Unauthenticated demo mode uses synthetic data only; no cluster access is possible without authentication. -3. **kc-agent trust model** — The kc-agent runs with the user's local permissions. A compromised kc-agent could access any cluster the user has kubeconfig access to. This is mitigated by the agent running locally (not as a network service). +3. **kc-agent trust model** — The kc-agent runs with the user's local permissions. A compromised kc-agent could access any cluster the user has kubeconfig access to. This is mitigated by the agent binding to `127.0.0.1` only (not accessible from the network) and running as a user-space process (not a privileged daemon). ### Related Security Documentation