{"record":{"id":"e0a705c76513fb8f","repo":"OpenNHP/opennhp","slug":"failed-to-generate-random-cookie-signing-key-v","errorCode":null,"errorMessage":"failed to generate random cookie signing key: %v","messagePattern":"failed to generate random cookie signing key: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"endpoints/server/udpserver.go","lineNumber":298,"sourceCode":"\t// verify a cookie that a sibling minted. When the operator hasn't\n\t// configured one we mint a random per-process key — fine for a single\n\t// instance, broken for a cluster (the failure is silent: cookies\n\t// minted by replica A don't verify on replica B and the agent's RKN\n\t// stalls until timeout). Always log which mode we're in.\n\tcookieKey, cookieKeyErr := decodeCookieSigningKey(s.config.CookieSigningKeyBase64)\n\tif cookieKeyErr != nil {\n\t\t// Malformed (not empty) is an ops mistake — fail fast rather\n\t\t// than silently degrading to a per-process random key. Silent\n\t\t// fallback would let a cluster look healthy while its replicas\n\t\t// each mint cookies a sibling can't verify.\n\t\tlog.Critical(\"invalid CookieSigningKeyBase64 in config: %v\", cookieKeyErr)\n\t\treturn fmt.Errorf(\"invalid CookieSigningKeyBase64: %w\", cookieKeyErr)\n\t}\n\tif len(cookieKey) == 0 {\n\t\tcookieKey = make([]byte, 32)\n\t\tif _, readErr := rand.Read(cookieKey); readErr != nil {\n\t\t\tlog.Critical(\"failed to generate random cookie signing key: %v\", readErr)\n\t\t\treturn fmt.Errorf(\"failed to generate random cookie signing key: %v\", readErr)\n\t\t}\n\t\tlog.Info(\"CookieSigningKeyBase64 not set; using a random per-process key (single-instance only — clusters must share an operator-supplied key)\")\n\t} else {\n\t\tlog.Info(\"CookieSigningKeyBase64 configured; cookies are stateless and shared across the cluster\")\n\t\t// Catch operators who copy the docker-compose demo config and\n\t\t// forget to regenerate the shared key. The shipped value is\n\t\t// public (committed to docker/nhp-server/etc/config.toml so\n\t\t// `docker-compose up` works out of the box) — running it in\n\t\t// any environment a real client can reach lets anyone who has\n\t\t// browsed the repo mint cookies the server will accept.\n\t\t// Critical (not Warning) so it surfaces in default journalctl\n\t\t// filters and any oncall log-volume alarms.\n\t\tif s.config.CookieSigningKeyBase64 == shippedDemoCookieSigningKeyBase64 {\n\t\t\tlog.Critical(\"CookieSigningKeyBase64 matches the docker-compose demo value committed at \" +\n\t\t\t\t\"docker/nhp-server/etc/config.toml — this key is PUBLIC. Regenerate before any \" +\n\t\t\t\t\"deployment reachable from outside the host (use `nhp-serverd keygen --curve` or \" +\n\t\t\t\t\"`openssl rand -base64 32`).\")\n\t\t}","sourceCodeStart":280,"sourceCodeEnd":316,"githubUrl":"https://github.com/OpenNHP/opennhp/blob/6e04ca5ff03222a699c24205cd4bf8fee9af7ffe/endpoints/server/udpserver.go#L280-L316","documentation":"UdpServer.Start generates a random 32-byte cookie signing key when CookieSigningKeyBase64 is unset, and returns this error if crypto/rand fails to produce those bytes. This is an environment/OS-level entropy failure, not a config problem.","triggerScenarios":"Calling Start with an empty CookieSigningKeyBase64 while rand.Read on the 32-byte buffer returns an error (e.g. exhausted or blocked system entropy source).","commonSituations":"Containers/seccomp profiles blocking getrandom(2); misconfigured chroots lacking /dev/urandom; heavily degraded kernels in embedded environments.","solutions":["Restart the process — rand.Read failures are typically transient OS-level conditions","Fix the container sandbox so getrandom(2)/getentropy is permitted (adjust seccomp/AppArmor profile)","Ensure /dev/urandom is available in the container or jail","Set CookieSigningKeyBase64 explicitly to skip the random-generation path entirely"],"exampleFix":"// before (docker run)\ndocker run --security-opt seccomp:strict-random.json nhp-server\n// after (allow getrandom in the profile, or pre-supply the key)\nenvironment:\n  - CookieSigningKeyBase64=<base64 32-byte key>","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := srv.Start(); err != nil {\n    if strings.Contains(err.Error(), \"random cookie signing key\") {\n        log.Fatalf(\"entropy unavailable on host: %v — fix OS randomness source or set CookieSigningKeyBase64\", err)\n    }\n    return err\n}","preventionTips":["Pre-supply CookieSigningKeyBase64 so the rand.Read path is never exercised in production","Verify containers permit getrandom(2) before shipping seccomp profiles","Confirm /dev/urandom exists in minimal images"],"tags":["crypto","entropy","startup"],"backgroundTag":"internal-invariant-violation","analyzedSha":"6e04ca5ff03222a699c24205cd4bf8fee9af7ffe","analyzedAt":"2026-09-07T15:44:59.941Z","contentChangedAt":"2026-09-07T15:44:59.941Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}