diff --git a/README.md b/README.md index b6b703c1..df398271 100644 --- a/README.md +++ b/README.md @@ -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 @@ -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
[main.rs]"] + node_policy["Zone policy
[policy.rs]"] + node_registry["Zone registry
[registry.rs]"] + node_rootfs["Zone filesystem
[rootfs.rs]"] + node_files["Zone files
[files.rs]"] + node_cgroup["Resource limits
[cgroup.rs]"] + node_caps["Capabilities
[caps.rs]"] + node_landlock["Filesystem rules
[landlock.rs]"] + node_seccomp["Syscall filter
[seccomp.rs]"] + node_isolate["Namespace setup
[isolate.rs]"] + node_spawn["Zone process
[spawn.rs]"] + node_volume[("Encrypted volumes
[volume.rs]")] +end + +subgraph group_desktop["Desktop isolation"] + node_launch["Desktop launcher
[kryptik-launch.c]"] + node_wlproxy["Wayland proxy
[kryptik-wlproxy]"] + node_session["Protocol session
[session.rs]"] + node_protocol["Protocol tables
[protocol.rs]"] + node_wire["Wire framing
[wire.rs]"] + node_identity["Zone colour identity
[identity.rs]"] + node_palette["Colour palette
[palette.rs]"] +end + +subgraph group_services["Zone services"] + node_broker["Transfer broker
[broker.rs]"] + node_consent["Transfer consent
[consent.rs]"] + node_update["Update mediation
[update.rs]"] + node_fetch["Update fetcher
[update-fetch.py]"] + node_network["Network zones
[netzone.rs]"] + node_wifi["Wi-Fi control
[wifi.rs]"] +end + +subgraph group_boot["Boot and updates"] + node_apply["Update apply
[kryptik-update]"] + node_efiboot["EFI boot entries
[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 ` 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 @@ -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 @@ -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` 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 @@ -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 @@ -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