Security Model
Volt implements defense-in-depth using Linux-native security primitives. Every workload runs under multiple isolation layers — Landlock LSM for filesystem access control, seccomp for syscall filtering, Linux capabilities for privilege restriction, and kernel namespaces for resource isolation. No third-party security agents. No daemon-level trust. Just the kernel.
Defense in Depth
┌─────────────────────────────────────────────────────────────────┐
│ Workload Process │
└──────────────────────────┬──────────────────────────────────────┘
│
┌────────────────┼────────────────┐
│ │ │
┌──────▼──────┐ ┌─────▼──────┐ ┌──────▼──────┐
│ Landlock │ │ Seccomp │ │ Capabilities│
│ LSM rules │ │ BPF filter│ │ drop ALL │
│ per-path │ │ per-call │ │ grant few │
└──────┬──────┘ └─────┬──────┘ └──────┬──────┘
│ │ │
┌──────▼────────────────▼────────────────▼──────┐
│ Kernel Namespaces │
│ PID · Mount · Net · User · UTS · IPC │
└───────────────────────┬───────────────────────┘
│
┌───────────────────────▼───────────────────────┐
│ cgroups v2 │
│ CPU · Memory · I/O · PIDs limits │
└───────────────────────┬───────────────────────┘
│
┌───────────────────────▼───────────────────────┐
│ Linux Kernel │
│ systemd-nspawn · KVM · nftables │
└───────────────────────────────────────────────┘
Each layer is independent. Compromising one does not disable the others. A workload that escapes its namespace still faces Landlock restrictions, seccomp filters, and dropped capabilities.
Landlock LSM — Filesystem Access Control
Volt uses Landlock LSM as its primary mandatory access control framework. Landlock is a stackable Linux Security Module available since kernel 5.13 that allows unprivileged processes to restrict their own filesystem access — no root configuration required.
Unlike kernel-module-based MACs, Landlock is built into the Linux kernel, requires no policy daemon, and can be applied per-workload without system-wide configuration. It aligns with Volt's philosophy: use what the kernel provides, add nothing extra.
How Volt Uses Landlock
Every Voltainer container and Voltvisor VM gets a Landlock ruleset applied at launch. Profiles are defined in /etc/volt/profiles/:
# Apply a Landlock profile to a container
sudo volt container create myapp --landlock webserver
# Inspect active Landlock rules
sudo volt security inspect myapp --landlock
# Create a custom Landlock profile
sudo volt security profile create my-profile \
--allow-read /app,/usr/lib \
--allow-write /tmp,/var/log/app \
--deny-execute /tmp
Landlock Rulesets
| Access Right | Description | Default |
|---|---|---|
LANDLOCK_ACCESS_FS_READ_FILE | Read file contents | Allowed (select paths) |
LANDLOCK_ACCESS_FS_WRITE_FILE | Write to files | Denied (except /tmp) |
LANDLOCK_ACCESS_FS_EXECUTE | Execute files | Allowed (select paths) |
LANDLOCK_ACCESS_FS_READ_DIR | List directory contents | Allowed (select paths) |
LANDLOCK_ACCESS_FS_MAKE_REG | Create regular files | Denied (except /tmp) |
Seccomp — Syscall Filtering
Volt applies seccomp-BPF (Berkeley Packet Filter) profiles to every workload, restricting which system calls the process can invoke. This reduces the kernel attack surface available to compromised workloads.
Built-in Profiles
| Profile | Syscalls Blocked | Use Case |
|---|---|---|
strict.json |
~200 blocked, ~60 allowed | Stateless web services, static content |
default-plus-networking.json |
~150 blocked, ~110 allowed | Network services, databases |
permissive.json |
~50 blocked (dangerous only) | Development, debugging |
# Apply a seccomp profile at creation
sudo volt container create myapp --seccomp strict
# Inspect active seccomp filters
sudo volt security inspect myapp --seccomp
# Audit mode — log violations without killing
sudo volt container create myapp --seccomp strict --seccomp-audit
Dangerous Syscalls Always Blocked
Regardless of profile, these syscalls are always filtered:
kexec_load/kexec_file_load— loading a new kernelreboot— system reboot from within containersmount/umount2— filesystem mount/unmount (unless explicitly allowed)ptrace— process tracing (unless debugging profile)init_module/finit_module— kernel module loadingswapon/swapoff— swap manipulation
Linux Capabilities — Minimal Privilege
Volt drops all Linux capabilities by default and adds back only what each workload needs. This follows the principle of least privilege — a web server doesn't need CAP_SYS_ADMIN.
Default Capability Sets
| Workload Type | Capabilities Granted | Everything Else |
|---|---|---|
| Web server | NET_BIND_SERVICE |
Dropped |
| Database | DAC_OVERRIDE, CHOWN, FOWNER |
Dropped |
| Network service | NET_BIND_SERVICE, NET_RAW |
Dropped |
| Minimal (default) | None | All dropped |
# Create with specific capabilities
sudo volt container create myapp \
--cap-add NET_BIND_SERVICE \
--cap-add CHOWN
# Inspect granted capabilities
sudo volt security inspect myapp --capabilities
# Drop all capabilities (already default, but explicit)
sudo volt container create myapp --cap-drop ALL
Capability restrictions are passed directly to systemd-nspawn via --capability= and --drop-capability= flags in the generated .nspawn configuration files.
Namespace Isolation
Every Voltainer container runs in its own set of Linux kernel namespaces, providing complete process, network, and filesystem isolation from the host and other containers.
Namespace Types
| Namespace | Isolates | Effect |
|---|---|---|
| PID | Process IDs | Container sees only its own processes; PID 1 is the container init |
| Mount | Filesystem mounts | Container has its own mount tree; host mounts invisible |
| Network | Network stack | Container gets its own interfaces, IP addresses, routing table |
| User | UID/GID mappings | Root inside container maps to unprivileged user on host |
| UTS | Hostname | Container can set its own hostname without affecting host |
| IPC | Inter-process communication | Shared memory, semaphores, message queues isolated per container |
# Inspect namespace configuration
sudo volt security inspect myapp --namespaces
# Verify PID isolation — container only sees its own processes
sudo volt container exec myapp -- ps aux
# User namespace mapping — root inside is nobody outside
sudo volt container exec myapp -- id
# uid=0(root) inside → uid=65534(nobody) on host
User Namespace UID Mapping
Volt uses systemd-nspawn's --private-users= to map UIDs inside the container to unprivileged ranges on the host:
Container UIDs Host UIDs
───────────── ─────────
0 (root) → 65536 (unprivileged)
1 (daemon) → 65537
1000 (user) → 66536
... ...
Even if a process escapes the container as "root",
it's UID 65536 on the host — no privileges.
CAS Integrity — Stellarium Verification
Stellarium, Volt's content-addressed storage system, provides cryptographic integrity guarantees for all stored images and blobs. Every object is stored by its SHA256 hash — if the content changes, the address changes.
Integrity Guarantees
- Tamper detection: Any modification to a stored blob changes its SHA256 hash, causing immediate verification failure
- Immutable objects: Once written, CAS objects are never modified — only new versions are created
- Deduplication: Identical content across workloads is stored once, reducing attack surface from duplicated vulnerable binaries
- Manifest verification: Refs (manifests) map human-readable names to verified SHA256 hashes
# Verify integrity of all CAS objects
sudo volt cas verify
# ✓ 1,247 objects verified, 0 corrupted
# Verify a specific image
sudo volt cas verify --ref myapp-v2
# Show hash chain for a reference
sudo volt cas inspect myapp-v2 --show-hashes
Because CAS stores content by hash, you can verify that the exact image you audited is the exact image running in production. Hash the running rootfs and compare against the CAS ref — any difference means the image was modified.
Network Isolation — volt-net Bridge
Volt isolates container networking using volt-net bridge interfaces managed through nftables. Each workload gets its own virtual ethernet pair, and inter-container traffic is denied by default.
Network Architecture
┌────────────┐ ┌────────────┐ ┌────────────┐
│ Container A│ │ Container B│ │ Container C│
│ 10.42.0.2 │ │ 10.42.0.3 │ │ 10.42.1.2 │
└──────┬─────┘ └──────┬─────┘ └──────┬─────┘
veth-a veth-b veth-c
│ │ │
┌────▼────────────────▼───┐ ┌───────▼───────┐
│ volt-net0 bridge │ │ volt-net1 │
│ 10.42.0.0/24 │ │ 10.42.1.0/24 │
└────────────┬────────────┘ └───────┬───────┘
│ │
┌────────────▼────────────────────────▼───────┐
│ nftables firewall │
│ Per-workload ingress/egress rules │
│ Default: deny inter-bridge traffic │
└─────────────────────┬──────────────────────┘
│
Host network
Network Policies
# Isolate a container — no network access
sudo volt container create myapp --network none
# Allow specific inter-container communication
sudo volt network policy create \
--from web --to db --port 5432 --protocol tcp --action allow
# List active network policies
sudo volt network policy list
# Inspect firewall rules for a workload
sudo volt security inspect myapp --firewall
Resource Limits — cgroups v2
Volt uses cgroups v2 (unified hierarchy) to enforce hard resource limits on every workload. This prevents resource exhaustion attacks and noisy-neighbor problems.
Enforced Limits
| Resource | Controller | Default | Configurable |
|---|---|---|---|
| CPU | cpu.max |
No limit (fair share) | --cpu-limit 200% |
| Memory | memory.max |
512 MiB | --memory 2G |
| Memory (swap) | memory.swap.max |
0 (no swap) | --memory-swap 1G |
| I/O bandwidth | io.max |
No limit | --io-limit 50M |
| PIDs | pids.max |
256 | --pids-limit 1024 |
# Create with resource limits
sudo volt container create myapp \
--memory 1G \
--cpu-limit 100% \
--pids-limit 512
# Update limits on a running workload
sudo volt container update myapp --memory 2G
# Monitor resource usage
sudo volt ps --resources
sudo volt monitor myapp
When a container exceeds its memory limit, the kernel's OOM killer terminates processes within that container's cgroup — not processes from other containers or the host. Isolation is maintained even during resource exhaustion.
Neutron Stardust — microVM Isolation
For workloads requiring hardware-level isolation beyond containers, Voltvisor uses Neutron Stardust as its microVMM. Neutron Stardust provides lightweight KVM-based virtual machines with minimal attack surface — a purpose-built VMM with only the devices and emulation needed for the workload.
microVM Security Properties
- Minimal device model: Only virtio devices exposed — no legacy PCI emulation
- Per-VM seccomp: The VMM process itself runs under seccomp filters
- Memory isolation: KVM hardware enforces VM memory boundaries via EPT/NPT
- Boot in milliseconds: Minimal firmware reduces time-to-isolation
- No persistent state: microVMs can be configured as ephemeral — destroyed on stop
# Create a microVM with Neutron Stardust
sudo volt vm create secure-worker \
--engine stardust \
--memory 256M \
--vcpus 1
# Ephemeral microVM — destroyed on stop
sudo volt vm create ephemeral-task \
--engine stardust \
--ephemeral
Security Best Practices
1. Use the Strictest Profile That Works
Start with --seccomp strict and --landlock default, then relax only what your application needs. Volt's audit mode helps identify required syscalls and paths:
# Run with audit mode to discover required syscalls
sudo volt container create myapp --seccomp strict --seccomp-audit
sudo volt logs myapp --filter seccomp
# Review violations, add only what's needed to a custom profile
2. Enable User Namespaces
Always use --private-users (enabled by default) so that root inside the container maps to an unprivileged user on the host. Never run containers with --private-users=no in production.
3. Restrict Network Access
Use --network none for workloads that don't need network access. For those that do, define explicit network policies rather than relying on defaults:
# Database container — only accessible from the web tier
sudo volt container create db --network none
sudo volt network policy create --from web --to db --port 5432 --action allow
4. Set Resource Limits on Everything
Always set --memory and --pids-limit. Unbounded workloads can starve the host and impact other containers:
sudo volt container create myapp \
--memory 512M \
--pids-limit 256 \
--cpu-limit 100%
5. Verify CAS Integrity Regularly
Run volt cas verify on a schedule (cron or systemd timer) to detect storage corruption or tampering:
# Add to a systemd timer or cron
sudo volt cas verify --quiet || notify-admin "CAS integrity check failed"
6. Keep the Host Kernel Updated
Volt's security depends on kernel features (Landlock, seccomp, namespaces, cgroups v2). Kernel vulnerabilities can undermine all isolation layers. Keep the host kernel current and enable automatic security updates.
7. Audit Security Configuration
# Full security audit of a workload
sudo volt security audit myapp
# System-wide security overview
sudo volt security audit --all
# Check for common misconfigurations
sudo volt security check
Security Layer Summary
| Layer | Mechanism | Protects Against |
|---|---|---|
| Filesystem | Landlock LSM | Unauthorized file read/write/execute |
| Syscalls | seccomp-BPF | Kernel exploit via dangerous syscalls |
| Privileges | Linux capabilities | Privilege escalation |
| Process | PID namespace | Cross-container process visibility |
| Filesystem | Mount namespace | Host filesystem access |
| Network | Network namespace + nftables | Unauthorized network access |
| Identity | User namespace | Root escape to host |
| Resources | cgroups v2 | Resource exhaustion / DoS |
| Integrity | Stellarium CAS (SHA256) | Image tampering / corruption |
| VM isolation | Neutron Stardust / KVM | Kernel-level container escape |