Identity, configuration, and connections
This page describes the identity, certificate, and configuration rules that ctrl, nodes, and clients share. It answers questions such as "what does this configuration item mean" and "where does this certificate come from, and when does it expire".
- For first-time deployment steps, see Installation overview.
- For
kiboflags and exit codes, see kibo CLI reference.
Source of truth for configuration
Both ctrl and node read only strict TOML: an unknown field is an error. For the full set of fields, example values, and constraints, the authority is
ctrl.example.toml and node.example.toml. The values in the examples are only examples, not the defaults of every field. Every table and key, with the comments of the examples, is listed in ctrl configuration and node configuration.
| Configuration item | Description |
|---|---|
ctrl [identity].trust_domain | The trust domain that Operator and node identities belong to, in lowercase domain-name form. It cannot be changed after initialization |
ctrl [identity].host | The hostname or IP shared by both ctrl listen addresses. The hostname clients connect with must match it. Wildcards are not accepted |
ctrl [api].listen | The mTLS listen address of the Workspace API and the Operator API |
ctrl [node_api].listen | The listen address for node enrollment, certificate issuance, and connections that nodes open to ctrl |
ctrl [data_plane].host_suffix | Required. Each node's data-plane certificate contains <node_id>.<host_suffix> |
ctrl [data_plane].default_extra_hosts | Optional. Extra hostnames or IPs added to every node's data-plane certificate |
ctrl [storage].root | The directory holding ctrl's own PKI and credential encryption keys. init creates the PKI here, and serve reads it from here. When serve finds no key under credential-keys/, it generates one with mode 0600, owned only by the service account |
node [ctrl].endpoint / proxy | The HTTPS address of the ctrl node API, and an optional forward proxy |
node [data_plane].listen / advertise | The local listen address of the data plane, and the external address that ctrl tells clients to use |
node [storage].root | The root directory for the node's identity, persistent state, Template cache, and VM runtime |
node [[storage.pool]] | Declare at least one storage pool: a directory that holds Volume block files, retained layers, and a marker file. The pool's path can equal storage.root or be elsewhere (for example, an NFS mount). Pool capacity is not declared here. See Pool capacity |
node [runtime].socket_root | The node's Unix socket directory. The node does not append the node ID under it, so keep the path short |
ctrl [metrics] | Optional. The remote write address of the instance metrics store, the private key file and CA for issuing write credentials, and instance_info_labels. Without this section, no instance metrics are written. Nodes get the write address and credentials from ctrl; a node refuses to start if its configuration contains this section. See Instance metrics storage |
ctrl [traces] | Optional. The OTLP/HTTP address of the trace store, the private key file and CA for issuing trace tokens, and the sampling ratio for the node data plane. Without this section, no spans are produced. Nodes get the address and credentials from ctrl; a node refuses to start if its configuration contains this section. See Traces |
ctrl and node [telemetry].listen | Optional. The listen address for the service's own metrics: plain HTTP, unauthenticated, serving only GET /metrics. Without it, nothing listens. It is unrelated to [metrics]. See Cluster and service metrics |
- The default configuration path is
/etc/kibotos/ctrl/config.tomlfor ctrl and/etc/kibotos/node/config.tomlfor node. Use--configto give another absolute path. - Certificates, CAs, and signing private keys are kept in directories managed by ctrl or node, not in the TOML.
- The node ID comes from the client certificate obtained during enrollment. It is not a configuration item.
- The node's
[resources]declares the CPU and memory this host can give to VMs: the physical amount minus what the host keeps for itself. It cannot exceed the host's online CPU count andMemTotal, or the node refuses to start. Overcommit is not set here. Operators set the ratios withkibo node overcommit. See Overcommit ratios. - The Template cache limit is declared with
[storage].template_cache_limit. When the cache needs space, the node evicts content not used by any running Instance, least recently used first, including partial files left by interrupted transfers. After you lower the limit, the node evicts down to the limit at startup. Content used by running Instances is kept. If eviction falls short, the node still starts, and preparing new Templates fails for lack of capacity until those Instances stop. The storage capacity for Volumes and retained layers is each pool's capacity on ctrl, set withkibo storage-pool set-capacity. The node does not detect machine capacity automatically. - Omit
[host_network]when guests need no network. For the dual-stack interfaces, routes, and DNS configuration that thepublic-internetpolicy needs, see the node configuration example.
Identity and enrollment
The initialization order of ctrl is kibotos-ctrl init → migrate → local enrollment create → serve.
init does not use the network, connect to the database, or listen on ports. It creates four things: the CA that issues client certificates, the ctrl server CA, the signing key for data-plane session credentials, and the ctrl server private key.
When the state is complete, running it again returns unchanged. When the state is incomplete or mismatched, it fails and does not repair anything automatically.
| Operation | Performed by | Result |
|---|---|---|
kibotos-ctrl enrollment create --operator <id> --output <path> | The ctrl host administrator (with access to the ctrl configuration, PKI, and database) | Issues an enrollment key for the first Operator. Also used for recovery when all Operator identities are lost |
kibo enrollment create --operator <id> --output <path> | An enrolled Operator | Issues a one-time enrollment key for another Operator |
kibo enrollment create --node <id> --output <path> | An enrolled Operator | Issues a one-time enrollment key for the node with the given ID, optionally with extra data-plane hostnames |
kibo context enroll | Operator | Exchanges an enrollment key for an Operator identity and saves it, along with the ctrl address, to the context directory |
kibotos-node join --config ... | The node host administrator | Exchanges an enrollment key for a node identity and writes it to <storage.root>/pki/. Does not start the node |
Identity rules
- The URI of a full identity is
spiffe://<trust-domain>/operator/<id>orspiffe://<trust-domain>/node/<id>. - A node ID must be in lowercase domain-name form, because it becomes part of the data-plane certificate hostname.
- Access rights are decided by the enrollment records in ctrl. Currently enrolled Operators have cluster administration rights and can call the Workspace API and the Operator API. Trusting only the ctrl server certificate (as a browser does) grants no rights.
Enrollment key rules
- A key is valid for 1 hour by default.
--ttladjusts it between 1 minute and 24 hours. - The key contains a bootstrap private key and the ctrl server CA. Treat it as a credential: keep it out of command-line arguments, environment variables, logs, and version control.
- Delete the key file after enrollment succeeds.
kibo context enroll and kibotos-node join read the key the same way:
- Without a key flag, they prompt for it in the terminal without echo. When standard input is not a terminal, give exactly one of
--key-stdin,--key-fd <n>(nis 3 or higher), or--key-file <path>. - The key cannot be passed as a command-line argument or in an environment variable.
- The key must be a single token of at most 16 KiB.
--key-fileaccepts relative paths, absolute paths, and symbolic links to a regular file. FIFOs, directories, and other special files are rejected.- When the key file is readable by group or other, the command prints a warning and still reads it. It does not change the file. Give the file mode
0600. - Permissions on the identity directory and the private key files that enrollment writes are checked strictly.
Neither kibo context enroll nor kibotos-node join overwrites an existing identity directory. When the identity in the directory has expired or is corrupted, stop the process that uses it, delete the directory, then enroll with a new enrollment key.
kibotos-ctrl enrollment create on the ctrl host invalidates that Operator's unused older keys. For replaying kibo enrollment create, see Idempotent replay.
Server and data-plane certificates
Server certificate of ctrl
During init, ctrl creates the server CA, and serve uses it to issue a server certificate for [identity].host. Every enrollment key carries this CA's certificate:
kibo context enroll and kibotos-node join first use it to verify the ctrl hostname, then send the bootstrap identity. On success, they save the CA as server-ca.pem in the identity directory.
From then on, both ctrl mTLS ports trust only this CA. They do not read the system root certificates, and they need no public DNS, no ACME, and no change to the system trust store.
Data-plane certificate of a node
The node generates the data-plane private key locally, and ctrl issues the certificate based on the node's enrolled identity. The hostnames in the certificate come from three places, with duplicates removed:
<node_id>.<host_suffix>, derived by ctrl.[data_plane].default_extra_hostsin the ctrl configuration.--data-plane-extra-hostpassed when the node's enrollment key was issued.
Rules:
- An extra hostname can be a fully qualified domain name or an IP. Wildcards are not accepted. None of them can equal ctrl's own
[identity].host. - The hostname of
[data_plane].advertisein the node configuration must be in the certificate. - The derived hostname does not need to be registered in DNS. It needs to resolve only when clients use it as the connection address.
For example, with host_suffix = "nodes.kibotos.trial", node ID node-a, and --data-plane-extra-host 127.0.0.1 added when the key is issued,
the certificate covers both node-a.nodes.kibotos.trial and 127.0.0.1, and clients on a single machine can connect directly to https://127.0.0.1:<port>.
The node stores the certificate as leaf.key, leaf.pem, and manifest.json under <storage.root>/pki/data-plane/, verifies and reuses it at startup, and reissues it when needed.
Changing the set of hostnames:
- To change a node's extra hostnames, revoke the node, issue a new enrollment key with the new hostnames, delete the old identity directory, and
joinagain. - Changing ctrl's
host_suffixordefault_extra_hostsaffects only certificates issued afterward. Schedule it together with updates to the nodes'advertiseconfiguration and certificates.
How data-plane clients verify
Data-plane clients such as kibo and the SDK use a different TLS configuration from the control plane: they trust the system root certificates plus server-ca.pem, and check hostnames by the standard rules.
So clients can connect either directly to a node or to a public TLS reverse proxy that the deployer places in front of the node. The reverse proxy must be within the deployer's trust boundary and must forward streaming requests and long-lived connections correctly.
This public TLS termination applies only to the data plane. The ctrl mTLS ports always require an enrolled identity and ctrl's own server CA.
Client connections
Context directory
kibo context enroll saves the ctrl address, the Operator identity, the trusted CAs, and the optional forward proxy in one directory, called the context. Every later kibo command reads it.
- The default location is
$XDG_CONFIG_HOME/kibo/context, or~/.config/kibo/contextwhenXDG_CONFIG_HOMEis not set. The environment variableKIBO_CONTEXT_DIRcan point to another absolute path. - The directory contains
context.json, the currentidentity-<serial>.pemandidentity-<serial>.key,control-client-ca.pem, andserver-ca.pem. enrollrefuses to overwrite an existing context directory. To enroll again, delete the old directory first.- The global flag
--endpointor the environment variableKIBO_ENDPOINTchanges only the address for the current request. The identity and the trusted CAs still come from the context.
Forward proxy
kibo context enroll --proxy and the node's [ctrl].proxy accept http://, https:// (CONNECT), or socks5:// proxies, for example --proxy socks5://proxy.example:1080.
kibosaves the proxy given toenrollin the context and uses it for every later command, including data-plane connections.- An explicit setting takes precedence. Without one, the proxy is chosen from
HTTPS_PROXY,ALL_PROXY, andNO_PROXY(and their lowercase forms). Connections to loopback addresses do not use proxies from environment variables. - TLS verification and mTLS happen inside the proxy tunnel. The username and password in the proxy address never appear in output or logs.
- The data plane does not follow redirects, and sends the session credential only after TLS verification succeeds.
Renewal, revocation, and recovery
Lifetime
| Certificate | Lifetime and renewal |
|---|---|
| ctrl server certificate | 30 days, kept only in memory. When fewer than 10 days remain, it is reissued and swapped atomically. It is reissued when ctrl restarts |
| Operator and node client identities | 30 days. Renewed when fewer than 10 days remain: kibo renews automatically before contacting ctrl, or you can run kibo context renew. A node renews automatically while running |
| node data-plane certificate | 30 days. After it enters the renewal window, renewal retries with backoff while the current certificate stays in use. After it expires, new TLS handshakes are rejected |
| The two CAs | Not rotated online. Recovery must use the original state. Replacing a CA requires reinitializing ctrl and having all clients enroll again |
- When automatic renewal fails,
kiboprints a warning and keeps using the identity until it expires. - An expired identity cannot be renewed. Enroll again with a new enrollment key.
Revocation
kibo enrollment revoke --operator <id> --yes or --node <id> --yes ends that identity immediately and cannot be undone: unused enrollment keys are invalidated, and later requests, enrollment, and renewal are rejected. Revoking a node also closes its current control connection to ctrl.
Revocation does not affect existing Workspaces or in-flight data-plane connections; they continue under their own rules. To only stop a node from accepting new Workspaces, use kibo node drain.
To bring a revoked Operator or node back, issue a new enrollment key, then run kibo context enroll or kibotos-node join again.
Backup and recovery
Recovering a deployment requires PostgreSQL data, ctrl PKI, node persistent state, and client identities that all match, plus ctrl and node versions that can connect to each other. Do not delete only the ctrl PKI while keeping the other state.
To rebuild a disposable trial environment, stop all processes first, clear all state as described in the deployment documentation, then initialize from empty directories. Do not edit the database migration version by hand, and do not forge identity files.
Service accounts and state directories
| Process or directory | Description |
|---|---|
| ctrl | Can run under a dedicated service account that can read the configuration, the database connection string, and its own PKI |
| node | Must run as root. It starts VMMs as the kibotos-vmm account |
| VMM | Runs as the system account kibotos-vmm, which must belong to the kvm group and be able to read and write /dev/kvm |
| node storage directory | Holds the owner lock, incarnation, Instances, Template cache, VM runtime, and node identity. Deleting it loses all of the node's local state |
| node storage pools | Hold Volume block files and retained layers, and can be outside the storage directory (for example, on an NFS mount). For declaring a pool and initializing its marker file, see Install node |
| node socket directory | Holds sockets and temporary VMM state while processes run. Delete it only after stopping the node and confirming that no VMM is left |
- The parent directories of the storage directory and the socket directory must allow
kibotos-vmmto enter them. - The node creates and verifies its own directories. Do not bypass the checks with symbolic links or by loosening private key permissions.
Execution ownership
Only one ctrl on a database executes: it calls nodes, runs commands and background work, and writes to the database. A row in the database guarantees this, independently of connections and database sessions, so it also holds through a connection proxy or pool.
| Situation | Behavior |
|---|---|
| No other ctrl executes when ctrl starts | It executes immediately |
| Another ctrl is executing | It answers only requests read from the database. Writes, the node API, and node control connections return a retryable unavailable. The log records another ctrl executes; answering reads only until it stops |
| The executing ctrl exits normally | It stops all work and then releases ownership, and a waiting ctrl takes over immediately |
| The executing ctrl crashes or loses the database | Ownership expires after 30 seconds before a waiting ctrl takes over. A disconnected ctrl stops executing before it expires |
| The executing ctrl loses ownership | All its later writes fail, and the process exits with an error. After the service manager restarts it, it waits read-only |
A ctrl that takes over first marks the observations of all nodes as stale. It places work on a node only after the node reconnects and reports its full inventory.
To replace ctrl, stop the old one first, then start the new one, and wait for the nodes to reconnect and report their full inventory.
Version compatibility
A node connects to ctrl only when their versions are compatible:
| Versions of ctrl and node | Rule | Log on ctrl when rejected |
|---|---|---|
Both v0.1.0 or later, release or -rc.N, with the same MAJOR.MINOR | The versions can differ. See Rolling upgrades within a MINOR | |
Both v0.1.0 or later, release or -rc.N, with different MAJOR.MINOR | The connection is rejected | is not in ctrl release line |
Any other version (-alpha.N, -beta.N, unreleased builds, v0.0.x) | The source revision must be exactly the same | does not match ctrl release |
Errors
This page helps you find out what an error means and what to do next. Look it up by the failure reason a program receives, or by the symptom you see. The linked pages explain each case in full.
kibo CLI reference
This page lists the global flags of kibo, its exit codes, its JSON output format, and its rules for reading and writing local files. Command usage is split across three places by reader: