# 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](./users-and-roles.md).
- **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.
