Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Zero Trust Posture

This page describes how Open Sesame applies zero trust principles to its architecture. Zero trust in this context means that no component, process, or network path is implicitly trusted. Every interaction is authenticated, authorized, and audited, regardless of origin.

Principles

Never Trust, Always Verify

Every IPC message on the bus is authenticated via the Noise IK protocol. There is no unauthenticated communication path between daemons.

Implementation: When a daemon connects to the IPC bus hosted by daemon-profile, the Noise IK handshake verifies the connecting daemon’s X25519 static public key against the clearance registry (core-ipc/src/registry.rs). UCred (pid, uid, gid) from the Unix domain socket is bound into the Noise prologue, preventing a compromised process from reusing another process’s Noise session.

Unregistered clients (e.g., the sesame CLI) receive Open clearance. They can send and receive Open-level messages but are excluded from Internal, ProfileScoped, and SecretsOnly traffic.

The SecurityLevel enum (core-types/src/security.rs) defines the clearance hierarchy:

#![allow(unused)]
fn main() {
pub enum SecurityLevel {
    Open,           // Visible to all, including extensions
    Internal,       // Authenticated daemons only
    ProfileScoped,  // Daemons with current profile's security context
    SecretsOnly,    // Secrets daemon only
}
}

A message at SecretsOnly level is delivered only to daemons registered at SecretsOnly clearance. A daemon at Internal clearance never sees it. This is enforced in the IPC server’s message routing loop (core-ipc/src/server.rs): the server checks conn.security_clearance >= msg.security_level before delivering each message, and checks conn.security_clearance >= msg.security_level before accepting each sent message from a daemon.

Least Privilege

Each daemon operates with the minimum privileges required for its function. Privilege boundaries are enforced at multiple layers:

Per-Daemon Clearance

DaemonClearanceRationale
daemon-secretsSecretsOnlyHolds decrypted vault keys; must not leak to other daemons
daemon-clipboardProfileScopedHandles clipboard content scoped to the active profile
daemon-profileInternalIPC bus host; sees all Internal-level and below
daemon-wmInternalWindow management; no access to secrets
daemon-launcherInternalApplication launching; receives secrets only via env injection
daemon-inputInternalKeyboard/mouse capture; no secret access
daemon-snippetsInternalSnippet management; no secret access

Filesystem Sandboxing (Landlock)

Each daemon restricts its own filesystem access at startup via Landlock. The secrets daemon, for example, can access only $XDG_RUNTIME_DIR/pds/ and ~/.config/pds/. Attempts to read or write outside these paths return EACCES.

Partially-enforced Landlock is a fatal error. If the kernel supports Landlock but enforcement is incomplete (e.g., missing filesystem support), the daemon aborts rather than operating with degraded isolation.

Syscall Filtering (seccomp-bpf)

Each daemon installs a seccomp-bpf filter with a per-daemon syscall allowlist. Unallowed syscalls terminate the offending thread (SECCOMP_RET_KILL_THREAD). A SIGSYS handler logs the denied syscall before the thread dies, providing visibility into unexpected syscall usage.

systemd Hardening

All daemon services apply:

DirectiveEffect
NoNewPrivileges=yesPrevents privilege escalation via setuid/setgid binaries
ProtectSystem=strictRoot filesystem mounted read-only
ProtectHome=read-onlyHome directory read-only except explicit ReadWritePaths
LimitCORE=0Core dumps disabled
LimitMEMLOCK=64MLocked memory budget for memfd_secret and mlock
MemoryMaxPer-daemon memory ceiling

The secrets daemon additionally uses PrivateNetwork=yes, which creates a network namespace with only a loopback interface. The secrets daemon has no path to any network socket.

Capability-Based Authorization

The CapabilitySet type (core-types/src/security.rs) implements fine-grained, capability-based authorization. Each agent’s session_scope defines exactly which operations it can perform. The 16 defined capabilities are:

  • Admin, SecretRead, SecretWrite, SecretDelete, SecretList
  • ProfileActivate, ProfileDeactivate, ProfileList, ProfileSetDefault
  • StatusRead, AuditRead, ConfigReload
  • Unlock, Lock
  • Delegate, ExtensionInstall, ExtensionManage

Delegation narrows scope via lattice intersection: effective = delegator_scope.intersection(grant.scope). A delegatee can never exceed the delegator’s capabilities.

Continuous Verification

Trust is not established once and cached. Multiple mechanisms provide ongoing verification:

Watchdog

All daemons report health to systemd via WatchdogSec=30. If a daemon fails to report within 30 seconds, systemd restarts it. This detects hung processes and ensures daemon liveness.

Audit Chain

