Commit ae93a37
[core/http] Fix FIPS-mode cookie sealing (Deriving bits failed) (elastic#268045)
> [!IMPORTANT]
> this is a backwards-incompatible change. Existing sessions will be
terminated following an upgrade to a version which includes this change
## Summary
In FIPS mode, login succeeds at the auth layer but the very next
response (the post-login redirect that sets the `sid` cookie) fails
with:
```
Failed to encode cookie (sid) value: Deriving bits failed
```
…and the user is bounced back to the login page.
Root cause: `@hapi/iron`'s PBKDF2 defaults are `iterations: 1`, which
OpenSSL's FIPS provider rejects (`SP 800-132` requires ≥ 1000
iterations). This PR plumbs a custom `iron` config through the
auth-cookie strategy in `cookie_session_storage.ts`, setting iterations
to **1000** for both encryption and integrity blocks.
## Why 1000
- `SP 800-132` minimum for FIPS-approved PBKDF2 — clears the OpenSSL
FIPS check.
- Iron caps PBKDF2's load to one call per seal/unseal, so cookie work
happens once at login + once per authenticated request. 1000 iterations
is ~1 ms; bumping higher would add user-visible latency to every
authenticated request without buying real security here.
- The iteration count's job is to slow down brute force on weak
passwords. Kibana already requires `xpack.security.encryptionKey` to be
≥ 32 characters, so the input is already high-entropy random material.
## Risk / impact
- **Cookie format changes.** Existing `sid` cookies in user browsers
will fail to decrypt after upgrade, forcing a single re-login. No data
loss; worth a release note.
- The `iron` field is officially typed on `StateOptions` from
`@hapi/statehood` and forwarded to `Iron.seal`/`Iron.unseal`, so this is
a supported usage path.
- No behavior change for non-FIPS deployments beyond the cookie-format
reset.
## How it was found
Reproduced locally against the 9.3.4 staging FIPS build
(`elasticsearch-cloud-ess-fips` + `kibana-cloud-fips`):
1. Without the fix: login → redirect → `Deriving bits failed` → bounce
to login page.
2. Verified the failing call path by tracing
`@hapi/statehood/lib/index.js:486 → prepareValue → Iron.seal` (default
`iterations: 1`).
3. Confirmed `iterations: 1000` clears OpenSSL FIPS rejection in
isolation against bundled Node, and that `iron` propagates correctly
through `@hapi/cookie`'s `.unknown()` schema → `server.state()` →
statehood → iron.
4. Patched the running Kibana container with this exact change; login
then completes successfully.
## Test plan
- [ ] CI green
- [ ] Manual: bring up a FIPS-mode Kibana + ES, log in as `elastic`,
confirm no `Deriving bits failed` and that the session persists across
page refreshes
- [ ] Manual: non-FIPS deployment — verify login still works and
existing sessions are reset cleanly (one expected re-login on first
deploy)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Larry Gregory <larry.gregory@elastic.co>1 parent eb74355 commit ae93a37
1 file changed
Lines changed: 18 additions & 0 deletions
Lines changed: 18 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
150 | 150 | | |
151 | 151 | | |
152 | 152 | | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
153 | 171 | | |
154 | 172 | | |
155 | 173 | | |
| |||
0 commit comments