Files
zitadel/apps/api/project.json
Tim MöhlmannandGitHub e94d4c3986 feat(crypto): FIPS 140-3 compliant build and runtime checks (#12233)
# Which Problems Are Solved

Enable FIPS 140-3 compliant build.

# How the Problems Are Solved

- Add runtime config validation, if the FIPS flag is enabled fail the
application when a non-compliant hasher is used, or throw a warning when
a legacy verifier is used
- Add a build matrix for FIPS certified build:
  - Go binary is built with `GOFIPS140=certified`
- Login container uses a separate base:
[ubi9](https://catalog.redhat.com/en/software/containers/ubi9/ubi/615bcf606feffc5384e8452e)
from redhat which provides a FIPS certified OpenSSL (used by NodeJS TLS
stack)
- Non-FIPS images where already pushed to both Github Container Registry
and Google Artifact Repository (GAR). Fips images are only pushed to the
GAR.
- Tag versions are suffixed `-fips`. So on release the following images
will be additionally available:

```
europe-docker.pkg.dev/zitadel-common/zitadel-repo/zitadel-login:vX.Y.Z-fips
europe-docker.pkg.dev/zitadel-common/zitadel-repo/zitadel:vX.Y.Z-fips-debug
europe-docker.pkg.dev/zitadel-common/zitadel-repo/zitadel:vX.Y.Z-fips
```
  
# Other changes

- Bumb Go toolchain. At least v1.25.10 is required for a
GOFIPS140=certified setting.
 
# Additional Context

- Closes https://github.com/zitadel/zitadel/issues/4335
- Build [test
run](https://github.com/zitadel/zitadel/actions/runs/27253916052)
pushing FIPS and non-FIPS images
2026-06-16 10:16:49 +02:00

544 lines
24 KiB
JSON

{
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"name": "@zitadel/api",
"projectType": "application",
"namedInputs": {
"sources": [
"{workspaceRoot}/cmd/defaults.yaml",
"{workspaceRoot}/cmd/defaults_fips.yaml",
"{workspaceRoot}/cmd/**/*.go",
"{workspaceRoot}/internal/**/*.go",
"{workspaceRoot}/proto/**/*.go",
"{workspaceRoot}/pkg/**/*.go",
"{workspaceRoot}/main.go",
"{workspaceRoot}/internal/**/*.yaml",
"{workspaceRoot}/internal/**/*.json"
],
"runtime": [
"sources",
"{workspaceRoot}/go*",
"!{workspaceRoot}/internal/integration/**/*",
"!{workspaceRoot}/**/*_test.go",
"!{workspaceRoot}/**/integration_test/**/*"
],
"pack": [
{
"env": "VERSION"
},
{
"env": "ZITADEL_GOFIPS140"
},
"runtime"
]
},
"targets": {
"prod": {
"description": "Runs the Go-based API backend in production mode",
"continuous": true,
"dependsOn": [
"build"
],
"executor": "nx:run-commands",
"options": {
"parallel": false,
"commands": [
"./.artifacts/bin/$(go env GOOS)/$(go env GOARCH)/${ZITADEL_BINARY:-zitadel.local} start-from-init --config ${API_CONFIG_FILE} --steps ${API_CONFIG_FILE} --masterkey MasterkeyNeedsToHave32Characters"
]
},
"defaultConfiguration": "default",
"configurations": {
"default": {
"env": {
"API_CONFIG_FILE": "{projectRoot}/prod-default.yaml"
}
},
"test-integration-api": {
"env": {
"API_CONFIG_FILE": "{projectRoot}/test-integration-api.yaml"
}
},
"test-functional-ui": {
"env": {
"API_CONFIG_FILE": "{projectRoot}/test-functional-ui.yaml"
}
}
}
},
"build": {
"description": "Compiles the Go-based API backend into an executable binary.",
"dependsOn": [
"generate",
"build-console"
],
"cache": true,
"command": "bash -c 'CGO_ENABLED=0 go build -o .artifacts/bin/$(go env GOOS)/$(go env GOARCH)/zitadel.local -ldflags=\"-s -w\"'",
"inputs": [
{
"runtime": "go env GOOS"
},
{
"runtime": "go env GOARCH"
},
"runtime",
{
"dependentTasksOutputFiles": "internal/api/ui/console/static/**/*"
}
],
"outputs": [
"{workspaceRoot}/.artifacts/bin/*/*/zitadel.local"
]
},
"build-linux": {
"description": "Compiles the Go-based API backend into a Linux executable binary for Docker packaging.",
"dependsOn": [
"generate",
"build-console"
],
"cache": true,
"command": "bash -c 'CGO_ENABLED=0 GOOS=linux go build -o .artifacts/bin/linux/$(go env GOARCH)/zitadel.local -ldflags=\"-s -w\"'",
"inputs": [
{
"runtime": "go env GOARCH"
},
"runtime",
{
"dependentTasksOutputFiles": "internal/api/ui/console/static/**/*"
}
],
"outputs": [
"{workspaceRoot}/.artifacts/bin/linux/*/zitadel.local"
]
},
"pack": {
"description": "Builds a local Docker image for the ZITADEL API (zitadel/zitadel:local). Requires Docker daemon.",
"dependsOn": [
"build-linux"
],
"command": "bash -c 'docker build --build-arg TARGETPLATFORM=linux/$(go env GOARCH) --build-arg BINARY=zitadel.local -f apps/api/Dockerfile -t zitadel/zitadel:local .'",
"cache": false
},
"generate": {
"description": "Generates the code needed to start a full-featured API: gRPC and OpenAPI stubs, static files for the embedded login v1, asset routes and documentation.",
"dependsOn": [
"generate-stubs",
"generate-assets",
"generate-statik"
]
},
"lint-install": {
"description": "Installs golangci-lint binary for linting. Using go install is not recommended in the official docs, because this can produce non-deterministic results.",
"cache": true,
"command": "curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/HEAD/install.sh | sh -s -- -b .artifacts/bin/$(go env GOOS)/$(go env GOARCH) v2.11.3",
"inputs": [
{
"runtime": "go env GOOS"
},
{
"runtime": "go env GOARCH"
}
],
"outputs": [
"{workspaceRoot}/.artifacts/bin/*/*/golangci-lint"
]
},
"lint": {
"description": "Lints the Go code with golangci-lint using the configuration in .golangci.yaml",
"dependsOn": [
"lint-install",
"generate-stubs",
"generate-assets"
],
"command": "PATH=\"${PWD}/.artifacts/bin/$(go env GOOS)/$(go env GOARCH):$PATH\" golangci-lint run --timeout 15m --config ./.golangci.yaml --verbose",
"cache": true,
"inputs": [
"sources",
"{workspaceRoot}/.golangci.yaml"
]
},
"test": {
"description": "Runs all tests (unit and integration)",
"dependsOn": [
"test-unit",
"test-integration"
]
},
"test-unit": {
"description": "Runs the unit tests with coverage",
"dependsOn": [
"generate"
],
"cache": true,
"command": "go test -race -coverprofile=profile.api.test-unit.cov -coverpkg=./internal/...,./backend/... ./...",
"inputs": [
"sources",
"{workspaceRoot}/go*"
],
"outputs": [
"{workspaceRoot}/profile.api.test-unit.cov"
]
},
"test-integration-build": {
"description": "Builds the test binary for integration tests.",
"dependsOn": [
"generate"
],
"command": "go build -cover -race -tags integration -o .artifacts/bin/$(go env GOOS)/$(go env GOARCH)/zitadel.test main.go",
"cache": false,
"inputs": [
{
"runtime": "go env GOOS"
},
{
"runtime": "go env GOARCH"
},
"sources",
"{workspaceRoot}/internal/integration/**",
"{workspaceRoot}/go*"
],
"outputs": [
"{workspaceRoot}/.artifacts/bin/*/*/zitadel.test"
]
},
"test-integration-run-db": {
"description": "Runs the database and cache for integration tests.",
"continuous": true,
"command": "nx run @zitadel/devcontainer:compose up --force-recreate --renew-anon-volumes db-api-integration cache-api-integration"
},
"test-integration-run-api": {
"description": "Runs the API server for the integration tests.",
"continuous": true,
"dependsOn": [
"test-integration-build"
],
"executor": "nx:run-commands",
"options": {
"env": {
"ZITADEL_BINARY": "zitadel.test",
"GOCOVERDIR": "{workspaceRoot}/.artifacts/api-test-integration/coverage",
"GORACE": "log_path=.artifacts/api-test-integration/race.log"
},
"parallel": false,
"commands": [
"rm -rf .artifacts/api-test-integration",
"mkdir -p ${GOCOVERDIR}",
"nx run @zitadel/api:prod:test-integration-api --excludeTaskDependencies"
]
}
},
"test-integration": {
"description": "Runs the integration tests sequentially with coverage and race condition detection. Go test caching is disabled, because the tests run against an out-of-process API.",
"dependsOn": [
"test-integration-run-db",
"test-integration-run-api"
],
"executor": "nx:run-commands",
"options": {
"parallel": false,
"env": {
"GOCOVERDIR": "{workspaceRoot}/.artifacts/api-test-integration/coverage"
},
"commands": [
"wait-on --verbose --interval 2000 --simultaneous 1 --timeout 30m \"${ZITADEL_API_URL}/debug/ready\"",
"bash -c 'go test -race -count 1 -tags integration -timeout 60m -parallel 1 $(go list -tags integration ./... | grep -e \"integration_test\")'",
"go tool covdata textfmt -i=$GOCOVERDIR -pkg=github.com/zitadel/zitadel/internal/...,github.com/zitadel/zitadel/cmd/... -o profile.api.test-integration.cov",
"nx run @zitadel/api:test-integration-stop"
]
},
"inputs": [
{
"runtime": "go env GOOS"
},
{
"runtime": "go env GOARCH"
},
"sources",
"{workspaceRoot}/internal/integration/**",
"{workspaceRoot}/go*"
],
"outputs": [
"{workspaceRoot}/profile.api.test-integration.cov"
]
},
"test-integration-stop": {
"description": "Stops the database and cache containers used for integration tests.",
"command": "nx run @zitadel/devcontainer:compose down --volumes db-api-integration cache-api-integration"
},
"build-console": {
"description": "Builds the Management Console and copies its static files to the API.",
"dependsOn": [
"@zitadel/console:build"
],
"command": "find internal/api/ui/console/static -mindepth 1 ! -name 'gitkeep' -delete -print && cp -r -v console/dist/console/* internal/api/ui/console/static",
"cache": true,
"inputs": [
{
"dependentTasksOutputFiles": "console/dist/console/**/*"
}
],
"outputs": [
"{workspaceRoot}/internal/api/ui/console/static"
]
},
"generate-install": {
"description": "Installs the binaries needed for generating code. We avoid using go tools so the dev tool dependencies don't interfere with the prod dependencies.",
"executor": "nx:run-commands",
"options": {
"commands": [
"GOBIN=${PWD}/.artifacts/bin/$(go env GOOS)/$(go env GOARCH) go install github.com/daixiang0/gci@v0.14.0",
"GOBIN=${PWD}/.artifacts/bin/$(go env GOOS)/$(go env GOARCH) go install github.com/dmarkham/enumer@v1.6.3",
"GOBIN=${PWD}/.artifacts/bin/$(go env GOOS)/$(go env GOARCH) go install go.uber.org/mock/mockgen@v0.6.0",
"GOBIN=${PWD}/.artifacts/bin/$(go env GOOS)/$(go env GOARCH) go install golang.org/x/tools/cmd/stringer@v0.43.0",
"GOBIN=${PWD}/.artifacts/bin/$(go env GOOS)/$(go env GOARCH) go install github.com/rakyll/statik@v0.1.8",
"GOBIN=${PWD}/.artifacts/bin/$(go env GOOS)/$(go env GOARCH) go install github.com/bufbuild/buf/cmd/buf@v1.67.0",
"GOBIN=${PWD}/.artifacts/bin/$(go env GOOS)/$(go env GOARCH) go install google.golang.org/protobuf/cmd/protoc-gen-go@v1.36.11",
"GOBIN=${PWD}/.artifacts/bin/$(go env GOOS)/$(go env GOARCH) go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@v1.6.1",
"GOBIN=${PWD}/.artifacts/bin/$(go env GOOS)/$(go env GOARCH) go install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway@v2.28.0",
"GOBIN=${PWD}/.artifacts/bin/$(go env GOOS)/$(go env GOARCH) go install github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2@v2.28.0",
"GOBIN=${PWD}/.artifacts/bin/$(go env GOOS)/$(go env GOARCH) go install github.com/envoyproxy/protoc-gen-validate@v1.3.3",
"GOBIN=${PWD}/.artifacts/bin/$(go env GOOS)/$(go env GOARCH) go install connectrpc.com/connect/cmd/protoc-gen-connect-go@v1.19.1",
"GOBIN=${PWD}/.artifacts/bin/$(go env GOOS)/$(go env GOARCH) go install ./internal/protoc/protoc-gen-authoption",
"GOBIN=${PWD}/.artifacts/bin/$(go env GOOS)/$(go env GOARCH) go install ./internal/protoc/protoc-gen-zitadel"
]
},
"cache": true,
"inputs": [
{
"runtime": "go env GOOS"
},
{
"runtime": "go env GOARCH"
},
"{workspaceRoot}/internal/protoc/protoc-gen-authoption/**/*",
"{workspaceRoot}/internal/protoc/protoc-gen-zitadel/**/*"
],
"outputs": [
"{workspaceRoot}/.artifacts/bin/*/*/enumer",
"{workspaceRoot}/.artifacts/bin/*/*/mockgen",
"{workspaceRoot}/.artifacts/bin/*/*/stringer",
"{workspaceRoot}/.artifacts/bin/*/*/statik",
"{workspaceRoot}/.artifacts/bin/*/*/buf",
"{workspaceRoot}/.artifacts/bin/*/*/protoc-gen-go",
"{workspaceRoot}/.artifacts/bin/*/*/protoc-gen-go-grpc",
"{workspaceRoot}/.artifacts/bin/*/*/protoc-gen-grpc-gateway",
"{workspaceRoot}/.artifacts/bin/*/*/protoc-gen-openapiv2",
"{workspaceRoot}/.artifacts/bin/*/*/protoc-gen-validate",
"{workspaceRoot}/.artifacts/bin/*/*/protoc-gen-connect-go",
"{workspaceRoot}/.artifacts/bin/*/*/protoc-gen-authoption",
"{workspaceRoot}/.artifacts/bin/*/*/protoc-gen-zitadel"
]
},
"generate-stubs": {
"description": "Generates the gRPC and OpenAPI stubs from the proto files.",
"dependsOn": [
"generate-install"
],
"executor": "nx:run-commands",
"options": {
"parallel": false,
"commands": [
"bash -c 'PATH=\"${PWD}/.artifacts/bin/$(go env GOOS)/$(go env GOARCH):$PATH\" buf generate'",
"mkdir -p pkg/grpc openapi/v2/zitadel",
"cp -r .artifacts/grpc/github.com/zitadel/zitadel/pkg/grpc/** pkg/grpc/",
"cp -r .artifacts/grpc/zitadel/ openapi/v2/zitadel"
]
},
"cache": true,
"inputs": [
"{workspaceRoot}/proto/**/*",
"{workspaceRoot}/buf.gen.yaml",
"{workspaceRoot}/buf.yaml"
],
"outputs": [
"{workspaceRoot}/pkg/grpc/**/*",
"{workspaceRoot}/openapi/v2/zitadel/**/*"
]
},
"generate-statik": {
"description": "Generates statik files for embedding static resources",
"dependsOn": [
"generate-install"
],
"executor": "nx:run-commands",
"options": {
"commands": [
"PATH=\"${PWD}/.artifacts/bin/$(go env GOOS)/$(go env GOARCH):$PATH\" go generate internal/api/ui/login/static/resources/generate.go",
"PATH=\"${PWD}/.artifacts/bin/$(go env GOOS)/$(go env GOARCH):$PATH\" go generate internal/api/ui/login/statik/generate.go",
"PATH=\"${PWD}/.artifacts/bin/$(go env GOOS)/$(go env GOARCH):$PATH\" go generate internal/notification/statik/generate.go",
"PATH=\"${PWD}/.artifacts/bin/$(go env GOOS)/$(go env GOARCH):$PATH\" go generate internal/statik/generate.go"
],
"parallel": false
},
"cache": true,
"inputs": [
{
"runtime": "go env GOOS"
},
{
"runtime": "go env GOARCH"
},
"{workspaceRoot}/internal/statik/generate.go",
"{workspaceRoot}/internal/static/**/*",
"{workspaceRoot}/internal/notification/statik/generate.go",
"{workspaceRoot}/internal/notification/static/**/*",
"{workspaceRoot}/internal/api/ui/login/static/resources/generate.go",
"{workspaceRoot}/internal/api/ui/login/statik/generate.go",
"{workspaceRoot}/internal/api/ui/login/static/**/*"
],
"outputs": [
"{workspaceRoot}/internal/statik/statik.go",
"{workspaceRoot}/internal/notification/statik/statik.go",
"{workspaceRoot}/internal/api/ui/login/static/resources/themes/zitadel/css/zitadel.css*",
"{workspaceRoot}/internal/api/ui/login/statik/statik.go"
]
},
"generate-assets": {
"description": "Generates asset routes and documentation",
"dependsOn": [
"generate-install"
],
"command": "mkdir -p apps/docs/content/apis/assets && go run internal/api/assets/generator/asset_generator.go -directory=internal/api/assets/generator/ -assets=apps/docs/content/apis/assets/assets.mdx",
"cache": true,
"inputs": [
"{workspaceRoot}/internal/api/assets/generator/**/*"
],
"outputs": [
"{workspaceRoot}/internal/api/assets/authz.go",
"{workspaceRoot}/internal/api/assets/router.go",
"{workspaceRoot}/apps/docs/content/apis/assets/assets.mdx"
]
},
"generate-go": {
"description": "Generates Go using Go native generation tools. This only needs to be run if sources for //go:generate files change, like for Stringer, Enumer, Mockgen etc.",
"dependsOn": [
"generate-install"
],
"command": "PATH=\"${PWD}/.artifacts/bin/$(go env GOOS)/$(go env GOARCH):$PATH\" go generate ./..."
},
"pack-platform": {
"description": "Cross-compiles the binary and packages it for the platform defined by GOOS and GOARCH environment variables. The version is taken from the ZITADEL_VERSION environment variable.",
"executor": "nx:run-commands",
"options": {
"parallel": false,
"commands": [
"mkdir -p .artifacts/pack .artifacts/bin/$GOOS/$GOARCH",
"bash -c 'EXT=\"\"; if [ \"$GOOS\" = \"windows\" ]; then EXT=\".exe\"; fi; echo \"Building for $GOOS-$GOARCH (GOFIPS140=${ZITADEL_GOFIPS140:-off})...\"; CGO_ENABLED=0 GOFIPS140=${ZITADEL_GOFIPS140:-off} go build -o .artifacts/bin/$GOOS/$GOARCH/zitadel$EXT -ldflags=\"-s -w -X github.com/zitadel/zitadel/cmd/build.commit=$(git rev-parse --short HEAD) -X github.com/zitadel/zitadel/cmd/build.date=$(date \"+%Y-%m-%dT%T%z\" | sed -E \"s/.([0-9]{2})([0-9]{2})$/-\\1:\\2/\") -X github.com/zitadel/zitadel/cmd/build.version=${ZITADEL_VERSION}\"'",
"bash -c 'EXT=\"\"; if [ \"$GOOS\" = \"windows\" ]; then EXT=\".exe\"; fi; FOLDER=\"zitadel-$GOOS-$GOARCH\"; mkdir -p \".artifacts/pack/$FOLDER\"; cp README.md LICENSE \".artifacts/bin/$GOOS/$GOARCH/zitadel$EXT\" \".artifacts/pack/$FOLDER/\"; tar -czvf \".artifacts/pack/$FOLDER.tar.gz\" -C .artifacts/pack \"$FOLDER\"; rm -rf \".artifacts/pack/$FOLDER\"'"
]
}
},
"pack-darwin-amd64": {
"description": "Packages the API for Darwin AMD64 (Intel) architecture",
"dependsOn": [
"generate",
"build-console"
],
"command": "GOOS=darwin GOARCH=amd64 nx run @zitadel/api:pack-platform",
"cache": true,
"inputs": [
"pack",
{
"env": "ZITADEL_VERSION"
}
],
"outputs": [
"{workspaceRoot}/.artifacts/pack/zitadel-darwin-amd64.tar.gz",
"{workspaceRoot}/.artifacts/bin/darwin/amd64/zitadel"
]
},
"pack-darwin-arm64": {
"description": "Packages the API for Darwin ARM64 (Apple Silicon) architecture",
"dependsOn": [
"generate",
"build-console"
],
"command": "GOOS=darwin GOARCH=arm64 nx run @zitadel/api:pack-platform",
"cache": true,
"inputs": [
"pack",
{
"env": "ZITADEL_VERSION"
}
],
"outputs": [
"{workspaceRoot}/.artifacts/pack/zitadel-darwin-arm64.tar.gz",
"{workspaceRoot}/.artifacts/bin/darwin/arm64/zitadel"
]
},
"pack-linux-amd64": {
"description": "Packages the API for Linux AMD64 architecture",
"dependsOn": [
"generate",
"build-console"
],
"command": "GOOS=linux GOARCH=amd64 nx run @zitadel/api:pack-platform",
"cache": true,
"inputs": [
"pack",
{
"env": "ZITADEL_VERSION"
}
],
"outputs": [
"{workspaceRoot}/.artifacts/pack/zitadel-linux-amd64.tar.gz",
"{workspaceRoot}/.artifacts/bin/linux/amd64/zitadel"
]
},
"pack-linux-arm64": {
"description": "Packages the API for Linux ARM64 architecture",
"dependsOn": [
"generate",
"build-console"
],
"command": "GOOS=linux GOARCH=arm64 nx run @zitadel/api:pack-platform",
"cache": true,
"inputs": [
"pack",
{
"env": "ZITADEL_VERSION"
}
],
"outputs": [
"{workspaceRoot}/.artifacts/pack/zitadel-linux-arm64.tar.gz",
"{workspaceRoot}/.artifacts/bin/linux/arm64/zitadel"
]
},
"pack-windows-amd64": {
"description": "Packages the API for Windows AMD64 architecture",
"dependsOn": [
"generate",
"build-console"
],
"command": "GOOS=windows GOARCH=amd64 nx run @zitadel/api:pack-platform",
"cache": true,
"inputs": [
"pack",
{
"env": "ZITADEL_VERSION"
}
],
"outputs": [
"{workspaceRoot}/.artifacts/pack/zitadel-windows-amd64.tar.gz",
"{workspaceRoot}/.artifacts/bin/windows/amd64/zitadel.exe"
]
},
"pack-windows-arm64": {
"description": "Packages the API for Windows ARM64 architecture",
"dependsOn": [
"generate",
"build-console"
],
"command": "GOOS=windows GOARCH=arm64 nx run @zitadel/api:pack-platform",
"cache": true,
"inputs": [
"pack",
{
"env": "ZITADEL_VERSION"
}
],
"outputs": [
"{workspaceRoot}/.artifacts/pack/zitadel-windows-arm64.tar.gz",
"{workspaceRoot}/.artifacts/bin/windows/arm64/zitadel.exe"
]
}
}
}