Kevin's trust layer is four things: rule-based entitlements over addressable resources, one sealed credential file instead of secrets hand-copied between machines, records that name the build that wrote them, and a WireGuard overlay with a kill switch that holds locally. All of it runs on your hardware.
Every access decision in the platform reduces to the same triple: can this subject perform this operation on this resource. Resources are addressed as URIs, subjects as patterns, and the engine returns both the verdict and the identifier of the rule that produced it. A denial you cannot trace to a rule is a denial you cannot fix or audit, so the rule id travels with the 403. One engine answers this for HTTP routes, bus topics, vault documents and devices alike (it is called Grant in the source).
A tool, a browser session, a peer machine, or a daemon service.
Bearer session token, then JWT, then a signed service header. Loopback falls back to a configured local user.
grant/__init__.py::get_subject
Matches every loaded rule on resource, subject and operation. Explicit deny wins over explicit allow, whatever the order.
grant/engine.py::evaluate
JSON on disk, watched by OS filesystem events. An edit reloads the domain and clears the decision cache.
grant/policies/*.json
Allow is cached 30 seconds per triple. Deny is never cached, so a denial is re-evaluated every time it is asked.
Grant-Denied-Rule: <rule id>
Append-only JSONL, one file per UTC day. Every denial is written. Successful checks are sampled.
grant/audit.py
Scheme selects the policy domain. Each domain declares its own default.
| Scheme | Addresses | Default |
|---|---|---|
| vault:// | Documents and objects in the vault. | deny |
| api:// | Daemon HTTP routes. | deny |
| mx:// | Device and firmware resources. | deny |
| mqtt:// | Bus topics. | allow |
| fed:// | Reserved for federation. No policy file ships, so it denies everything. | n/a |
The bus domain defaults to allow and the others default to deny. That is a deliberate asymmetry, and it is the first thing to change if your threat model includes an untrusted process on the same host. A resource whose scheme has no loaded policy is denied outright rather than guessed at.
From the shipped vault domain. Patterns: * is one segment, ** is any.
// an explicit deny that no allow can override { "id": "vault-noted-export-deny", "resource": "vault://noted/**", "subjects": ["*"], "ops": ["export"], "effect": "deny" }
Deny-beats-allow is what makes a blanket restriction survive later edits. A rule added next quarter that grants a team broad read access cannot silently re-open an export path closed here.
It is a complete record of denials and of grants issued with a TTL. It is not a complete record of successful access: allows are sampled at a configurable rate, defaulting to one in ten thousand. If you need every successful read logged, raise the sample rate and size the disk for it. We would rather state the default than let you assume the stronger thing.
Two behaviours worth knowing before you deploy. The engine fails open during the boot window, before it has loaded policy, on the assumption that no external traffic reaches protected routes that early. And an unauthenticated request from loopback resolves to a configured local user rather than the anonymous principal, which means local access to the host is trusted by default. Both are defensible on a single owned machine and both are worth revisiting on a shared one.
The common failure is not weak encryption. It is a provider key that exists in nine places: a .env on the workstation, a second .env on the laptop, a CI secret, a password manager note, and a Slack message from the day it was rotated. Nobody can answer which copy is current, and rotation means finding all nine. Kevin collapses that to one encrypted file per machine, with the schema in version control and the values never in it.
Committed to git. Declares which providers exist and what field holds the secret. Values are empty placeholders.
daemon/config/vault-template.yaml
On first run, seeds each slot from legacy sources in priority order, then stops consulting them. Idempotent.
daemon/src/bootstrap_vault.py
One Fernet-encrypted JSON file, mode 0600. After bootstrap this is the only source of truth.
~/.kevin/vault.fernet
Provider SDKs read environment variables and will not be rewritten. At startup the vault exports its values into the process environment under the canonical names, and it overwrites what is already there rather than deferring to it. The direction matters: a stale shell variable cannot win against the vault, so there is exactly one answer to "which key is this process using".
sealed_vault.py::hydrate_env
Adding a provider means adding a slot to the template once. The credential registry, the environment-variable aliases, and the connections card in the operator UI are all derived from that file at load time rather than maintained as three tables that drift apart. Listings redact by default: first four characters, last four, nothing between.
The master key is a file on the same disk as the vault it opens, protected by file permissions and nothing else. There is no passphrase prompt, no HSM, no cloud KMS, and no split-knowledge scheme. An attacker with file-level read access to that home directory has the vault. This is a meaningful improvement over secrets scattered across nine locations, and it is not equivalent to a managed secrets service with hardware-backed keys. If your control requires the latter, this is not it.
A running service can report its own version. That says nothing about rows already on disk. When a bug turns out to have been writing wrong values for six weeks, the question is which rows came from the broken build, and without provenance stored beside the data that question is archaeology rather than a query. The platform standard for this is S012: every record carries the build version and the logical service that wrote it.
The operation ledger stamps each row on insert. Column shape, not live data.
// daemon/src/operation_ledger.py pub_version TEXT // build version of the writer pub_service TEXT // logical service, a role
The service name is a role, not a machine name, so moving a workload to another host does not invalidate the history. The standard also defines a consumer half, recording which build read a record; this store implements the writer half only.
Stamped at publish, in a reserved envelope key.
"_meta": { "schema_version": 1, "pub_version": "<build>", "pub_service": "daemon" }
Provenance lives in the envelope and is never merged into the payload, so a domain field can never collide with it. A message that fails its declared contract is not stamped even when enforcement is set to warn: stamping something just declared invalid would assert a conformance that is not true.
Provenance is mandatory for new stores and is being retrofitted into existing ones. It is live in the operation ledger, in the tick cache, and on contracted bus topics. It is not yet on every table the platform writes, and the cost ledger is among those still being migrated. So: this is a standard we enforce on new work and a migration we are partway through, not a property you can assume of every row in the system today. Ask which stores carry it before you depend on it for a specific question.
Machines reach each other over WireGuard. We did not write the cryptography and do not claim to have improved on it: it is the standard tunnel, with peers declared in a registry that lives in configuration. What the platform adds is honest state reporting and a kill switch that does not depend on the network it is switching off.
Third-party, unmodified. The tunnel is a service on the host; keys are generated and held client-side.
Overlay state reads the tunnel service state, the live interface dump with real peers and last-handshake ages, and the declared peer registry, and reports them separately. "Service running" is not "peers reachable", and collapsing the two is how a dead link reads as healthy.
daemon/src/fleet_net/overlay.py
Authorized through the entitlement engine, published on the bus before it is enacted so the fleet hears the intent even if local enactment then fails, and enforced locally by holding the tunnel service down. It persists across restarts: a kill survives a reboot until explicitly re-armed.
daemon/src/fleet_net/killswitch.py
The switch never touches loopback. It kills the overlay, not the interface the operator is sitting on, because a remote control plane that can strand you is worse than no remote control plane.
One thing this is not yet. Partner access today is network-level, meaning the tunnel plus the peer registry plus the same route rules that apply to any subject. Per-partner federation policy has a reserved address scheme and no shipped policy file, so that scheme currently denies everything. If you need contractual data-sharing boundaries expressed as policy rather than as network reachability, that work is ahead of us, not behind us.
A security page that only lists strengths tells a technical reader that the omissions are the interesting part. These are the cases where you should choose something else.