diff --git a/docs/skills/k0s-sysext-ops.md b/docs/skills/k0s-sysext-ops.md index 7b806f8..e6a0127 100644 --- a/docs/skills/k0s-sysext-ops.md +++ b/docs/skills/k0s-sysext-ops.md @@ -46,6 +46,33 @@ k0s automatically applies all `.yaml` files under `/var/lib/k0s/manifests/argocd k0s kubectl get pods -A ``` +## Configuring KubeStellar Console OAuth and JWT Secret + +By default, the KubeStellar console runs in local development mode without requiring OAuth credentials or a static JWT secret. + +To configure production GitHub OAuth credentials and a persistent JWT signing key, apply an operator-provided Secret to the `kubestellar-console` namespace: + +```bash +cat <<'EOF' | k0s kubectl apply -f - +apiVersion: v1 +kind: Secret +metadata: + name: kubestellar-console-github-oauth + namespace: kubestellar-console +type: Opaque +stringData: + client-id: "" + client-secret: "" + jwt-secret: "" +EOF +``` + +Restart the console deployment to pick up the configured credentials: + +```bash +k0s kubectl rollout restart deployment/kubestellar-console -n kubestellar-console +``` + ## Troubleshooting - **Extension not merged**: Check `systemd-sysext status`. Verify the persistent image is `/var/lib/k0s/k0s.raw`; the boot activation unit copies it into `/run/extensions/k0s.raw`. diff --git a/files/k0s/manifests/kubestellar/01-kubestellar-console-github-oauth.yaml b/files/k0s/manifests/kubestellar/01-kubestellar-console-github-oauth.yaml deleted file mode 100644 index 3e58dc3..0000000 --- a/files/k0s/manifests/kubestellar/01-kubestellar-console-github-oauth.yaml +++ /dev/null @@ -1,15 +0,0 @@ -apiVersion: v1 -kind: Namespace -metadata: - name: kubestellar-console ---- -apiVersion: v1 -kind: Secret -metadata: - name: kubestellar-console-github-oauth - namespace: kubestellar-console -type: Opaque -stringData: - client-id: "" - client-secret: "" - jwt-secret: default-jwt-secret-123456789012345678901234 diff --git a/files/k0s/manifests/kubestellar/40-kubestellar-console.yaml b/files/k0s/manifests/kubestellar/40-kubestellar-console.yaml index fc502bd..76baf7e 100644 --- a/files/k0s/manifests/kubestellar/40-kubestellar-console.yaml +++ b/files/k0s/manifests/kubestellar/40-kubestellar-console.yaml @@ -40,7 +40,9 @@ spec: spec: containers: - name: console - image: ghcr.io/kubestellar/console:v0.3.34 + # v0.3.34, pinned by digest for supply-chain integrity (same pattern + # as the kiosk proxy's nginx image in 41-kubestellar-kiosk-proxy.yaml). + image: ghcr.io/kubestellar/console@sha256:f27adaf8d097a5403f60041615525497e0970151fcd10b90b7b6e903b395be32 env: - name: DEV_MODE value: "true" @@ -60,12 +62,19 @@ spec: name: kubestellar-console-github-oauth key: client-secret optional: true + # When unset, the image's own start.sh generates a random + # openssl rand -hex 32 secret (persisted to $INSTALL_DIR/data/ + # .jwt_secret so it survives a plain container restart, but lost on + # pod recreation since no volume is mounted here) rather than + # falling back to an empty or compiled-in default -- verified + # against the pinned v0.3.34 tag: + # https://github.com/kubestellar/console/blob/v0.3.34/start.sh#L524-L541 - name: JWT_SECRET valueFrom: secretKeyRef: name: kubestellar-console-github-oauth key: jwt-secret - optional: false + optional: true ports: - containerPort: 8080 name: http diff --git a/tests/unit/test_k0s_manifests.py b/tests/unit/test_k0s_manifests.py index 8e0b7b6..dd7ac49 100644 --- a/tests/unit/test_k0s_manifests.py +++ b/tests/unit/test_k0s_manifests.py @@ -33,3 +33,4 @@ def test_k0s_manifest_files(): assert (ks_dir / "30-kubestellar-core.yaml").is_file() assert (ks_dir / "40-kubestellar-console.yaml").is_file() assert (ks_dir / "41-kubestellar-kiosk-proxy.yaml").is_file() + assert not (ks_dir / "01-kubestellar-console-github-oauth.yaml").exists() diff --git a/tests/unit/test_kubestellar_kiosk.py b/tests/unit/test_kubestellar_kiosk.py index 5cffd7e..10546bd 100644 --- a/tests/unit/test_kubestellar_kiosk.py +++ b/tests/unit/test_kubestellar_kiosk.py @@ -86,10 +86,13 @@ def test_console_provides_local_and_oauth_login_options() -> None: assert "hostPort:" not in console assert "name: GITHUB_CLIENT_ID" in console assert "name: GITHUB_CLIENT_SECRET" in console + assert "name: JWT_SECRET" in console assert "name: kubestellar-console-github-oauth" in console assert "key: client-id" in console assert "key: client-secret" in console + assert "key: jwt-secret" in console assert "optional: true" in console + assert "optional: false" not in console def test_proxy_is_the_only_public_console_endpoint() -> None: