Install¶
Edition: Community and Enterprise Offering: Self-managed, offline
sealfix installs from a signed offline bundle with Docker Compose. No step needs the internet on the host that runs it.
Prerequisites:
- A Linux host with Docker Engine and Docker Compose v2.
- The host's clock follows your organisation's NTP servers. The executor refuses to start when its clock and the metadata store's differ by more than 5 seconds.
- A TLS reverse proxy you control (nginx, HAProxy, F5).
- Your LDAP or Active Directory, or an OIDC identity provider.
1. Build and sign the bundle¶
On a machine with internet access, build the image and export it, with the pinned PostgreSQL image, into one bundle signed with your own cosign key:
make image
COSIGN_KEY=cosign.key scripts/release-bundle.sh bundle sealfix:<version> postgres:16
tar czf sealfix-deploy.tgz deploy/prod config/sealfix.example.yaml docs scripts/verify-bundle.sh
bundle/ holds the images, a CycloneDX SBOM, a signature for each and SHA256SUMS. Nothing
uses a public transparency log, so everything works offline. Keep cosign.key offline and give
cosign.pub to the operators by another channel.
2. Verify and load on the offline host¶
tar xzf sealfix-deploy.tgz
scripts/verify-bundle.sh bundle cosign.pub # checksums and signatures; stop if it fails
docker load -i bundle/sealfix-images.tar
Note
Keeping a loaded image's digest needs Docker's containerd image store, the default on new
Docker Engine installs. On the classic store, enable "containerd-snapshotter": true in
/etc/docker/daemon.json before loading.
3. Configure¶
cd deploy/prod
for f in api executor meta; do cp "$f.env.example" "$f.env"; done
cp ../../config/sealfix.example.yaml sealfix.yaml
chmod 600 *.env
| File | Holds |
|---|---|
meta.env |
Three strong passwords: the owner's, the API role's and the executor role's (openssl rand -base64 24) |
api.env |
The API role's connection, the directory's service account, the bootstrap administrator's password hash |
executor.env |
The executor role's connection, and one TARGET_*_DSN per target database |
sealfix.yaml |
Everything else. No secret ever goes in this file |
Create the bootstrap administrator's password hash:
4. Start¶
keygen and migrate exit with code 0; meta-pg, api and executor run and become healthy.
The first start creates the executor's key, the schema and the database roles' grants.
Optional services¶
Each optional service is a Compose profile named after the section of sealfix.yaml it reads.
| Profile | Adds |
|---|---|
notifications |
Tells each role what waits for it: e-mail, Teams, Slack, webhooks |
git |
A signed record of every reviewed, approved and executed fix in your Git repository |
siem |
The audit chain in your SIEM, as OCSF over syslog with TLS |
To keep it on across restarts and upgrades, add COMPOSE_PROFILES=notifications to
deploy/prod/.env.
5. TLS and access¶
The API listens on 127.0.0.1:8080. Put your TLS proxy in front of it and set
FORWARDED_ALLOW_IPS in api.env to the proxy's address, so the audit log records the real
client address.
- Point the proxy's health check at
/readyz. It answers 200 only when the metadata store answers, the executor's public key is loaded and the executor was seen in the last 3 minutes. - The session cookie is
Secure: sign-in over plain HTTP does not work, by design.
6. Back up the executor's key¶
Do this now, before the first fix. Without the key, nothing sealed can ever be opened: pending fixes cannot run and executed fixes cannot be rolled back.
docker run --rm --user 0 -v sealfix_executor-keys:/keys:ro -v "$PWD":/backup \
sealfix:<version> tar czf /backup/executor-keys.tgz -C /keys .
Store the archive offline, under your key-handling policy. Never copy it to the API's host.
Next¶
First-time setup: sign in as the bootstrap administrator at /login/local and walk
the wizard.
Troubleshooting¶
The executor does not start: clock skew
The executor compares its clock with the metadata store's at start. Point both hosts at the
same NTP servers, then check any host with sealfix doctor --clock.
Sign-in returns to the sign-in page
The session cookie is Secure. Reach sealfix through your HTTPS proxy, not on port 8080
directly.
The setup wizard says the executor key is not published yet
The API reads the public key from the executor-public volume. Check that the API container
mounts it, and that keygen exited with code 0.
The notifier stopped after an upgrade
Optional services start only with their profile. Add COMPOSE_PROFILES=notifications (and
git, siem if you run them) to deploy/prod/.env, then docker compose up -d.