# Concepts

> What PowerCloud is and the ideas every other page builds on - trusted and untrusted nodes, the cluster and its storage locations, the passphrase and recovery key, the cluster CA, nodes, pcctl, the mesh and apps - with a glossary.

PowerCloud is an operating system for running your own cloud on machines you own, rented servers and VMs on any public cloud, all at once. Data is encrypted before it leaves a machine you trust, so storage providers and plain cloud VMs only ever hold ciphertext, and it is spread over several providers so that no single one can read it, change it unnoticed, or take it away. This page explains the parts of a PowerCloud cluster and the words the rest of the documentation uses.

## What PowerCloud is

PowerCloud OS is a minimal, hardened Linux kernel with a userland written entirely in Go, for x86-64 (amd64) and arm64 machines.

- **No shell, no SSH, no login.** The userland is a handful of static Go binaries: `pcinit` (PID 1, which starts and supervises services) and `pcd` (the node daemon). There is no package manager and no way to log in.
- **Managed only through an API.** Everything is done with the `pcctl` command-line tool on your own computer, which talks to nodes over mutually authenticated TLS.
- **One image file.** The kernel, its initramfs and a fixed kernel command line are a single EFI application that UEFI firmware boots directly, with no boot loader. Nobody at the console or at the cloud provider can change the command line, and one signature covers the whole OS for Secure Boot.
- **Hardened kernel.** Loadable modules are disabled entirely and kernel lockdown is forced to confidentiality mode.

PowerCloud has two halves that you can use separately: an encrypted, replicated object store you drive from `pcctl` alone, and nodes that run the OS, join a mesh, hold storage and run apps.

## Trusted and untrusted

Every place your data touches is either trusted or untrusted.

```mermaid
%% alt: You manage trusted nodes with pcctl; everything that leaves them for buckets and plain VMs is already encrypted.
flowchart TB
  admin["Your computer: pcctl + passphrase"]
  subgraph trusted ["Trusted: hold keys, run apps"]
    direction LR
    home["Home server"] <-->|WireGuard| colo["Colo machine"] <-->|WireGuard| cvm["Attested confidential VM"]
  end
  subgraph untrusted ["Untrusted: hold only ciphertext"]
    direction LR
    s3a[("Bucket, provider A")]
    s3b[("Bucket, provider B")]
    vm["Plain cloud VM"]
  end
  admin -->|mutual TLS| trusted
  trusted -->|encrypted chunks| untrusted
```

| | Examples | What it may do |
|---|---|---|
| **Trusted node** | Your own hardware (home server, colo machine), or a confidential VM (AMD SEV-SNP) that passed attestation | Holds keys, decrypts data, runs apps |
| **Untrusted location or node** | An S3 bucket, a plain cloud VM | Stores and relays ciphertext only |

