Skip to main content
Headgate provides opt-in, client-side payload encryption through headgate-crypto for Rust and go/headgatecrypto for Go. Encryption happens before enqueue, and decryption happens inside the registered handler. Core and the storage drivers never receive encryption keys.

Install

Encrypt before enqueue

The key provider exposes one active write key and any historical read keys. The built-in static keyring is useful for configuration-backed keys; production applications can implement the provider interface over a KMS or secret manager.
Register encrypted task kinds with the encrypted registration function. A normal typed handler receives ciphertext and correctly classifies it as undecodable.

What is protected

AES-256-GCM encrypts only Envelope.payload, using a fresh 96-bit nonce for every encryption. The authenticated data binds the ciphertext to the job ID, task kind, and schema version. Moving ciphertext to another job or changing its decoder identity fails authentication and moves the job to undecodable instead of retrying forever. The following values remain visible because admission and operations need them:
  • job ID, kind, schema version, queue, partition, rate class, tags, and headers;
  • priority, schedule, retry, lease, and retention metadata;
  • results, progress, mid-run output, logs, and attempt errors.
Use database or disk encryption when the entire store must be opaque. Do not place secrets in visible metadata or output fields unless the application protects them separately.

Fingerprints and equality

Headgate computes the fingerprint from plaintext before adding the random nonce. That preserves uniqueness and poison-pill quarantine across identical encrypted payloads. It also reveals that two payloads are equal even though their ciphertext differs.

Rotate keys without losing jobs

  1. Add the new key while retaining all old keys.
  2. Change the provider’s active key ID so new jobs use the new key.
  3. Keep historical keys until no queued, scheduled, retryable, quarantined, or retained job can reference them.
  4. Remove an old key only after that retention window has closed.
Headgate stores the key ID in a versioned wire format but never stores key material. Rust and Go share the same byte-level format, so either runtime can process a job encrypted by the other when both have the same key.

Inspect encrypted jobs in the console

The job detail view recognizes the encrypted envelope and labels it as AES-256-GCM. It shows the wire-format version, key ID, and copyable Base64 ciphertext. It does not decrypt the payload: sending application or KMS keys to a browser would break the client-side encryption boundary. Routing metadata, tags, progress, results, output, and errors remain visible because this layer encrypts only the payload bytes.

Run the encryption example

Verify ciphertext, authenticated decoding, and the shared application boundary locally.