Customers run software in very different places: a disconnected network, their own data centre, or a cloud account. cryptship handles all three with one loader and one license format. The only thing that changes is how the content key is obtained.
🔌 Key providers
That choice is a single pluggable interface, pkg/keyprovider:
| Mode | Provider | Binding | Revocation |
|---|---|---|---|
| Air-gapped | offline | machine fingerprint, or none | expiry only |
| On-prem / cloud | online | a per-license secret held by your server | real: the server declines |
| Confidential | attested | SEV-SNP / TDX attestation gates the key | planned: interface and mock only today |
🛫 offline: no network, ever
Everything needed to unwrap the key is in the license and the machine. Revocation is by expiry: issue short-lived licenses and renew them. Binding policies none, strict and pool all work offline.
🌐 online: revocation that works
With online, the per-license binding secret stays on your server. The reference cryptship-server is a stateless key broker: the loader fetches the secret, and the server answers with a signed, nonce-bound response, so replaying an old answer does not work. Revoke a license on the server (--revoke) and its next start fails; instances already running keep running.
If the key server is unreachable, an online-bound app does not start. Separately, a license can carry an optional revocation_url; for that check alone you choose what happens on a network error: open, closed, or grace:<duration>.
🔐 attested: for when the host is not trusted
The attested provider releases the key only to a guest that proves, through hardware attestation, that it is running the expected code in a confidential VM (AMD SEV-SNP or Intel TDX). In v0.1.0 it is built behind an Attester interface and tested with a mock key broker; real quote generation needs confidential-compute hardware and is on the roadmap.
☸️ Deploying it
The repo's deploy/ folder has a seccomp profile and documented Docker and Kubernetes snippets for a hardened run: a non-root user (set in the Kubernetes example), dropped capabilities, a read-only root filesystem and a tmpfs for the decrypted app. More on what those do and do not stop in Part 3.
🔁 Keys change; licenses keep working
Signing keys live in a key ring identified by signing_key_id, so you can rotate your signing key without invalidating licenses already in the field.
🔗 cryptship
- 🐙 GitHub: github.com/AI2TH/cryptship (GPLv3)
- 📦 Release: v0.1.0
- 📚 Docs: HOWTO · Architecture · Diagrams
- 🌐 Website: ai2th.github.io/cryptship.html
- 💬 Discussion: AI2TH Google Group