The reason is the threat model: on someone else's ordinary VM, the host can read the VM's memory, and with it any key the VM holds. Only a confidential VM, whose memory the CPU encrypts, closes that gap; PowerCloud verifies AMD SEV-SNP attestation before it gives such a VM a key (Intel TDX and Arm CCA are not supported yet). See [Security model](https://powercloud.unidatum.com/security) for the full threat model and [Unlocking nodes after a reboot](https://powercloud.unidatum.com/docs/unlock.md) for attested unlock.

## The cluster

A cluster is one set of keys, one store and the nodes enrolled in it.

### Storage locations: the repository

The cluster's data lives in an encrypted store spread over **storage locations**. Together they are called the **repository**, given to `pcctl` with `--repo` as a comma-separated list:

```sh
pcctl --repo '/srv/pc,s3://my-bucket/pc?region=us-east-2,node://home-1' ls
```

A location is a local directory, an S3-compatible bucket (AWS S3, Cloudflare R2, Backblaze B2, Wasabi, RustFS and others), the encrypted disk of one of your nodes (`node://NAME`), or an erasure-coded set of several of these (`ec:K:LOC;LOC;...`). You can mix them freely. Instead of typing `--repo` every time, you can set the `POWERCLOUD_REPO` environment variable to the same list.

- **Everything is encrypted on your machine first.** Files are split into 4 MiB chunks, each sealed with XChaCha20-Poly1305. Names, sizes and chunk lists are in encrypted manifests, so a provider sees neither file names nor contents.
- **Each write goes to several locations.** A write must reach a **quorum** of locations (by default a majority) to succeed. Reads fall back to any location that has the data, so losing one provider loses nothing.
- **`pcctl check`, `repair` and `gc`** compare the locations, bring one that was down (or newly added) up to date, and reclaim chunks nothing uses any more.

[Storage](https://powercloud.unidatum.com/docs/storage.md) covers locations, quorum, erasure coding and repair in detail.

### The passphrase and the recovery key

The cluster has one random 256-bit **root key**, which is never stored in plaintext. It is wrapped, in the style of LUKS keyslots, in a small **key header** stored at every location:

- a **passphrase** slot (at least 12 characters; stretched with Argon2id), which you choose at `pcctl init`
- a **recovery key** slot: `pcctl init` prints a 160-bit recovery key once. Write it down and store it offline. It opens the cluster on its own, if the passphrase is forgotten.

Every other key is derived from the root key for its purpose: the store's encryption keys, the cluster CA, the keys for each node's disk. So whoever has the passphrase or the recovery key, plus a copy of the header from any location, holds the whole cluster. If either leaks, `pcctl rotate` replaces the root key and re-encrypts the store (see [Admins, keys and revocation](https://powercloud.unidatum.com/docs/access.md)).

```mermaid
%% alt: The passphrase or the recovery key opens the key header from any location; pcctl unwraps the root key in memory and derives every other key from it.
flowchart TB
  pass["Passphrase"] -->|Argon2id| header
  rec["Recovery key"] --> header
  header[("Key header, at every location")]
  subgraph pc ["pcctl, on your computer"]
    root["256-bit root key"]
    root --> store["Store encryption keys"]
    root --> ca["Cluster CA key"]
    root --> vol["Disk key for each node"]
  end
  header -->|unwraps| root
  ca -->|signs| certs["Node and admin certificates"]
  vol -->|"sent at enroll and unlock"| node["Node's state volume"]
```

There is no backdoor. If every passphrase and the recovery key are lost, the data cannot be recovered by anyone.

`pcctl` reads the passphrase from the terminal, or from `POWERCLOUD_PASSPHRASE` for scripts. To unlock with the recovery key instead, set `POWERCLOUD_RECOVERY_KEY`.

### The cluster CA

Nodes and admins prove who they are with certificates from the **cluster CA**. Its Ed25519 key is derived from the root key and is never stored anywhere, so anyone who can unlock the cluster can issue certificates, and nobody else can, including a provider holding every blob.

The CA signs everything nodes accept from admins: node and admin certificates, the membership list, the revocation list, releases, cluster apps and the consensus founding document. Nodes check the CA's signature, so these documents can be passed from node to node safely.

## Nodes and pcd

A **node** is a machine (physical or virtual) running PowerCloud OS. Its daemon, `pcd`, holds the node's identity and serves the **node API** on TCP port 7443.

- **Identity.** On first start, `pcd` generates an Ed25519 key. The node ID is a hash of that key (shown as 16 hex digits, such as `fa8adc53910a6a79`).
- **Enrollment.** A new node prints a one-time **enrollment code** on its console. `pcctl node enroll` uses it to check it is talking to that exact node and to prove you read the console, then gives the node a certificate from the cluster CA. Alternatively, a node can be issued its identity ahead of time as a **join bundle** and join with nobody at its console. See [Enroll a node](https://powercloud.unidatum.com/docs/enroll.md).
- **After enrollment** the node accepts only clients with a certificate from its cluster CA, and checks each certificate's role: `admin` (you) or `node` (its peers). Node certificates last a year and are renewed with `pcctl node renew`.
- **Encrypted state volume.** A node keeps its identity and state on an encrypted partition of its disk (dm-crypt, with an HMAC-SHA256 tag on every sector, so a disk changed while the node is off reads as an error rather than as altered data). The key for it can only be derived by someone who can unlock the cluster. After a reboot, the node stays **locked** until an admin runs `pcctl node unlock`, unless TPM unlock or peer unlock is on; see [Unlocking nodes after a reboot](https://powercloud.unidatum.com/docs/unlock.md).
- **The registry.** Every enrolled node is recorded in the cluster's encrypted store, so every admin of the cluster sees the same nodes, their addresses and their disk volume IDs.

See [Managing nodes](https://powercloud.unidatum.com/docs/nodes.md) for managing nodes day to day.

## pcctl and admin certificates

`pcctl` is the only management tool. It runs on Linux and macOS (amd64 and arm64); there is no Windows build.

Commands come in two kinds:

- **Commands that need the cluster keys** take `--repo` (or `--via NODE`, below) and ask for the passphrase: `init`, `put`, `get`, `node enroll`, `node unlock`, `node rm`, `rotate` and others.
- **Day-to-day commands** need only your **admin certificate**: `pcctl status`, `pcctl node info NAME`, `pcctl node reboot NAME`, `pcctl app ...`, `pcctl console`.

An admin certificate lasts 30 days. `pcctl --repo ... login` issues one, and any command that unlocks the cluster renews it by itself when a week or less is left. It is kept, with the CA certificate and the list of nodes this machine knows (`nodes.json`), in the configuration directory: `$POWERCLOUD_CONFIG` if set, otherwise `~/.config/powercloud` on Linux or `~/Library/Application Support/powercloud` on macOS. `pcctl revoke-admins` revokes every admin certificate at once, for example after losing a laptop.

Once a node serves the storage (`pcctl node storage`), `--via NODE` can replace `--repo`: the node holds the storage locations and their credentials and relays encrypted blobs, so your laptop needs only the passphrase and its admin certificate. The node never gets the keys. `init`, `check`, `repair`, `gc` and `rotate` still need `--repo`.

```mermaid
%% alt: pcctl reaches the storage locations directly with --repo, or through a node with --via; either way it encrypts first, so the locations and the relaying node see only ciphertext.
flowchart TB
  subgraph laptop ["Your computer"]
    pcctl["pcctl, with passphrase<br/>and admin certificate"]
  end
  node["Node running pcd"]
  subgraph locs ["Storage locations"]
    direction LR
    dir[("Directory")]
    s3[("S3 bucket")]
    nd[("Node disk")]
  end
  pcctl -->|"--repo: encrypted blobs"| locs
  pcctl -->|"mutual TLS"| node
  node -->|"--via: relays blobs"| locs
```

[pcctl command reference](https://powercloud.unidatum.com/docs/pcctl.md) is the full command reference.

## The mesh

Enrolled nodes connect to each other over an encrypted **mesh** of kernel WireGuard tunnels, on UDP port 51820.

- **Addresses come from identity.** Each node's mesh address is a private IPv6 address made from the cluster ID and the node ID, so there is nothing to allocate.
- **Peers are distributed automatically.** A **membership list**, signed by the cluster CA, names every node with its WireGuard key and **endpoint** (the public `IP:PORT` where peers can reach it). `pcctl` publishes a new list whenever a node is added or removed, and nodes pass newer lists on to each other, so a node that was offline catches up from any peer.
- **NAT traversal.** Nodes behind NAT find each other's public address through a node both can reach and connect directly. When their NATs prevent that (symmetric NAT), they connect through a **relay**: a public node that forwards their WireGuard packets, which it cannot read.
- **Authenticated twice.** Inside the tunnel, nodes still call each other's API with their node certificates.

`pcctl node info NAME` shows each peer's handshake age and whether its API answers over the mesh.

## Apps

Nodes run services you deploy, called **apps**: static Linux binaries or container images from a registry.

- **Apps on one node** (`pcctl app deploy NODE NAME ...`): each runs in a sandbox (chrooted on the node's encrypted disk, as its own user, in its own namespaces and cgroup with memory, CPU and process limits, under a seccomp filter, with its own network reached only through ports it publishes), and is restarted when it exits. With `--vm`, an app runs in a **microVM** with a kernel of its own. See [Apps on a node](https://powercloud.unidatum.com/docs/apps.md).
- **Cluster apps** (`pcctl --repo ... cluster app deploy ...`): you publish the app for the whole cluster, and the nodes decide among themselves where it runs, starting it elsewhere when a node goes away. See [Cluster apps](https://powercloud.unidatum.com/docs/cluster-apps.md).

## Consensus

For state the nodes must agree on themselves, such as which node runs an exclusive app or the marks that detect a provider rolling back an object, the nodes form a Raft group: `pcctl --repo ... consensus init`, once. It keeps working while a majority of its voters are up. See [Cluster apps](https://powercloud.unidatum.com/docs/cluster-apps.md) and [Storage](https://powercloud.unidatum.com/docs/storage.md).

## Glossary

| Term | Meaning |
|---|---|
| **Admin certificate** | A 30-day client certificate from the cluster CA, kept in pcctl's configuration directory, that lets you manage nodes without the passphrase. |
| **Attestation** | A report signed by the CPU (AMD SEV-SNP) proving a VM's memory is encrypted; pcctl checks it before giving such a node its disk key. |
| **Cluster** | One root key, the store it encrypts, and the nodes enrolled with its CA. |
| **Cluster app** | An app published for the whole cluster, which the nodes place and move among themselves. |
| **Cluster CA** | The certificate authority whose key is derived from the root key; it signs node and admin certificates and every document nodes accept. |
| **Consensus** | The nodes' Raft group, which keeps a key-value state they agree on while a majority is up. |
| **Endpoint** | Where peers reach a node's WireGuard port, as `IP:PORT` or `HOST:PORT`. |
| **Enrollment code** | The one-time code a new node shows on its console: a fingerprint of its key plus a secret, used by `pcctl node enroll`. |
| **Join bundle** | A file from `pcctl node provision` holding a node's whole identity, given to a machine as cloud user data or a QEMU fw_cfg file so it joins unattended. |
| **Key header** | The one unencrypted blob at each location: the keyslots that wrap the root key, holding no plaintext key. |
| **Location** | One place the store is kept: a directory, an S3-compatible bucket, a node's disk (`node://NAME`) or an erasure-coded set (`ec:K:...`). |
| **Membership list** | The CA-signed list of nodes with their WireGuard keys and endpoints, passed between nodes. |
| **Mesh** | The WireGuard network between a cluster's nodes, with addresses derived from node identity. |
| **MicroVM** | A small virtual machine with its own kernel that an app can run in (`--vm`), for a stronger boundary than the shared-kernel sandbox. |
| **Node** | A machine running PowerCloud OS, enrolled in a cluster. |
| **Node API** | The mutual-TLS API `pcd` serves on TCP 7443, used by pcctl and by peers. |
| **pcctl** | The command-line tool that manages a cluster from your own computer. |
| **pcd** | The node daemon: identity, enrollment, unlock, mesh, storage and apps. |
| **Quorum** | How many locations must accept a write for it to succeed; by default a majority (`--quorum N` overrides it). |
| **Recovery key** | A 160-bit key printed once at `pcctl init` (and at `pcctl rotate`) that unlocks the cluster without the passphrase. |
| **Registry** | The cluster's record of its nodes, kept in the encrypted store. |
| **Relay** | A public node that forwards WireGuard packets between two nodes whose NATs block a direct connection; it sees only ciphertext. |
| **Release** | A CA-signed set of node images that nodes roll out themselves, one at a time; a PowerCloud release is also the set of downloadable files named `vYYYY.MM.DD`. See [Upgrades and releases](https://powercloud.unidatum.com/docs/upgrades.md). |
| **Repository** | All of a cluster's storage locations together, given with `--repo` or `POWERCLOUD_REPO`. |
| **Revocation list** | The CA-signed list of removed nodes and revoked admin certificates, enforced by every node. |
| **Root key** | The cluster's 256-bit master key, from which every other key is derived; never stored in plaintext. |
| **State volume** | The encrypted, integrity-checked partition where a node keeps its identity and state; locked after each reboot until unlocked. |
| **Trusted node** | A node that may hold keys and run apps: your own hardware or an attested confidential VM. |
| **Unlock code** | The code a locked node shows on its console after a reboot, used by `pcctl node unlock`. |
| **Untrusted** | A bucket or plain VM that may only store or relay ciphertext. |