The BLAKE3 hash-chained audit log provides a tamper-evident record of all operations. Each entry hashes the previous entry’s hash, forming a chain from the genesis entry at sesame init to the most recent operation. Verification via sesame audit verify detects:

  • Modified entries (hash mismatch).
  • Deleted entries (chain gap).
  • Reordered entries (hash mismatch).
  • Inserted entries (hash mismatch).

The hash algorithm is configurable: BLAKE3 (default) or SHA-256 (governance-compatible), via CryptoConfigToml.audit_hash (core-config/src/schema_crypto.rs).

Authorization Freshness

The TrustVector.authz_freshness field (core-types/src/security.rs) tracks how long since the last authorization refresh. Delegated capabilities expire via DelegationGrant.initial_ttl and require periodic renewal via heartbeat_interval. A stale authorization is equivalent to no authorization.

Heartbeat Renewal

The Attestation::HeartbeatRenewal variant records heartbeat events for time-bounded attestations. Missing a heartbeat revokes the corresponding delegation.

Device Health as Posture Signal

The availability of memfd_secret(2) is a binary posture signal. A system with memfd_secret removes secret pages from the kernel direct map; a system without it leaves secrets accessible to any process that can read /proc/pid/mem or perform DMA.

Posture SignalValueMeaning
memfd_secret availabledevice_posture: 1.0Secrets removed from kernel direct map
memfd_secret unavailabledevice_posture: 0.5Secrets on kernel direct map (mlock fallback)
No mlockdevice_posture: 0.0Secrets may be swapped to disk

The TrustVector.device_posture field (core-types/src/security.rs) is a f64 from 0.0 (unknown) to 1.0 (fully attested). In a federation context, a peer with low device posture may be restricted from receiving high-sensitivity secrets.

Additional posture signals include:

  • Landlock enforcement status – whether the filesystem sandbox is active.
  • seccomp-bpf status – whether syscall filtering is active.
  • Machine binding – whether the installation is bound to specific hardware via MachineBindingType::TpmBound or MachineBindingType::MachineId.
  • Kernel version – whether the kernel meets minimum requirements for all security controls.

Microsegmentation via Profile Isolation

Trust profiles are the microsegmentation boundary in Open Sesame. Each profile is an isolated trust context:

BoundaryIsolation Mechanism
SecretsSeparate SQLCipher vault per profile (vaults/{name}.db)
Encryption keysSeparate BLAKE3-derived vault key per profile
ClipboardProfile-scoped clipboard history
AuditProfile attribution in every audit entry
FrecencySeparate frecency database per profile
EnvironmentProfile-scoped secret injection via sesame env -p {profile}

Cross-profile access is not possible without explicit configuration. A daemon operating in the work profile cannot read secrets from the personal profile’s vault. The vault encryption keys are derived from different BLAKE3 context strings ("pds v2 vault-key work" vs. "pds v2 vault-key personal"), so even with the master key, the derived keys are distinct.

The LaunchProfile type (core-types/src/profile.rs) allows explicit profile stacking for applications that need secrets from multiple profiles:

#![allow(unused)]
fn main() {
pub struct LaunchProfile {
    pub trust_profiles: Vec<TrustProfileName>,
    pub conflict_policy: ConflictPolicy,
}
}

When multiple profiles are stacked, the ConflictPolicy determines how secret key collisions are handled: Strict (abort), Warn (log and use higher-precedence), or Last (silently use higher-precedence). The default is Strict, preventing accidental secret leakage across profile boundaries.

Explicit Security Posture

Open Sesame does not degrade silently. Security controls that fail are fatal, with one documented exception:

  • Landlock enforcement failure: fatal. Daemon does not start.
  • seccomp-bpf installation failure: fatal. Daemon does not start.
  • memfd_secret unavailability: non-fatal. Daemon starts with mlock fallback. Logged at ERROR level with an explicit compliance impact statement naming affected frameworks (IL5/IL6, DISA STIG, PCI-DSS) and the exact remediation command.

The memfd_secret exception exists because the feature depends on kernel configuration that application software cannot control. The ERROR-level log ensures the operator is informed of the reduced posture, and the compliance impact statement provides actionable remediation guidance.

Network Trust Model

The NetworkTrust enum (core-types/src/security.rs) classifies the trust level of the network path:

#![allow(unused)]
fn main() {
pub enum NetworkTrust {
    Local,           // Unix domain socket, same machine
    Encrypted,       // Noise IK, TLS, WireGuard
    Onion,           // Tor, Veilid
    PublicInternet,  // Unencrypted or minimally authenticated
}
}

The ordering represents decreasing trust: Local is most trusted (no network traversal), PublicInternet is least trusted.

In the current implementation, all IPC communication uses Local (Unix domain socket). In a federation context (Design Intent), Encrypted (Noise IK over TCP) would be used for cross-machine communication. The TrustVector.network_exposure field allows authorization policies to require stronger authentication for less-trusted network paths.