Skip to content

design-proposal(compute-plane): deliver as an operator-owned extra module wrapping apps/kubernetes (supersedes #27)#33

Open
Andrei Kvapil (kvaps) wants to merge 3 commits into
mainfrom
design/compute-plane-module
Open

design-proposal(compute-plane): deliver as an operator-owned extra module wrapping apps/kubernetes (supersedes #27)#33
Andrei Kvapil (kvaps) wants to merge 3 commits into
mainfrom
design/compute-plane-module

Conversation

@kvaps

@kvaps Andrei Kvapil (kvaps) commented Jul 13, 2026

Copy link
Copy Markdown
Member

What

Revises the ComputePlane design proposal. ComputePlane is delivered as a Cozystack-owned Tenant module (packages/extra/computeplane) that provisions a hardened kind: Kubernetes by wrapping the existing apps/kubernetes chart with operator-fixed values — not user-facing preset fields (isolationProfile × componentProfile) on kind: Kubernetes.

Because a Tenant module is registered via an ApplicationDefinition, ComputePlane does get its own apps.cozystack.io module-kind and API (like SeaweedFS, Kubernetes and every managed service). The accurate framing is therefore: no new CRD, no new controller/reconcile path, and no new fields on kind: Kubernetes — the ComputePlane kind is a thin operator-owned wrapper over the unchanged apps/kubernetes.

Why this supersedes #27

#27 put the posture on kind: Kubernetes as user-facing fields. This revision moves it into an operator-owned extra module:

  • apps vs extra (docs(development): explain why packages live in apps vs extra website#594): a ComputePlane is a per-tenant enabler switched on under the hood, not a first-class cluster the tenant orders/configures — exactly an extra module (like extra/etcdapps/kubernetes).
  • Tamper-proof by construction: the hardening lives in the operator-owned chart and the tenant holds no admin kubeconfig, so there is no field for the tenant to weaken. The chart is the profile.
  • kind: Kubernetes untouched: no fields added to the cluster app; the user still gets the same cluster — they just don't administer it and can change only the curated knobs the module exposes.

Mechanism

Reuses the existing PackageSource "source-only chart" pattern (how NATS/SeaweedFS already ship): a computeplane-application PackageSource re-sources apps/kubernetes as a source-only ExternalArtifact, plus a computeplane-rd resource-definition and the extra/computeplane module chart. Apps route in via a new placement: ManagementPlane | ComputePlane field on ApplicationDefinition, injecting kubeConfig.secretRef → computeplane-admin-kubeconfig for one-way remote Flux apply (unchanged mechanism from the merged first revision).

Relationship to prior proposals

Departs from #26's "no new kind at all" (that is the #27 field model, set aside here) but keeps the #26 / #17-review objection to a heavyweight distinct kind: the ComputePlane module-kind does not duplicate the cluster reconcile/RBAC path — it wraps the unchanged apps/kubernetes. Supersedes #27 (preset fields — see "Alternatives considered" for the full trade-off). The underlying isolation mechanism (remote Flux apply, per-VM boundary, single-tenant, scoped egress, cozystack-api visibility control) is unchanged.

Closes #26

Summary by CodeRabbit

  • Documentation
    • Clarified ComputePlane as a tenant-facing module built on the existing Kubernetes application.
    • Documented management-plane and compute-plane placement options, including default behavior.
    • Added details on remote cluster targeting, service connectivity, inbound access, and restricted application visibility.
    • Clarified upgrade, rollback, dependency, failure, and teardown expectations.
    • Updated testing, rollout phases, alternatives, and open questions.

…ing apps/kubernetes

Revise the ComputePlane proposal: deliver it as an operator-owned Tenant
module (extra/computeplane) that wraps the existing apps/kubernetes chart
with fixed values, instead of user-facing preset fields on kind: Kubernetes.
Keeps the "not a new kind" conclusion from the #17 review and #26;
supersedes the preset-field revision (#27). The underlying isolation
mechanism (remote Flux apply, per-VM boundary, single-tenant) is unchanged.

Assisted-By: Claude
Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
@coderabbitai

coderabbitai Bot commented Jul 13, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@kvaps, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 33 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 349349f0-db2c-4fcf-99ae-0b5323e00eb3

📥 Commits

Reviewing files that changed from the base of the PR and between f17a27b and 90f0409.

📒 Files selected for processing (1)
  • design-proposals/compute-plane/README.md
📝 Walkthrough

Walkthrough

Changes

The ComputePlane proposal now defines an operator-owned Tenant module wrapping apps/kubernetes, with placement-based remote application routing, sandbox connectivity controls, restricted-app enforcement, additive defaults, and updated security, failure, testing, rollout, and compatibility contracts.

ComputePlane delivery redesign

Layer / File(s) Summary
Tenant module packaging
design-proposals/compute-plane/README.md
ComputePlane is packaged as an extra Tenant module using a source-only PackageSource around apps/kubernetes, without introducing a new CRD, controller, or kind: Kubernetes fields.
Placement and tenant controls
design-proposals/compute-plane/README.md
ApplicationDefinition placement injects the ComputePlane kubeconfig reference, while sandbox egress and restricted application visibility and mutation are defined as API-enforced contracts.
Compatibility and rollout behavior
design-proposals/compute-plane/README.md
Security boundaries, failure cases, testing, rollout phases, defaults, deferred questions, and retired alternatives are revised for the module-based design.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

Suggested reviewers: lllamnyp

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The PR pivots away from #26’s required kind: Kubernetes preset model and introduces a separate module-owned surface. Keep ComputePlane on the existing kind: Kubernetes surface with composable presets and remove the separate module-kind framing.
Out of Scope Changes check ⚠️ Warning The new module-packaging and ApplicationDefinition module-kind changes go beyond the issue’s requested preset-only surface. Restrict the PR to the existing kind: Kubernetes preset model; defer the operator-owned module wrapper and new module-kind.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly states the main redesign: an operator-owned extra module wrapping apps/kubernetes.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch design/compute-plane-module

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request updates the design proposal for Cozystack's ComputePlane. Instead of introducing a new top-level kind or user-facing preset fields on kind: Kubernetes, the proposal now delivers ComputePlane as an operator-controlled Tenant module (packages/extra/computeplane) that wraps the ordinary apps/kubernetes chart with operator-fixed values. The reviewer identified an architectural contradiction in the packaging design: the proposal describes ComputePlane as a new Tenant module, but the illustrative HelmRelease points directly to the re-sourced apps/kubernetes chart, which would bypass the packages/extra/computeplane chart entirely. Clarification on whether the module chart acts as a wrapper or if it is redundant is requested.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +78 to +98
Reuse the `kubernetes` app as the substrate, unchanged. A ComputePlane is delivered as a new Tenant module, `packages/extra/computeplane`, of the same shape as `extra/etcd` / `extra/seaweedfs`. When a tenant has the module enabled, the tenant chart renders a `HelmRelease` (in the tenant namespace, on the management cluster) whose `chartRef` points at the **source-only** `apps/kubernetes` `ExternalArtifact`, carrying operator-fixed values:

```yaml
# packages/extra/computeplane — rendered HelmRelease (illustrative)
apiVersion: helm.toolkit.fluxcd.io/v2
kind: HelmRelease
metadata:
name: computeplane
namespace: tenant-<name> # management cluster, tenant namespace
spec:
chartRef:
kind: ExternalArtifact
name: cozystack-computeplane-application-kubevirt-kubernetes # apps/kubernetes, re-sourced (Design §2)
namespace: cozy-system
values: # operator-owned; the tenant cannot edit these
# hardened posture: restricted PSA + admission, deny egress → management kube-apiserver,
# scoped per-service egress only, addon set, GPU node groups, autoscaling bounds …
valuesFrom:
- kind: Secret # only the curated knobs the module chooses to surface
name: cozystack-values
```

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

There is an architectural contradiction in how the packages/extra/computeplane module is defined versus how it is deployed:

  1. The proposal states that "ComputePlane is delivered as a new Tenant module, packages/extra/computeplane" (line 78).
  2. However, the illustrative HelmRelease (lines 81-98) has its chartRef pointing directly at cozystack-computeplane-application-kubevirt-kubernetes (which is the re-sourced apps/kubernetes chart).

If the tenant chart's HelmRelease points directly to the re-sourced apps/kubernetes chart, the packages/extra/computeplane chart itself is bypassed and remains completely unused.

To resolve this, please clarify the packaging structure:

  • Option A: The tenant chart renders a HelmRelease pointing to packages/extra/computeplane, and packages/extra/computeplane acts as the wrapper that contains/renders the apps/kubernetes HelmRelease or templates.
  • Option B: If the tenant chart directly releases apps/kubernetes with overridden values, then the packages/extra/computeplane chart is redundant and only the computeplane-application PackageSource and computeplane-rd are needed.

…module

A Tenant module is registered via an ApplicationDefinition, so ComputePlane
does get its own apps.cozystack.io kind and API — the 'not a new top-level
kind' claim carried over from #27 is inaccurate for this delivery. Reframe
honestly: no new CRD, no new controller/reconcile path, and no fields on
kind: Kubernetes; but a thin ComputePlane module-kind is registered like
every other managed service.

Assisted-By: Claude
Signed-off-by: Andrei Kvapil <kvapss@gmail.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@design-proposals/compute-plane/README.md`:
- Line 151: Expand the “Connectivity to tenant services” section to define the
complete ComputePlane-to-service egress contract: identify the authorization
owner, specify how scoped CiliumNetworkPolicy resources are generated, bind
policies to workloads and tenant services, define revocation behavior, and
prevent bypass through direct service endpoints. Keep the contract explicit
about denying kube-apiserver access and allowing only authorized tenant
services.
- Line 211: Clarify the tenant/module deletion flow by naming the existing
component that owns and removes the module finalizer, and document the
fail-closed disable-then-deprovision sequence. Explicitly state that remote
HelmReleases are deleted before the ComputePlane or target cluster disappears,
and describe the behavior when cleanup cannot be confirmed so deletion cannot
hang or proceed prematurely.
- Line 136: Update the ComputePlane design and related deployment flow so
placement: ComputePlane app releases use Flux remote-cluster ServiceAccount
impersonation via spec.serviceAccountName and a least-privilege identity. Remove
references to computeplane-admin-kubeconfig and super-admin.svc for app routing,
while retaining the Kamaji admin kubeconfig only where administrative access is
explicitly required.
- Around line 207-208: Update the ComputePlane placement dependency
documentation and implementation guidance so the remote HelmRelease waits for
the module-level ComputePlane Ready condition, not merely the
computeplane-admin-kubeconfig Secret. Ensure Flux starts the remote release only
after PSA, admission, and egress hardening reconciliation completes, while
preserving the existing fail-closed behavior for missing or rotated credentials.
- Around line 92-98: Update the cozystack-values valuesFrom configuration to
enforce an explicit allowlist or schema for accepted Secret keys, ensuring
parent- or tenant-editable inputs cannot override hardened settings through
targetPath or Flux merge ordering. Keep only the curated knobs intended by the
module exposed, and preserve the operator-owned inline values as authoritative.
- Line 144: Update the ComputePlane deployment flow for ApplicationDefinition
placement so the target tenant namespace is pre-created with required PSA
labels, quotas, and ownership metadata before the HelmRelease can install
workloads. Do not rely solely on spec.install.createNamespace; either provision
the namespace explicitly or enforce equivalent admission gating before workload
creation.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 9a3c7d2e-1201-4964-b71f-8b232983157f

📥 Commits

Reviewing files that changed from the base of the PR and between 4ec8567 and f17a27b.

📒 Files selected for processing (1)
  • design-proposals/compute-plane/README.md

Comment thread design-proposals/compute-plane/README.md
- `computeplane-rd` → `path: system/computeplane-rd` with `install:` — the resource-definition chart carrying the module's `cozyrd` (its `ApplicationDefinition` / dashboard presentation and the tenant-values wiring), the same role `seaweedfs-rd` / `kubernetes-rd` play.

An empty string means disabled; a non-empty value names a ComputePlane **profile/class**. The profile — node groups, GPU types, Kubernetes version, autoscaling bounds — is defined **once** at the tenant/platform level and referenced by name. There is deliberately **no per-module `valuesOverride` blob**: that would re-create the two-sources-of-truth problem (the module spec living both in the profile and inline on the tenant). Keeping the module a bare profile reference makes the profile definition the single source of truth.
The tenant chart gains a `computePlane` toggle (a bool, or a profile name if the operator ships more than one module variant) alongside the existing module toggles; when set by the parent tenant, `packages/apps/tenant/templates/computeplane.yaml` renders the `HelmRelease` above. Kamaji writes the cluster's admin kubeconfig to `computeplane-admin-kubeconfig` (key `super-admin.svc`), which `placement: ComputePlane` apps consume (Design §4).

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the relevant section of the proposal
FILE="design-proposals/compute-plane/README.md"
wc -l "$FILE"
sed -n '120,170p' "$FILE"

# Find references to the kubeconfig and placement
rg -n "computeplane-admin-kubeconfig|super-admin\.svc|placement: ComputePlane|HelmRelease|serviceAccountRef|remote cluster" "$FILE"

Repository: cozystack/community

Length of output: 16209


🌐 Web query:

Flux HelmRelease remote cluster serviceAccountName kubeConfig secretRef docs

💡 Result:

To deploy a HelmRelease to a remote cluster using Flux, you use the spec.kubeConfig field to reference a Kubernetes Secret containing the remote cluster's kubeconfig [1][2][3]. This configuration directs the Flux helm-controller to perform Helm operations on the target cluster instead of the local cluster where Flux is installed [2][4]. Key components for this setup include: 1. KubeConfig Secret: You must create a Kubernetes Secret in the same namespace as the HelmRelease [2][5][6]. This secret stores the kubeconfig file for the remote cluster, typically under the data key value (default) or as specified by the secretRef [2][4][5]. 2. HelmRelease Configuration: Include the kubeConfig field in your HelmRelease manifest to link to this secret [2][3]: spec: kubeConfig: secretRef: name: 3. Impersonation (Optional): You can optionally use spec.serviceAccountName to specify a ServiceAccount in the target cluster that the controller should impersonate [2][4]. When both spec.kubeConfig and spec.serviceAccountName are provided, the controller will act on behalf of that ServiceAccount within the remote cluster [2][4]. For this to work, the ServiceAccount must exist in the target cluster within a namespace that matches the namespace of the HelmRelease on the management cluster [2]. Important considerations: - The management cluster must have network access to the remote cluster's API server [5]. - If the remote API server uses self-signed certificates, you may need to configure the controller with the --insecure-kubeconfig-tls flag [5]. - The secretRef must reside in the same namespace as the HelmRelease object [2][5]. - If you do not specify a ServiceAccount, the controller will default to using the credentials provided in the kubeconfig [4]. Note that there is a distinction between the ServiceAccount used for impersonation on the remote cluster (spec.serviceAccountName) and the controller's own ServiceAccount [2].

Citations:


Don't route app releases with the ComputePlane super-admin kubeconfig

placement: ComputePlane should use Flux remote-cluster ServiceAccount impersonation (spec.serviceAccountName) with a least-privilege identity, not computeplane-admin-kubeconfig/super-admin.svc. An admin kubeconfig gives a compromised chart the ability to create cluster-scoped resources and access other tenant secrets.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@design-proposals/compute-plane/README.md` at line 136, Update the
ComputePlane design and related deployment flow so placement: ComputePlane app
releases use Flux remote-cluster ServiceAccount impersonation via
spec.serviceAccountName and a least-privilege identity. Remove references to
computeplane-admin-kubeconfig and super-admin.svc for app routing, while
retaining the Kamaji admin kubeconfig only where administrative access is
explicitly required.

Source: MCP tools

### 4. `placement` routes a catalog app onto the ComputePlane

This is where the design leans entirely on an existing, proven mechanism. An application that must be isolated declares `placement: ComputePlane` on its `ApplicationDefinition`. When a tenant creates the app:
`ApplicationDefinition` gains `placement` = `ManagementPlane` (default) | `ComputePlane`. `ManagementPlane` deploys into the tenant namespace on the management cluster, as today. `ComputePlane` routes the generated `HelmRelease` onto the tenant's ComputePlane by injecting `spec.kubeConfig.secretRef` → `computeplane-admin-kubeconfig` (the module's fixed secret) and `spec.install.createNamespace: true`. Because the module is a single per-tenant enabler, `ComputePlane` resolves unambiguously to *that* tenant's cluster — no cluster name to thread through the app.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

sed -n '120,170p' design-proposals/compute-plane/README.md

Repository: cozystack/community

Length of output: 7627


🏁 Script executed:

rg -n "createNamespace|targetNamespace|computeplane-admin-kubeconfig|Placement|ManagementPlane|ComputePlane" design-proposals/compute-plane/README.md

Repository: cozystack/community

Length of output: 19897


🌐 Web query:

Flux HelmRelease install.createNamespace targetNamespace namespace labels PSA quotas documentation

💡 Result:

Flux HelmRelease fields/behavior for: 1) install.createNamespace - In Flux HelmRelease v2, namespace creation is controlled by.spec.install.createNamespace (boolean). It “tells the Helm install action to create the HelmReleaseSpec.TargetNamespace if it does not exist yet”. On uninstall, “the namespace will not be garbage collected”. It defaults to false. [1][2] - Nuance: this only affects the Helm install action (not upgrades). [1][2][3] 2) targetNamespace -.spec.targetNamespace is optional and specifies “the namespace to which the Helm release is made”; it defaults to the namespace where the HelmRelease resource lives. [4][2] - Warning: changing.spec.targetNamespace after install will not move the already-installed release; instead it uninstalls and reinstalls in the new target namespace. [2] 3) namespace labels - Flux/helm-controller can apply labels/annotations to the Kubernetes objects it manages via: a) HelmRelease metadata (Kubernetes-native labels), b) HelmReleaseSpec.commonMetadata (“common labels and annotations that are applied to all resources”). [1] - Those labels are applied to the objects created by Flux/Helm (deployments, services, etc.), not automatically to the Namespace object itself via createNamespace. 4) PSA labels and quotas - Flux’s HelmRelease documentation does not state any built-in option that, when createNamespace is enabled, will automatically set Kubernetes Namespace PSA labels (pod-security.kubernetes.io/*) or create ResourceQuota/LimitRange objects for quotas. - PSA is enforced by Namespace-level labels, and quotas are represented by Kubernetes ResourceQuota/LimitRange API objects, which must be created as Kubernetes manifests (either by your GitOps namespace-manifest layer, and/or by templates in your Helm chart). [5][1][2] What this means for your specific query - install.createNamespace: use spec.install.createNamespace to ensure the target Namespace exists. [1][2] - targetNamespace: use spec.targetNamespace to choose where the Helm release is installed. [4][2] - labels / PSA quotas: you must manage Namespace labels for PSA and Namespace ResourceQuota/LimitRange objects separately from Flux’s createNamespace behavior; Flux’s HelmRelease createNamespace does not provide automatic PSA/quotas setup per the official docs. [5][1][2] If you tell me the PSA profile you want (e.g., baseline/restricted/audit/warn/enforce versions) and the quota numbers, I can generate a GitOps-ready set of Namespace + ResourceQuota/LimitRange manifests to pair with your HelmRelease.

Citations:


Pre-create the ComputePlane namespace. install.createNamespace: true only creates targetNamespace; it won’t apply PSA labels, quotas, or ownership metadata. Pre-create that namespace with the required controls, or gate namespace creation through admission before workloads start.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@design-proposals/compute-plane/README.md` at line 144, Update the
ComputePlane deployment flow for ApplicationDefinition placement so the target
tenant namespace is pre-created with required PSA labels, quotas, and ownership
metadata before the HelmRelease can install workloads. Do not rely solely on
spec.install.createNamespace; either provision the namespace explicitly or
enforce equivalent admission gating before workload creation.

Source: MCP tools


The routing decision is driven by the `placement` enum on the `ApplicationDefinition` — `ManagementPlane` (default) applies into the tenant namespace on the management cluster as today; `ComputePlane` injects the ComputePlane `kubeConfig.secretRef`. The two values name the two symmetric planes. This keeps the routing policy declarative and out of per-app charts.
- **Remote apply (into the cluster).** For a `placement: ComputePlane` app, `cozystack-api` converts it to a `HelmRelease` on the management cluster carrying `spec.kubeConfig.secretRef` → `computeplane-admin-kubeconfig`; Flux applies the chart **into the ComputePlane**, never into the tenant namespace on management. This is exactly what the first revision implemented.
- **Connectivity to tenant services (`sandbox` data-plane contract).** A notebook/LLM/n8n flow needs the tenant's data ("my Jupyter → my managed Postgres"), which runs in the tenant namespace on the management cluster. The guarantee is "no kube-API access / no creds to escalate," **not** "no packets ever." No mesh is required: the ComputePlane's KubeVirt-VM node pods sit on the management Cilium pod network, so reachability is a **scoped per-service `CiliumNetworkPolicy`** — allow → the tenant's Postgres Service, deny → kube-apiserver (same shape as the existing `policy.cozystack.io/allow-to-apiserver` label). Per-service egress is narrower-by-construction than a node mesh — which matters because the consumer is untrusted code.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Map the target file and nearby sections
wc -l design-proposals/compute-plane/README.md
sed -n '120,260p' design-proposals/compute-plane/README.md

# Find the referenced label / policy shape and any related contract text
rg -n "allow-to-apiserver|CiliumNetworkPolicy|network policy|egress|sandbox|tenant's Postgres|tenant namespace|open questions|untrusted code|direct-endpoint|workload-to-service|revocation|authorization" design-proposals/compute-plane/README.md design-proposals -S

Repository: cozystack/community

Length of output: 50377


Define the ComputePlane→service egress contract.
The per-service egress path is still underspecified: who authorizes it, how the CiliumNetworkPolicy is generated, how workload-to-service binding and revocation work, and how direct-endpoint bypass is blocked all need to be nailed down before this sandbox contract is treated as complete.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@design-proposals/compute-plane/README.md` at line 151, Expand the
“Connectivity to tenant services” section to define the complete
ComputePlane-to-service egress contract: identify the authorization owner,
specify how scoped CiliumNetworkPolicy resources are generated, bind policies to
workloads and tenant services, define revocation behavior, and prevent bypass
through direct service endpoints. Keep the contract explicit about denying
kube-apiserver access and allowing only authorized tenant services.

Comment on lines +207 to +208
- **ComputePlane not ready when a `placement: ComputePlane` app is created** → the `HelmRelease` waits on the `computeplane-admin-kubeconfig` Secret; Flux surfaces not-ready, as with any dependency ordering.
- **kubeconfig Secret missing/rotated** → remote apply fails closed (no fallback to local apply); the security-correct behavior.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Show nearby context around the cited lines
file="design-proposals/compute-plane/README.md"
wc -l "$file"
sed -n '170,240p' "$file"

# Search for the key terms across the repo
rg -n --hidden --glob '!**/.git/**' -e 'computeplane-admin-kubeconfig|placement: ComputePlane|hardening readiness|PSA|admission|egress policy|remote apply|ComputePlane' .

Repository: cozystack/community

Length of output: 35012


🏁 Script executed:

#!/bin/bash
set -euo pipefail

file="design-proposals/compute-plane/README.md"
wc -l "$file"
sed -n '170,240p' "$file"
rg -n --hidden --glob '!**/.git/**' -e 'computeplane-admin-kubeconfig|placement: ComputePlane|hardening readiness|PSA|admission|egress policy|remote apply|ComputePlane' .

Repository: cozystack/community

Length of output: 35012


Gate placement on full ComputePlane readiness, not just kubeconfig availability. The computeplane-admin-kubeconfig Secret only gives remote-apply credentials; it does not guarantee the ComputePlane’s PSA/admission/egress hardening has finished reconciling. Make placement: ComputePlane wait on a module-level Ready condition before Flux starts the remote release.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@design-proposals/compute-plane/README.md` around lines 207 - 208, Update the
ComputePlane placement dependency documentation and implementation guidance so
the remote HelmRelease waits for the module-level ComputePlane Ready condition,
not merely the computeplane-admin-kubeconfig Secret. Ensure Flux starts the
remote release only after PSA, admission, and egress hardening reconciliation
completes, while preserving the existing fail-closed behavior for missing or
rotated credentials.

- **kubeconfig Secret missing/rotated** → remote apply fails closed (no fallback to local apply); the security-correct behavior.
- **`placement: ComputePlane` app but the module is disabled on the tenant** → reject at admission. Never climb to an ancestor's ComputePlane (Design §7).
- **GPU exhaustion** → cluster-autoscaler adds GPU nodes up to the configured `maxReplicas`; beyond that the workload pends.
- **Tenant / module deletion** → remote `HelmRelease`s must be deleted *before* the cluster is deprovisioned (a finalizer on the module blocks teardown until they're cleaned up) — otherwise Flux's HelmRelease finalizers block once the target API is gone.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

sed -n '180,240p' design-proposals/compute-plane/README.md

Repository: cozystack/community

Length of output: 9979


🏁 Script executed:

rg -n "finalizer|teardown|deprovision|disablement|disable|module.*finalizer|HelmRelease" design-proposals/compute-plane/README.md

Repository: cozystack/community

Length of output: 7702


🏁 Script executed:

sed -n '1,180p' design-proposals/compute-plane/README.md

Repository: cozystack/community

Length of output: 26654


🏁 Script executed:

sed -n '240,360p' design-proposals/compute-plane/README.md

Repository: cozystack/community

Length of output: 2408


Clarify teardown ownership and ordering. The finalizer needs an explicit owner and removal path; otherwise module deletion can hang waiting for cleanup, or the ComputePlane can disappear before Flux deletes the remote HelmReleases. Spell out which existing component clears the finalizer and the fail-closed disable/deprovision sequence.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@design-proposals/compute-plane/README.md` at line 211, Clarify the
tenant/module deletion flow by naming the existing component that owns and
removes the module finalizer, and document the fail-closed
disable-then-deprovision sequence. Explicitly state that remote HelmReleases are
deleted before the ComputePlane or target cluster disappears, and describe the
behavior when cleanup cannot be confirmed so deletion cannot hang or proceed
prematurely.

The illustrative HelmRelease conflated the tenant-rendered module release
with the cluster release the module renders, making extra/computeplane look
bypassed. Show both levels — tenant chart → extra/computeplane (release
computeplane-module) → re-sourced apps/kubernetes (release computeplane →
the computeplane-admin-kubeconfig contract) — matching the implementation
in cozystack/cozystack#3280, and pin the tenant toggle as the computeplane
bool.

Assisted-By: Claude
Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
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.

Follow-up to #17 (ComputePlane): deliver it as composable presets on kind: Kubernetes, not a new kind

1 participant