Skip to content
BitExactdocs
Documentation
On this page

Hardening: recorder integrity and the supply chain#

Beyond where the key lives (see Recorder-key custody), two deployment controls raise assurance that the recorder producing your evidence is a genuine, unmodified BitExact build. Both are deployment/infra controls, not application crypto — and that is the honest design, explained below.

The same holds for confidentiality at rest. BitExact makes the evidence tamper-evident, not unreadable: put the store on an encrypted volume or an encrypted database, keep it owner-only (BitExact creates its directories 0700 and its files 0600, under either backend, and bitexact health warns when the data directory is not owner-only), and encrypt its backups. See Compliance pack.

Cosign start-gate (supply-chain integrity)#

Every BitExact image is signed at release with cosign and the BitExact release key (scripts/release.sh). You pin its public half, cosign.pub, delivered with your license. The gate is the enforcement half: refuse to start unless the image you're running is that signed image.

Enforce it above the container, not inside it. An in-image gate has two problems. It needs a cosign binary, and the shipped image is python:3.15-slim plus pip installs running as a non-root user, so there is none and none can be installed at start-up. And a gate that ships inside the image it verifies is defeated by rebuilding the image: an attacker who patches the recorder also patches the gate. That is the same argument this document makes below against a vendor-signed measurement, and it applies here too.

So put the check where the attacker cannot rewrite it: an admission controller (Kyverno, Gatekeeper, or your registry's own signature policy) that refuses to admit an image whose digest is not the cosign-signed release.

# Kyverno: refuse any bitexact image that is not the signed release
verifyImages:
  - imageReferences: ["registry.example/bitexact*"]
    attestors:
      - entries:
          - keys:
              publicKeys: |-
                <the BitExact release public key, cosign.pub, as
                 delivered with your license>

Releases are signed with our release key on our release workstation, and verify against its public half, cosign.pub, delivered with your license. Each signature is also recorded in Sigstore's public transparency log - the entry holds only the image digest and the public key - so a signature made with a stolen release key would show there. A cluster with no route to that log checks the key signature alone: in Kyverno, set rekor: {ignoreTlog: true} beside publicKeys. The key signature is the guarantee; the log entry is the check against the key's misuse, and any connected machine can make it for the same digest.

When we rotate the release key, we deliver the new cosign.pub ahead of the first release it signs. List both public keys in your policy until the old one is retired; a release is never signed by a key you were not given.

If you have no admission control and want defense against an accidental image swap rather than a hostile one, an entrypoint wrapper in a derived image that carries cosign will do that much, and only that much:

# entrypoint wrapper — verify the running image before exec'ing the app
COPY cosign-gate.sh /usr/local/bin/cosign-gate.sh
ENTRYPOINT ["/usr/local/bin/cosign-gate.sh"]
# Setting ENTRYPOINT resets the base image's CMD, and the gate execs what
# follows it, so the command is given in full - with the address the base
# image binds, or the proxy listens on loopback only:
CMD ["bitexact", "serve", "--host", "0.0.0.0", "--port", "8787"]

tools/cosign-gate.sh is that wrapper: it runs cosign verify --key /etc/bitexact/cosign.pub "$BITEXACT_IMAGE_REF" and refuses to start the app unless it passes. BITEXACT_RELEASE_PUBKEY names another key path, and BITEXACT_COSIGN_OFFLINE=1 skips the transparency-log check on a host that cannot reach it.

Pin BITEXACT_IMAGE_REF to the digest your release published. Note the limit stated above: this catches the wrong image being run, not an attacker who rebuilt the image with the gate removed. Build it into your own derived image (FROM registry.example/bitexact@sha256:... plus cosign). Give the whole command after the gate, as above, for whichever role the container runs (bitexact recorder ..., bitexact view ...): a derived ENTRYPOINT drops the base image's CMD, and a command without its --host binds loopback and is unreachable from outside the container while its health probe still passes.

Recorder integrity: measured boot, not a redundant signature#

You might expect a "vendor-signed measurement of the recorder" baked into every run. We deliberately don't ship that as separate app crypto, because it would be security theater: a static signed manifest is baked into the package, so anyone who patches the recorder keeps the manifest and the "attestation" lies. It would prove a genuine build exists, not that the running one is unmodified.

The control that actually proves the running recorder is unmodified is measured boot / remote attestation — the host's TPM measures the boot chain and the container image, and your attestation service (e.g. a cloud confidential- computing attestation, or Keylime) refuses to release the recorder's key material to a host whose measurements don't match. That is infrastructure you own; it is strictly stronger than anything the recorder could self-assert, and it composes cleanly with what BitExact provides:

  • measured boot attests the host + image is the genuine, unmodified build;
  • the cosign gate attests the image is the signed release;
  • the recorder key (in your HSM, per recorder-key-custody.md) signs the run, and the vendor license binds that key to you (see Licensing).

Chained, a relying party gets: a genuine, attested BitExact build, running the signed release, signing with a licensed recorder key. No self-asserted "measurement" is needed or trusted — the assurance comes from your infra's root of trust, not from a manifest the recorder could carry.

If a specific customer requires a turnkey measured-boot integration (e.g. binding the KMS decrypt or HSM login to a TPM attestation policy), that is the trigger to build it against their platform — the recorder-key custody seam (hsm.py) is where it plugs in.