Using SPIKE as an encryption service
Problem
Sometimes you do not want SPIKE to store your data; you want it to encrypt
data you store somewhere else (an object store, a database column, a file on
disk). You keep custody of the ciphertext; SPIKE holds the key and does the
crypto. This is “encryption as a service,” and it pairs naturally with lite
mode, where Nexus has a root key and keepers but no secret store at all.
TL;DR
The spike cipher command encrypts and decrypts through Nexus without
persisting anything:
# encrypt a file (stream mode), keep the ciphertext yourself
spike cipher encrypt -f plan.txt -o plan.enc
# decrypt it back
spike cipher decrypt -f plan.enc -o plan.txt
The plaintext is never stored in SPIKE; only the key (derived from the root
key) lives there. Run Nexus in lite mode when this is the only thing you
need from it.
Workflow
-
Encrypt. Stream mode reads a file or stdin and writes ciphertext to a file or stdout; it handles binary data transparently:
spike cipher encrypt -f secret-plan.txt -o secret-plan.enc echo "transient token" | spike cipher encrypt -o token.enc -
Store the ciphertext wherever you like — S3/minio, a database BLOB, a git-crypt-style file. SPIKE is out of the loop until you need it back.
-
Decrypt by feeding the ciphertext back through Nexus:
spike cipher decrypt -f secret-plan.enc -o secret-plan.txt cat token.enc | spike cipher decrypt -
For programmatic callers, use JSON mode. Encrypt accepts base64
--plaintextand returns the version byte, nonce, and ciphertext; decrypt takes those three back:spike cipher encrypt --plaintext "$(printf 'hello' | base64)" # -> JSON with {version, nonce, ciphertext} (all base64) spike cipher decrypt \ --version 1 \ --nonce "<base64-nonce>" \ --ciphertext "<base64-ciphertext>"
Tips
- Stream mode for files, JSON mode for code. Stream mode (
-f/-oor stdin/stdout) is the easy path for files and pipelines. JSON mode (passing--plaintext, or any of--version/--nonce/--ciphertext) is for callers that want to persist the components separately. - Keep the version byte. Decryption needs the version, nonce, and ciphertext that encryption produced. Store all three with your data; losing the nonce or version makes the ciphertext undecryptable.
- Pair with
litemode. If encryption is all you need,litegives you the cipher routes (and the root key/keepers that back them) without a secret store to operate, back up, or persist. - Access still needs a policy. The caller authenticates with its SPIFFE ID and needs permission to use the cipher routes, the same as any other SPIKE operation.
Pitfalls
litestill needs keepers and a root key. “No secret store” does not mean “no setup.”liteis encryption-only, but the key that encrypts your data is the root key, which is reconstructed from the keepers. You must bootstrap it exactly likesqlite. See Bootstrapping a fresh SPIKE.- You own the ciphertext durability. SPIKE does not keep a copy. If you lose the ciphertext, SPIKE cannot recover the plaintext; it only holds the key.
- Re-keying invalidates old ciphertext. The key is derived from the root key. If you re-bootstrap with a new root key, data encrypted under the old key can no longer be decrypted. Treat root-key rotation as a deliberate migration.
--plaintextis base64. In JSON mode the plaintext is base64-encoded, not raw text. Encode on the way in and decode on the way out.
Cross-links
- Choosing a backend store (when
liteis the right mode) - Bootstrapping a fresh SPIKE
- Writing access policies
- Reference: Configuration and the command reference
What’s next
Make sure you can recover the key that all this depends on: Break-the-glass disaster recovery.