Docs / Licensing

Licensing — generating SimpleVirt license keys

Looking for what a subscription means? See docs/subscription.md: what a key does and does not buy, how the controller reports it, the dismissible non-subscribed notice, and the contract for the optional online validation server. This page is the vendor-side half — how to mint keys with your own signing key.

This page is about the SimpleVirt subscription, not the software licence. They are different things and only share a word. The software licence is the GNU Affero General Public License v3 or later: its full text is in LICENSE at the root of the source tree, and on an installed appliance at /usr/share/doc/simplevirt/LICENSE. A subscription token records a commercial entitlement and a licensed-to name; it gates no capability in the product and it narrows nothing the AGPL grants you.

SimpleVirt licenses are Ed25519-signed tokens. Nothing phones home: the appliance carries only the public key and verifies a token offline. Only whoever holds the private signing key can mint one, so licensing is entirely in your hands when you run your own build.

A token looks like:

SIMPLEVIRT-<base64url(payload)>.<base64url(signature)>

where the payload is {"tier":"Enterprise","to":"Acme Corp","exp":1790000000} (exp is a Unix timestamp; a perpetual key omits it).


1. Mint a license (the common case)

You already have deploy/license/simplevirt-license.key (the private signing key, git-ignored). Then:

make license TIER=Enterprise TO="Acme Corp" DAYS=365
  • TIER — any string your build recognises (e.g. Standard, Enterprise).
  • TO — the licensed-to name, shown on the appliance's Licensing screen.
  • DAYS — validity window; DAYS=0 mints a perpetual key.

The command prints one SIMPLEVIRT-… line. Paste it into the appliance under Administration → Licensing. The host verifies it against the embedded public key and stores it; there is no activation server and no network call.

Under the hood this is just cmd/simplevirt-license, so you can run it directly without make — handy in CI, where the key comes from a secret rather than a file on disk:

SIMPLEVIRT_LICENSE_KEY="$SIGNING_KEY_B64" go run ./cmd/simplevirt-license \
    -tier Enterprise -to "Acme Corp" -days 365

-key / SIMPLEVIRT_LICENSE_KEY is a base64 Ed25519 private key (64 bytes decoded). The Makefile target reads it from deploy/license/simplevirt-license.key.


2. Generate a signing keypair (first-time / fork / rotation)

Do this only when you are standing up licensing for your own build, or rotating a compromised key. It replaces the vendor keypair with one only you hold.

Generate the keypair (base64, the form both halves expect):

go run ./cmd/simplevirt-keygen

If that tool is not present in your tree, the same three lines inline:

go run - <<'EOF'
package main
import ("crypto/ed25519";"crypto/rand";"encoding/base64";"fmt")
func main(){
    pub, priv, _ := ed25519.GenerateKey(rand.Reader)
    fmt.Println("PRIVATE (keep secret):", base64.StdEncoding.EncodeToString(priv))
    fmt.Println("PUBLIC  (embed):      ", base64.StdEncoding.EncodeToString(pub))
}
EOF

Install the private half where the minting tools read it — this file is git-ignored (.gitignore → deploy/license/simplevirt-license.key) and must never be committed or baked into an ISO:

printf '%s' '<PRIVATE base64>' > deploy/license/simplevirt-license.key
chmod 600 deploy/license/simplevirt-license.key

Embed the public half so appliances can verify tokens. Replace the constant in internal/license/license.go:

var simplevirtPublicKey = mustDecodeKey("<PUBLIC base64>")

Then rebuild the binaries and rebake the ISOs — the public key ships inside the image, so a key change is an ISO change, not a hot config:

make appliance-binaries appliance-command-binaries
make appliance-iso appliance-command-iso

Every token you minted with the old private key stops verifying the moment an appliance runs the new build. Rotation invalidates the field — plan it.


Security notes

  • The private key is the whole ballgame. Anyone who holds it can issue unlimited perpetual Enterprise licenses. Keep it off the ISO, out of git, and in a secret store for CI — never in the repo, never in a layer of a Docker image.
  • The appliance only ever verifies. internal/license has no private key and no minting path, by design: a stolen appliance cannot forge licenses.
  • Tokens are not secret. A license token is signed, not encrypted — it is safe to email to a customer. Its contents (tier, licensed-to, expiry) are readable by anyone; the signature is what makes it unforgeable.
  • Expiry is enforced on the appliance clock. A box with a badly wrong clock can reject a valid perpetual-adjacent key or accept a just-expired one; this is the usual offline-licensing trade-off, accepted deliberately over a call-home check.
This page is part of the SimpleVirt 1.0.0 documentation set. The same guides ship inside the appliance images at /usr/share/doc/simplevirt.