Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
169 changes: 156 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,27 +12,51 @@ A from-scratch Linux distribution built on two commitments:
Kryptik is built from source via Linux From Scratch, with no upstream distro
base. Its binaries carry their own target triple:

```
```text
$ sysroot/usr/bin/bash --version
GNU bash, version 5.2.32(1)-release (x86_64-kryptik-linux-gnu)
```

## Status

Pre-alpha. The build produces a hardened kernel with the linux-hardened
patchset; install media (a USB image and an ISO) that boot by UEFI firmware
alone; an installer; an installed system that verifies its root with
dm-verity on every boot and keeps its state on an encrypted partition; A/B
updates with a judged trial boot and recovery from the medium; and a zoned
Wayland desktop. `make acceptance` runs every suite against the built images.
A pre-release, v0.1.0, is on the repository's Releases page. The build
produces a hardened kernel with the linux-hardened patchset; install media (a
USB image and an ISO) that boot by UEFI firmware alone; an installer; an
installed system that verifies its root with dm-verity on every boot and
keeps its state on an encrypted partition; A/B updates with a judged trial
boot and recovery from the medium; and a zoned Wayland desktop.
`make acceptance` runs every suite against the built images, and a release
is cut only from a run in which every suite passed.

What is tested, and what the last acceptance run proved, is in
[docs/status.md](docs/status.md). Everything so far has run under QEMU with
OVMF firmware; nothing has run on physical hardware, and releases are signed
by a key the build generates. Releases are on the repository's Releases
page: what one is, how it is numbered and how to check a download is in
OVMF firmware; nothing has run on physical hardware, and every release so far
is signed by keys the build generated. What a release is, how it is numbered
and how a production release will differ is in
[docs/releases.md](docs/releases.md).

## Get it

From the Releases page take the medium, its signed checksums and the anchor:
`kryptik-VERSION-usb.img.zst` (or `kryptik-VERSION.iso.zst`),
`kryptik-VERSION.SHA256SUMS` with its `.sig`, and `release-signers`. Check
the download, then write it to a USB stick:

```sh
zstd -d kryptik-VERSION-usb.img.zst
ssh-keygen -Y verify -f release-signers -I kryptik-release -n kryptik-media \
-s kryptik-VERSION.SHA256SUMS.sig < kryptik-VERSION.SHA256SUMS
sha256sum -c --ignore-missing kryptik-VERSION.SHA256SUMS
sudo dd if=kryptik-VERSION-usb.img of=/dev/sdX bs=4M status=progress oflag=sync
```

The anchor comes with the download, so this proves the files belong together,
not who made them; a production release's anchor will be the one made
offline. Boot with Secure Boot off, or enrol `kryptik-sb.der` from the same
page in the firmware first. Installing, the first boot, daily use, updating
and recovery are in the [user guide](docs/user-guide.md), which every release
also ships as `INSTRUCTIONS.md`.

## Hardware

x86-64 with UEFI firmware. There is no initramfs, so the storage controller
Expand Down Expand Up @@ -67,12 +91,126 @@ A machine outside that list boots a kernel that cannot find its disk or its
network. Adding a driver is one line in the fragment, a firmware file one line
in the list.

## How it fits together

```mermaid
flowchart TD

subgraph group_zone_runtime["Zone runtime (kryptikd)"]
node_daemon["Zone daemon<br/>[main.rs]"]
node_policy["Zone policy<br/>[policy.rs]"]
node_registry["Zone registry<br/>[registry.rs]"]
node_rootfs["Zone filesystem<br/>[rootfs.rs]"]
node_files["Zone files<br/>[files.rs]"]
node_cgroup["Resource limits<br/>[cgroup.rs]"]
node_caps["Capabilities<br/>[caps.rs]"]
node_landlock["Filesystem rules<br/>[landlock.rs]"]
node_seccomp["Syscall filter<br/>[seccomp.rs]"]
node_isolate["Namespace setup<br/>[isolate.rs]"]
node_spawn["Zone process<br/>[spawn.rs]"]
node_volume[("Encrypted volumes<br/>[volume.rs]")]
end

subgraph group_desktop["Desktop isolation"]
node_launch["Desktop launcher<br/>[kryptik-launch.c]"]
node_wlproxy["Wayland proxy<br/>[kryptik-wlproxy]"]
node_session["Protocol session<br/>[session.rs]"]
node_protocol["Protocol tables<br/>[protocol.rs]"]
node_wire["Wire framing<br/>[wire.rs]"]
node_identity["Zone colour identity<br/>[identity.rs]"]
node_palette["Colour palette<br/>[palette.rs]"]
end

subgraph group_services["Zone services"]
node_broker["Transfer broker<br/>[broker.rs]"]
node_consent["Transfer consent<br/>[consent.rs]"]
node_update["Update mediation<br/>[update.rs]"]
node_fetch["Update fetcher<br/>[update-fetch.py]"]
node_network["Network zones<br/>[netzone.rs]"]
node_wifi["Wi-Fi control<br/>[wifi.rs]"]
end

subgraph group_boot["Boot and updates"]
node_apply["Update apply<br/>[kryptik-update]"]
node_efiboot["EFI boot entries<br/>[kryptik-efiboot.c]"]
end

node_user(("User"))
node_wayland_client(("Zone application"))
node_compositor(("Wayland compositor"))
node_channel(("Update channel"))

