Migrating to Nauthilus v4
Nauthilus v4 establishes deliberate compatibility boundaries for the Go module and native plugin ABI, Policy
configuration and APIs, public Go protobuf imports, browser session state, and IdP token state. This guide targets the
stable v4.0.0 release and an upgrade from the 3.1 line. The 4.0.0 release notes summarize
every breaking change, the additional steps for v4 prereleases, and the new features. Validate the complete deployment
in a non-production environment before rollout.
Migration Checklist
- Replace only the exact module prefix
github.com/croessner/nauthilus/v3withgithub.com/croessner/nauthilus/v4. - Use Go 1.27.1 with
GOEXPERIMENT=runtimesecret. Rebuild every native.soagainst the exact host commit, toolchain, module graph, build tags, CGO mode, OS, and architecture, and embed the host's native artifact identity with-ldflags "$(go run -mod=vendor ./scripts/native_artifact_fingerprint)". Unmarked artifacts are rejected. - Manually migrate the removed v3
auth.policysubtree to top-levelpolicy. There is no converter, dual root, or compatibility window. - Replace unqualified
standard_auth, rule/checkstage, and checkconfig_refwith exact qualified identities and checkpoint ownership. Move record-predicate fields fromrecords.fieldinto therecords.whereleaves, and use onlypermit/deny(plustempfail/neutralinauthn) as rule decisions. - Configure Generic Policy callers separately from management and backchannel callers. Preserve exact audience, scope, target, schema, fact, diagnostics, rate, concurrency, and optional mTLS admission.
- Update native plugins: declare
ReplaySafetyon every effect descriptor, grantallow_capabilities: [password_hash]to modules that read password digests (for example ClickHouse), and make sure admin hooks are only used bynauthilus:admincallers. - Add
decision_bindingsto every GeoIP module. Remove the Luageoip_reputation.luaplugin and its settings, and switch to the bundledreputationplugin if you need reputation data. - Replace the complete browser-serving pool uniformly. Do not mix v3.1 and v4 session readers or try to migrate in-flight browser state. Old records remain inert and can expire.
- Prepare the IdP Redis hard cut: Redis 6.2 or newer with
maxmemory-policy noevictionand a mandatorystorage.redis.encryption_secret. All tokens, device flows, and unredeemed codes are invalidated; clients must reauthenticate. Operators coming from a v4 prerelease with dynamic clients also remove the oldoidc:dcr:{dynamic}:*andoidc:dcr:{registry}:activekeys and register dynamic clients again. Edge nodes replace rejected authority caller tokens on their own, so no manual edge token flush is needed. - Validate the direct MFA self-service entry, which now requires MFA for users with an enrolled factor, and each TOTP, WebAuthn, recovery-code, enrollment, and step-up flow.
- Review brute-force bucket limits: every distinct wrong password now counts immediately, while backend faults are no longer counted.
- Check reverse proxies: all
X-Forwarded-Forlines are evaluated. An invalid chain falls back to the direct peer, not toX-Real-IP;X-Real-IPstill applies when noX-Forwarded-Forheader is sent. - Regenerate Go clients that consume v4
go_packagemetadata. Independently generated protobuf clients remain wire compatible where their package, service, method, field, and HTTP identifiers are unchanged. - If you used the
dkim2-reputationmodule of an early v4 prerelease, replace it withgeoip+reputation+dkim2-intelligence, convert static data withscripts/convert-static-reputation.py, and keep enforcement off until a livedkim2dend-to-end run passes. - Run
nauthilus --config-checkagainst the final configuration. Authn rules must fit their checkpoint position (permit,deny, ortempfailat the final checkpoint;deny,tempfail, orneutralearlier), and an explicitfsm_event_markermust match decision and checkpoint. Omitted markers are still derived. - Make sure every authn
permitrule tests the host evidence it relies on (for examplebackend.authenticated), because a permit without host evidence fails closed as a temporary failure. Alert onauthn_fsm_guard_violations_total. - Review the LDAP pool settings of every pool section. Timeouts, size and time limits, retry, circuit-breaker, health,
cache, and
auth_rate_limit_*options now apply to every pool connection. - Point Kubernetes liveness probes at
/livezand keep/healthzfor readiness and startup probes, with a startup budget that covers the Redis readiness loop and the reputation start retry. - Update dashboards for the pipelined brute-force Redis labels of
bruteforce_redis_roundtrips_total, the halved failed-login share ofredis_write_total, and the new mail andjmapprotocol labels ofauthentication_response_time_seconds. - If the HTTP rate middleware is enabled, remember that the per-IP limit on caller-authenticated
/api/v1routes is a failure budget, and thatauth.pipeline.max_concurrent_requestsnow bounds the gRPC authority as well. - Optional features: enable the LDAP identity lookup cache (
storage.redis.identity_cache), Redis password caching for native backend modules (plugins.modules[].positive_password_cachewith plugin support),observability.log.notice_ignore_fields, and OIDC resource indicators (token_introspection) only after testing. Resource servers that readaudmust accept an array once resources are granted. - Validate the entire candidate in a non-production environment before any production rollout.
Detailed Contracts
- Nauthilus 4.0.0 release notes
- Policy configuration hard cut and manual migration
- Policy configuration overview
- Generic Policy REST and gRPC API
- Canonical browser session migration
- MFA self-service portal
- OIDC Dynamic Client Registration
- Native Go plugin guide
- Public protobuf APIs
- DKIM2/Rspamd Policy integration
- Reputation operations
- Generated protected HTTP API reference
Third-party module paths that independently contain a /v3 suffix are unrelated and must not be rewritten. The retired
browser /api/v1/mfa/* routes must not be confused with the separate cookie-free /api/v1/mfa-backchannel/* family.