Skip to main content

How kixctl accesses Incus

The control plane is the soft target. Every instance kixctl launches is isolated from the others and from the host — that is Incus doing its job. But the control plane sits outside that isolation by necessity: it is web-facing and holds the authority to command the fleet. Its job is to reach everything, so nothing protects it by isolating it. Per-instance isolation shrinks the blast radius of a bug in the control plane; it does not make the control plane immune to one. The honest claim is containment, not invulnerability — and containment is worthless if the credential the control plane holds is itself unlimited.

The governing rule is therefore simple: the identity kixctl uses to talk to Incus must be able to do exactly what kixctl does, and nothing more.

No shell, ever​

kixctl never touches the host. It decides and it remembers; the work happens through the Incus REST API as structured data. There is no code path where a value a user typed is interpolated into a shell command, because there is no shell — every action is an HTTP verb against a documented endpoint, and every name on the wire is URL-encoded. That single choice makes the surface between kixctl and Incus a known, enumerable set of API calls, which is what lets the permission boundary be drawn to fit it exactly.

A restricted certificate, scoped to a project​

kixctl authenticates to Incus with a restricted TLS client certificate scoped to a single project. A restricted certificate cannot make global configuration changes and is confined to the project it is granted, at the operator level within it. That maps onto what kixctl does: every action is either an operator action inside its project or an authenticated read for the fleet overview. Nothing it does needs server administration.

The certificate is the whole mechanism — no identity provider, no external authorization server, no moving parts beyond the certificate itself. In production kixctl always connects over HTTPS with that certificate; the local Unix socket used in development is root-equivalent on the host and never becomes the production path.

The powers it must never hold​

Least privilege is defined as much by what is absent as by what is present. The scoped identity never holds, and must never be granted: server administration, the creation of projects or certificates, storage-pool creation, or edits to the daemon's own configuration. If a future change appears to need one of these, that is the signal to rethink the design, not to widen the grant. Raising a certificate's scope is the cluster administrator's action, surfaced with guidance — never something kixctl does to itself.

Where authorization lives​

Access control is layered, and the layers are distinct:

  • The certificate is the transport identity — what the kixctl service may ask of Incus.
  • kixctl's own roles decide what a logged-in person may ask of kixctl. This is the free, open path, and it needs no external identity infrastructure. See Users, roles, and permissions.
  • Incus-native authorization is a later, opt-in enterprise direction: end users authenticate through an external identity provider and Incus itself enforces per-instance access — enforcement that holds even against the incus CLI and even against a bug in kixctl. It is a tier feature, never a baseline requirement.

The seam between those layers is kept clean, so the enterprise path stays open without the open-source path ever carrying its weight.