node_user -->|"launches"| node_launch
node_launch -->|"sends request"| node_daemon
node_daemon -->|"loads policy"| node_policy
node_daemon -->|"checks zone"| node_registry
node_daemon -->|"prepares root"| node_rootfs
node_daemon -->|"sets up files"| node_files
node_daemon -->|"limits resources"| node_cgroup
node_daemon -->|"sets capabilities"| node_caps
node_daemon -->|"sets filesystem rules"| node_landlock
node_daemon -->|"installs filter"| node_seccomp
node_daemon -->|"creates namespaces"| node_isolate
node_daemon -->|"manages storage"| node_volume
node_daemon -->|"starts process"| node_spawn
node_launch -->|"starts proxy"| node_wlproxy
node_wayland_client -->|"connects"| node_wlproxy
node_wlproxy -->|"creates session"| node_session
node_session -->|"checks messages"| node_protocol
node_session -->|"frames messages"| node_wire
node_session -->|"forwards allowed traffic"| node_compositor
node_compositor -->|"returns events"| node_session
node_session -->|"forwards events"| node_wayland_client
node_daemon -->|"serves broker"| node_broker
node_broker -->|"requests approval"| node_consent
node_launch -->|"requests clipboard move"| node_broker
node_fetch -->|"fetches release data"| node_channel
node_fetch -->|"submits update data"| node_broker
node_broker -->|"dispatches update requests"| node_update
node_update -->|"stages a checked release for"| node_apply
node_apply -->|"arms the trial boot"| node_efiboot
node_launch -->|"requests Wi-Fi action"| node_wifi
node_wifi -->|"controls radio zone"| node_network
node_identity -->|"uses colours"| node_palette

classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
class node_daemon,node_policy,node_registry,node_rootfs,node_files,node_cgroup,node_caps,node_landlock,node_seccomp,node_isolate,node_spawn,node_volume,node_user toneBlue
class node_launch,node_wlproxy,node_session,node_protocol,node_wire,node_identity,node_palette toneAmber
class node_broker,node_consent,node_update,node_fetch,node_network,node_wifi toneMint
class node_apply,node_efiboot toneRose
class node_wayland_client,node_compositor,node_channel toneIndigo
```

Each box names its file: the zone runtime and the zone services are
`compartments/kryptikd/src/`, the proxy `compositor/wlproxy/src/`, the colour
identity `compositor/zoneid/src/`, the launcher `tools/desktop/`, the fetcher
`tools/net/`, the update tools `tools/update/` and `tools/efi/`.

Zone 0 is the trusted base: PID 1, the services, kryptikd, the compositor and
the desktop session, with no route out and no user applications. Every
application runs in a zone that kryptikd creates as root from the zone's
policy: its own namespaces and root, Landlock rules, a seccomp filter, cgroup
limits, and a LUKS2 volume if the zone keeps state. A zone's windows reach
the compositor only through the zone's own `kryptik-wlproxy`, which passes
the protocol it knows and refuses the rest; the compositor draws the zone's
colour, and the trusted chrome names it. Files and clipboards cross zones
only through the broker, after the user answers its question. The net zone
alone holds the wire and the radio: it fetches releases, and zone 0 stages
what it hands over through that same broker before `kryptik update apply`
writes the other slot and arms one trial boot. The whole model is in
[docs/architecture.md](docs/architecture.md); the boundary of any one zone
is what `kryptikd explain <zone>` prints.

## What a zone does

`kryptik` is the command; `kryptikd` is what it calls. A zone has its own pid
namespace and hostname, and sees four processes where the host has 142:

```
```text
$ kryptik run untrusted -- /bin/sh -c \
'echo pid=$$; echo host=$(hostname); echo procs=$(ls /proc | grep -c "^[0-9]*$")'
kryptikd: zone "untrusted": ephemeral storage is a tmpfs freed on exit; its pages can reach swap, so this is not secure erasure
Expand Down Expand Up @@ -110,7 +248,7 @@ The tradeoff is spelled out in [docs/threat-model.md](docs/threat-model.md).

## Repository layout

```
```text
build/
stages/ Ordered build stages (00-host-check → 06-iso)
recipes/ One file per stage 04 step, sourced by 04-base-system.sh
Expand Down Expand Up @@ -147,7 +285,9 @@ docs/ Architecture, threat model, decisions, status
The `Distro` workflow (`.github/workflows/distro.yml`) builds and tests
everything on GitHub's runners: stages 01–02, then stages 04–06, then
`make acceptance` under KVM, uploading the acceptance report and the tested
images. To build locally, on Linux:
images. A tag `v<version>` builds that version from nothing and, for a
development release, drafts it on the Releases page. To build locally, on
Linux:

```sh
make check # what the host is missing
Expand All @@ -166,6 +306,8 @@ make acceptance EXPORT=DIR # every suite on the newest media; root and KVM

Host setup: [docs/building.md](docs/building.md). Booting, installing,
updating and recovering a release: [docs/user-guide.md](docs/user-guide.md).
A production release, signed with keys made offline:
[docs/release-keys.md](docs/release-keys.md).

## Documentation

Expand All @@ -176,6 +318,7 @@ updating and recovering a release: [docs/user-guide.md](docs/user-guide.md).
- [Supply chain](docs/supply-chain.md): source integrity and its gaps
- [Status](docs/status.md): what is tested and what the last run proved
- [Roadmap](docs/roadmap.md): what remains for 1.0 and 2.0
- [Releases](docs/releases.md): what a release is, how it is numbered, how to check a download
- [Building](docs/building.md) and the [user guide](docs/user-guide.md)
- [Release keys](docs/release-keys.md): making, keeping, using and replacing the keys that sign releases

Expand Down
Loading