Source identity
| Field | Recorded value |
|---|---|
| Source type | GitHub source |
| Original record | Janady13/missionmatch / infra/docker/README.md |
| Date | Not specified in source |
| Repository | Janady13/missionmatch |
| Revision | bdacd9d0b4d5998d25fc74bf4007f4c3ec538c7a |
| Branch | deploy-and-ops |
| Path or archive member | infra/docker/README.md |
| Original SHA-256 | 90c8042ba26b141f523e95e563baf413ff43016bee64d896ad91c80b2acda820 |
| Git blob SHA | 0cc85f57b7a897be9c483d36fcae2355bcc9db0a |
| Reading-copy SHA-256 | 90c8042ba26b141f523e95e563baf413ff43016bee64d896ad91c80b2acda820 |
Recovered source transcript
Download complete source text ↓90 lines · 3.9 KB
# Container images
Two minimal, non root, FIPS validated images, each a two stage build with the build context at the
repository root.
- `Dockerfile.mm-api` builds `cmd/api` (the API server, port 8080).
- `Dockerfile.megamind-gateway` builds `cmd/megamind-gateway` (the stateless inference proxy, port 8090).
## Build
```
docker build -f infra/docker/Dockerfile.mm-api -t mm-api:local .
docker build -f infra/docker/Dockerfile.megamind-gateway -t megamind-gateway:local .
```
Each build cross compiles the binary with the validated FIPS module
(`CGO_ENABLED=0 GOOS=linux GOARCH=amd64 GOFIPS140=v1.0.0`, identical to the Makefile `build` target) and
FAILS the build unless the artifact carries the stamp (`go version -m /out/<bin> | grep -q GOFIPS140=v1.0.0`,
the same assertion as `make verify-fips`). So a non FIPS binary can never be packaged.
## Verify the FIPS stamp inside the built image
The in build gate already guarantees it, but to confirm on the shipped image:
```
docker run --rm --entrypoint /busybox/sh mm-api:local -c 'true' # distroless has no shell; instead:
# extract and check on the host:
id=$(docker create mm-api:local) && docker cp "$id":/mm-api /tmp/mm-api && docker rm "$id"
go version -m /tmp/mm-api | grep GOFIPS140 # expect: GOFIPS140=v1.0.0
```
The running container also defaults `GODEBUG=fips140=on` (stamped in by `GOFIPS140=v1.0.0`) and runs the
in process FIPS guard plus the PBKDF2 self test at boot, so a non FIPS runtime fails closed before serving.
## Base image digests (pinned)
Both Dockerfiles pin the builder and the runtime base by sha256 digest. Re resolve them (and let
Renovate or Dependabot, which both understand `FROM ...@sha256`, open re pin pull requests):
```
# golang:1.26.4 (multi arch index)
tok=$(curl -s "https://auth.docker.io/token?service=registry.docker.io&scope=repository:library/golang:pull" | jq -r .token)
curl -sI -H "Authorization: Bearer $tok" -H "Accept: application/vnd.oci.image.index.v1+json" https://registry-1.docker.io/v2/library/golang/manifests/1.26.4 | grep -i docker-content-digest
# gcr.io/distroless/static-debian12:nonroot
tok=$(curl -s "https://gcr.io/v2/token?scope=repository:distroless/static-debian12:pull" | jq -r .token)
curl -sI -H "Authorization: Bearer $tok" -H "Accept: application/vnd.oci.image.index.v1+json" https://gcr.io/v2/distroless/static-debian12/manifests/nonroot | grep -i docker-content-digest
```
After any base bump, re run `make verify-fips` and rebuild the image so the in build stamp gate runs again.
## Runtime hardening (orchestration layer)
The Dockerfile sets the non root numeric user; the read only root filesystem, the writable `/tmp` tmpfs,
and dropping all Linux capabilities are enforced by the pod spec (a container image cannot set them
itself), per the NIST 800-171 baseline. Run both images with:
```yaml
securityContext: # pod
runAsNonRoot: true
runAsUser: 65532
runAsGroup: 65532
fsGroup: 65532
seccompProfile: { type: RuntimeDefault }
containers:
- name: mm-api
securityContext: # container
readOnlyRootFilesystem: true
allowPrivilegeEscalation: false
privileged: false
capabilities: { drop: [ALL] }
volumeMounts:
- { name: tmp, mountPath: /tmp }
volumes:
- name: tmp
emptyDir: { medium: Memory }
```
Neither entrypoint writes to disk outside `/tmp` (no `os.Create`, `WriteFile`, or `MkdirAll` in the request
path), so `/tmp` is the only writable mount required.
## Notes
- distroless static, NOT scratch: the app makes verify full TLS connections (managed Postgres, the cloud
secret store, the object store), so the `ca-certificates` bundle in static is load bearing.
- Never set `GODEBUG=fips140=only` in a production image or pod; the Go docs call it best effort and crash
by design. It belongs only in a dedicated CI probing stage.
- The gateway image proxies Ollama over `MEGAMIND_OLLAMA_URL` (set at deploy); it carries no model and no
Python.