# uvm `uvm` is a small, local Firecracker microVM command-line manager for Ubuntu. It creates one Firecracker process per VM, attaches it to a host TAP device, and persists enough state to list, stop, and destroy the VM later. This directory is a self-contained project. All UVM code, tests, packaging metadata, launcher scripts, and documentation live here. For architecture, lifecycle invariants, extension guidance, and contributor workflows, see [DEVELOPER.md](DEVELOPER.md). For end-to-end operator scenarios, CLI examples, and HTTP API calls, see [USAGE.md](USAGE.md). ## Quick Start From the parent repository directory, run commands from this project root: ```sh cd uvm ./uvm.py --help python3 -m uvm --help ``` The `pyproject.toml` file also defines an installable `uvm` console command. The project is an application, not a reusable Python SDK. ## Requirements - Ubuntu or another compatible Linux host - Python 3.12 or newer - Root access for UVM commands that read or mutate the protected VM registry - KVM enabled and accessible at `/dev/kvm` - An x86_64 host for the default guest assets - Working host networking, `iproute2`, `iptables`, `e2fsprogs`, `openssl`, and `openssh-client` `uvm install` installs the required host packages. It validates `/dev/kvm` before downloading or launching a microVM. ## Trusted Installation Installation requires trusted SHA-256 digests by default. Supply digests from an independently trusted source before running the privileged installer: ```sh cd uvm sudo env \ UVM_FIRECRACKER_SHA256='' \ UVM_KERNEL_SHA256='' \ UVM_ROOTFS_SHA256='' \ ./uvm.py install ``` Use `--force` to redownload Firecracker and guest assets when replacing an image or refreshing artifacts: ```sh sudo env \ UVM_FIRECRACKER_SHA256='' \ UVM_KERNEL_SHA256='' \ UVM_ROOTFS_SHA256='' \ ./uvm.py install --force ``` For local experimentation only, the old unverified quick-start behavior is available through an explicit opt-out: ```sh sudo env UVM_ALLOW_UNVERIFIED_DOWNLOADS=1 ./uvm.py install ``` An unverified install is recorded as such and cannot satisfy a later strict run. Reinstall with trusted digests to establish a verified local manifest. To create VMs from an unverified local-development install, retain `UVM_ALLOW_UNVERIFIED_DOWNLOADS=1` on later `create` commands and on the API server process. ## Commands ```sh # Install after supplying the trusted checksum variables shown above. # A bare `install` command fails under the default strict integrity policy. # Create and boot a VM with the defaults: 1 CPU, 512 MiB RAM, and root/root. sudo ./uvm.py create # Request CPU and RAM explicitly. RAM defaults to MiB; B/K/M/G suffixes work. sudo ./uvm.py create --cpu 1 --ram 1G # Set credentials for an account that already exists in the guest image. sudo ./uvm.py create --username root --password '' # Select the guest IP. Despite the legacy flag name, this is the guest IP. sudo ./uvm.py create --host-ip 10.42.0.10 # Show persisted VM state and observed process status. sudo ./uvm.py list # Connect over SSH by VM ID or guest IP. sudo ./uvm.py ssh vm- ssh root@10.42.0.10 # Stop or remove a VM. sudo ./uvm.py stop vm- sudo ./uvm.py destroy vm- ``` SSH uses `StrictHostKeyChecking=accept-new` and a VM-ID-specific host-key alias by default. `--insecure-host-key` restores the old no-verification behavior for a single connection. ## Management API Install the project dependencies before serving the API: ```sh cd uvm python3 -m pip install . ``` Launch the FastAPI management server with the requested CLI form: ```sh cd uvm export UVM_API_TOKEN='replace-with-a-long-random-secret' sudo env UVM_API_TOKEN="$UVM_API_TOKEN" \ uvm --serve --host 127.0.0.1 --port 8000 # Equivalent when running the source checkout directly. sudo env UVM_API_TOKEN="$UVM_API_TOKEN" \ ./uvm.py --serve --host 127.0.0.1 --port 8000 ``` The default bind address is `127.0.0.1` and the default port is `8000`. OpenAPI documentation is available at `/docs` once the server is running. The server exposes these routes: | Method | Route | Purpose | |---|---|---| | `GET` | `/health` | Unauthenticated liveness response | | `POST` | `/install` | Install or refresh host assets; body: `{ "force": false }` | | `GET` | `/vms` | List VM records and observed status | | `POST` | `/vms` | Create a VM; body supports `cpu`, `ram`, `guest_ip`, `username`, and `password` | | `GET` | `/vms/{id-or-ip}` | Retrieve one VM by ID or guest IP | | `POST` | `/vms/{id}/stop` | Stop a VM while retaining its private disk | | `DELETE` | `/vms/{id}` | Destroy a VM and release its resources | The API intentionally does not proxy interactive SSH. Use the returned guest IP with `uvm ssh` or a normal SSH client. ### API Security The server controls privileged host operations. `UVM_API_TOKEN` is required for every API server, including loopback-only deployments. All management routes require it in the `X-UVM-Token` header. FastAPI's informational `/docs`, `/redoc`, and `/openapi.json` endpoints do not require a token. A non-loopback bind additionally requires TLS certificate and key paths: ```sh export UVM_API_TOKEN='replace-with-a-long-random-secret' export UVM_API_TLS_CERT='/etc/uvm/api-cert.pem' export UVM_API_TLS_KEY='/etc/uvm/api-key.pem' sudo env \ UVM_API_TOKEN="$UVM_API_TOKEN" \ UVM_API_TLS_CERT="$UVM_API_TLS_CERT" \ UVM_API_TLS_KEY="$UVM_API_TLS_KEY" \ ./uvm.py --serve --host 0.0.0.0 --port 8000 ``` Send the token on management requests: ```sh curl \ -H "X-UVM-Token: $UVM_API_TOKEN" \ http://127.0.0.1:8000/vms ``` Do not expose this server directly to an untrusted network. For remote access, keep TLS enabled and consider placing it behind an additional authenticated reverse proxy. ## Guest Image Contract The installed kernel and rootfs are templates. `create` copies the rootfs to the VM runtime directory before Firecracker opens it read-write, so VMs do not share a mutable root disk. During creation, UVM updates the private ext4 disk with a password for an existing guest account and enables OpenSSH password authentication. The defaults are username `root` and password `root`. A custom image must provide: - `sshd` - `/etc/passwd`, `/etc/shadow`, and `/etc/ssh/sshd_config` - The requested user account; UVM does not create missing users The known public demo key bundled in Firecracker's default bionic image is removed from each private disk. UVM also replaces the conventional RSA, ECDSA, and Ed25519 SSH host keys in every private disk so cloned VMs have distinct host identities. Never rely on SSH private keys baked into a shared template. ## Host Networking By default, UVM manages: ```text Network: 10.42.0.0/24 Gateway: 10.42.0.1 Bridge: uvm0 TAPs: uvm- ``` It creates the bridge when absent, validates an existing bridge before using it, enables IPv4 forwarding, adds an egress masquerade rule, and adds matching forward rules for return traffic. Guest IPs, gateway, bridge name, and guest boot netmask derive from the configured CIDR. ## Persistent State The default data directory is `/var/lib/uvm`: ```text /var/lib/uvm/ ├── bin/ # Firecracker and Jailer binaries ├── images/ # Kernel and rootfs templates ├── vms// # Per-VM disk, config, log, and API socket ├── integrity.json # Download/build checksums and verification provenance └── state.json # Root-only VM inventory and guest credentials ``` State writes are locked and atomic. Lifecycle operations share an additional operation lock so concurrent `create`, `stop`, `destroy`, and `install` commands cannot overwrite each other's state or binaries. The registry stores guest usernames and passwords in plaintext, so `state.json` is mode `0600`. Treat it as a secret, do not include it in bug reports, and replace the default `root` password immediately. Credential provisioning applies only to VMs created by this version. Existing VM disks are not modified automatically. ## Configuration All optional configuration is supplied through environment variables: | Variable | Purpose | |---|---| | `UVM_BASE` | Data directory; defaults to `/var/lib/uvm` | | `UVM_NETWORK` | Guest IPv4 CIDR; defaults to `10.42.0.0/24` | | `UVM_GATEWAY` | Bridge/guest gateway; defaults to `10.42.0.1` | | `UVM_BRIDGE` | Linux bridge name; defaults to `uvm0` | | `UVM_KERNEL_URL` | Guest kernel download URL | | `UVM_ROOTFS_URL` | Guest rootfs download URL | | `UVM_FIRECRACKER_SHA256` | Trusted Firecracker release archive SHA-256 | | `UVM_KERNEL_SHA256` | Trusted guest kernel SHA-256 | | `UVM_ROOTFS_SHA256` | Trusted guest rootfs SHA-256 | | `UVM_FIRECRACKER_BINARY_SHA256` | Optional trusted local Firecracker binary SHA-256 | | `UVM_ALLOW_UNVERIFIED_DOWNLOADS` | Set to `1` only for unverified local development | | `UVM_API_TOKEN` | Required for every API server; sent as `X-UVM-Token` | | `UVM_API_TLS_CERT` | TLS certificate path required for a non-loopback API bind | | `UVM_API_TLS_KEY` | TLS private-key path required for a non-loopback API bind | ## Project Layout ```text uvm/ ├── README.md ├── pyproject.toml ├── uvm.py # Executable compatibility launcher ├── uvm/ # Private application implementation │ ├── cli.py # argparse, terminal output, SSH execution │ ├── app.py # Application composition root │ ├── api_models.py # FastAPI request and response models │ ├── config.py # Settings and filesystem layout │ ├── domain.py # Typed VM and state models │ ├── errors.py # Expected application failures │ ├── integrity.py # Checksums and manifest provenance │ ├── install.py # Host/artifact installation │ ├── images.py # Guest templates and per-VM disks │ ├── lifecycle.py # Create/list/stop/destroy orchestration │ ├── network.py # IP/MAC/TAP/bridge/NAT management │ ├── routers/ # Health, installation, and VM HTTP routers │ ├── server.py # FastAPI application factory and Uvicorn launcher │ ├── state.py # Locked atomic JSON persistence │ ├── system.py # Host command and KVM adapters │ └── firecracker/ # Firecracker config, API, and process adapters └── tests/ # Unit tests with mocked host boundaries ``` ## Testing From the parent repository directory, run the unit suite from this project root: ```sh cd uvm python3 -m pip install '.[test]' PYTHONDONTWRITEBYTECODE=1 python3 -B -m unittest discover -s tests -v ``` The unit tests do not need root, KVM, Firecracker, or host network changes. They cover validation, state migration and locking, integrity manifests, network command rendering, Firecracker request ordering, process safety, and lifecycle rollback. API route tests run automatically when the FastAPI and `httpx` test dependencies are installed. ## Current Boundaries - Fractional CPU requests still round Firecracker vCPUs up and are advisory. - `stop` retains the private VM disk; the current command surface does not yet include a separate `start` command. - Firecracker is launched directly by this local CLI. Jailer/cgroup hardening is not implemented by the current command set. - Run real KVM, TAP, and guest-connectivity checks on an isolated Linux host before relying on UVM for workloads.