Skip to content

feat: publish -fips images built against the validated Go crypto module - #4997

Merged
mnafees merged 17 commits into
mainfrom
nafees/fips
Oct 12, 2026
Merged

mnafees merged 17 commits into
mainfrom
nafees/fips

Conversation

@mnafees

@mnafees mnafees commented Sep 21, 2026 •

Copy link
Copy Markdown
Member

Description

Publish new set of -fips suffixed images for all of our GHCR images. The Go binaries are linked with the validated Go Cryptography Module (GOFIPS140=v1.0.0, CMVP #4985).

Much inspiration was taken from the go-fips hardened image from Chainguard meaning that we have CGO_ENABLED=0, -ldflags=-w, DefaultGODEBUG=fips140=on.

  • FIPS=true build arg on the servers, frontend, and dashboard Dockerfiles, the build stage fails unless go version -m shows the validated module.
  • Dashboard image serves the frontend and proxies /api with hatchet-staticfileserver instead of nginx so the whole serving path is Go.
  • hack/ci/assert-fips.sh inspects every Go binary in an image. Runs on PRs (fips job), on regular prerelease images (must not link the module) and on -fips prerelease images before manifests are combined.

Type of change

  • New feature (non-breaking change which adds functionality)
  • CI (any automation pipeline changes)

Checklist

Changes have been:

  • Documented (where applicable)
  • Added to CHANGELOG (where applicable) -- see Keep a Changelog

🤖 AI Disclosure
  • I acknowledge that an LLM was used in the creation of this Pull Request, in accordance with Hatchet's AI_POLICY.md.
  • Details: [e.g. generating tests, writing docs]

@mnafees mnafees self-assigned this Sep 21, 2026
@vercel

vercel Bot commented Sep 21, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
hatchet-docs Ready Ready Preview Oct 12, 2026 12:16pm UTC

Request Review

@github-actions github-actions Bot added documentation Improvements or additions to documentation github_actions Pull requests that update GitHub Actions code engine Related to the core Hatchet engine dashboard Related to the Hatchet dashboard labels Sep 21, 2026
Comment thread cmd/hatchet-admin/fips.go Outdated
Comment thread internal/signature/sign.go Outdated
@github-actions github-actions Bot removed the dashboard Related to the Hatchet dashboard label Sep 25, 2026
@mnafees
mnafees marked this pull request as ready for review September 25, 2026 14:14
@greptile-apps

greptile-apps Bot commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

RetriggerConfidence Score: 4/5

[High impact] Adds FIPS-validated cryptography build path and enforcement.

The PR does not appear safe to merge until the ARM FIPS job reliably fails when a binary build fails.

Summary

The PR adds FIPS-built image variants, image checks, runtime smoke tests, and deployment guidance. Since the previous review, it adds an ARM FIPS CI job to build and test those images.

Reviews (10) · Last reviewed commit: "arm builds" · Reviewed by Greptile

Comment thread .github/workflows/pre-release-fips.yaml
Comment thread pkg/encryption/local.go Outdated
Comment thread pkg/repository/user.go Outdated
Comment thread .github/workflows/release.yaml Outdated
Comment thread .github/workflows/pre-release-fips.yaml Outdated
Comment thread pkg/encryption/hmac.go
@github-actions

Copy link
Copy Markdown
Contributor

⚠️ Optional test failure: The load-deadlock job failed on this PR (optimistic-scheduling=true). This check is non-mandatory and does not block merging, but may be worth investigating. View logs

@greptile-apps

greptile-apps Bot commented Sep 25, 2026 •

Copy link
Copy Markdown
Contributor

Comments Outside Diff

These findings could not be posted inline.

  • P1 Previously encrypted secrets become unreadable pkg/encryption/local.go:254 ▶

    When a non-FIPS deployment upgrades from the previous revision of this PR, this code tries to decrypt stored secrets only with the AES-GCM envelope. That revision wrote new secrets with an AES-CTR-HMAC envelope, which the current path cannot read. Webhook credentials and OAuth tokens written by that revision therefore fail to decrypt.

Comment thread pkg/repository/user.go

@igor-kupczynski igor-kupczynski left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

At 30% this makes sense to me ✅

  • the PR uses the new native Go Cryptographic Module v1.0.0 which is certified by nist
  • the right args are passed to go in the dockerfiles

^^^ i have some amount of nickpicks which an agent can probably solve quickly, i'll raise them separately.

One big concern i have (also cc @abelanger5 to chime in) is if we need a fips base image:

  • the PR doesn't change the base and uses golang:1.26-alpine for build and alpine for the runtime image
  • my interpretation is that the approach in this PR is OK, because of the CGO_ENABLED=0 we don't shell for the native crypto of the base image but rather use fips go module
  • the base still has libcrypto3/libssl3 (not fips validated/compliant) which may come up on audit scans

@igor-kupczynski igor-kupczynski left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great stuff @mnafees; i've raised a lot of comments, i'd like to see them responded to before merging, so ❌ for now. Let me know WDYT.

Comment thread cmd/hatchet-api/fips.go Outdated
Comment thread cmd/hatchet-api/fips.go Outdated
Comment thread pkg/encryption/local.go Outdated
Comment thread pkg/encryption/local.go
Comment thread pkg/repository/user.go
Comment thread pkg/repository/user.go
Comment thread build/package/dashboard-entrypoint.sh Outdated
Comment thread pkg/encryption/local.go Outdated
Comment thread .github/workflows/build.yml Outdated
Comment thread api/v1/server/handlers/v1/webhooks/receive.go
Comment thread cmd/hatchet-admin/cli/user.go
Comment thread hack/ci/smoke-fips.sh
Comment thread build/package/dashboard-entrypoint.sh Outdated
Comment thread cmd/hatchet-admin/cli/user.go
Comment thread cmd/hatchet-admin/cli/user.go

@igor-kupczynski igor-kupczynski left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Opus 5.5 on behalf of Igor:

Approving. This replaces my earlier changes-requested. Thanks for working through all of it.

I've left two suggestions inline: docs for switching to -fips, and a written position on the Alpine base image. Your call on whether they go in this PR or a follow-up.

Greptile also has an open P1 on the set-password ordering with no reply yet: #4997 (comment). The risk is low in practice, since old bcrypt passwords can't log in on FIPS builds anyway. Writing the hash first and revoking sessions afterwards closes it; if revocation fails, you just re-run the command.

Comment thread pkg/encryption/local.go Outdated
aes256GcmHandle, err := keyset.NewHandle(aeadTemplate)
for _, k := range h.KeysetInfo().GetKeyInfo() {
if k.GetTypeUrl() == aesGCMKeyTypeURL {
return fmt.Errorf("master keyset uses AES-GCM, which is not FIPS-approved: run `hatchet-admin keyset create-local-keys` from a FIPS build to regenerate the master and JWT keysets together, then re-create secrets encrypted under the old master key (OAuth tokens, Slack and inbound webhook credentials)")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Opus 5.5 on behalf of Igor:

Docs suggestion: once this merges, the next tag publishes -fips:latest. Anyone pointing it at an existing database will hit three things that aren't written down anywhere:

  • Users with bcrypt passwords get a 400 on login, and the only hint is a server-side warning. The fix is hatchet-admin user set-password.
  • The server refuses to start on an AES-GCM master key. Regenerating with keyset create-local-keys makes the stored secrets unreadable (OAuth tokens, Slack and webhook credentials), so they have to be re-created.
  • Regenerating the JWT keysets invalidates every existing API token, so workers need new tokens. Worth a sentence in this error message too.

A short self-hosting page on switching to -fips would cover it.

# openssl and bash needed for admin build
RUN apk update && apk add --no-cache openssl bash ca-certificates tzdata
# openssl is used by hatchet-admin quickstart to generate dev certs; FIPS images do not ship it
RUN apk update && apk add --no-cache bash ca-certificates tzdata $([ "$FIPS" = "true" ] || echo openssl)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Opus 5.5 on behalf of Igor:

Following up on the base-image thread, which was resolved without a reply. Dropping openssl and blocking cert generation in quickstart fixes the real problem, so I'm fine with staying on Alpine.

libcrypto3/libssl3 from the Alpine base are still in the image, and scanners will flag them even though nothing loads them (CGO_ENABLED=0). I'd state that in the FIPS docs so support has something to point customers at. Distroless or scratch can be a follow-up if an audit asks for it.

@igor-kupczynski

Copy link
Copy Markdown
Contributor

🤖 Opus 5.5 on behalf of Igor:

Non-blocking notes, take them or leave them:

  • GenerateLocalKeys / HashPassword defaults: data keys now follow the master key type, so creating CTR-HMAC master keys and PBKDF2 hashes by default wouldn't need a migration. Existing installs keep working, and passwords move over as users change them. The real reasons to wait are rollback (older versions can't read either) and PBKDF2's CPU cost on a login endpoint with no rate limit. Fine as a follow-up issue.
  • release.yaml: fine to keep it decoupled. A retry loop around docker pull would avoid a red release run when the FIPS pre-release is slower.
  • receive.go checks: agreed. With fips140=on they're the only enforcement.
  • servers.dockerfile: still uses an untagged FROM alpine, while lite and dashboard use alpine:3.21. Nothing is pinned by digest.
  • hatchet-staticfileserver: doesn't call RequireFIPSBuild(). It only proxies plain HTTP to localhost, so probably fine; just noting it.

Comment thread frontend/docs/content/docs/self-hosting/fips.mdx Outdated
Comment thread frontend/docs/content/docs/self-hosting/fips.mdx
Comment thread .github/workflows/build.yml
@mnafees
mnafees merged commit fd1ba5f into main Oct 12, 2026
67 checks passed
@mnafees
mnafees deleted the nafees/fips branch October 12, 2026 12:36

This branch was successfully deployed

1 active deployment
Preview — f7ff0b3b Deployed Oct 12, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation engine Related to the core Hatchet engine github_actions Pull requests that update GitHub Actions code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants