PKI: Allow the HTTP post body to be reread for binary paths (#12290) (#12316)

* PKI: Allow the HTTP post body to be reread for binary paths

* Use a TeeReader to simplify the solution

* Add test and cl

* Apply suggestions from code review



* PR feedback

---------

Co-authored-by: Steven Clark <steven.clark@hashicorp.com>
Co-authored-by: Nick Cabatoff <ncabatoff@hashicorp.com>
This commit is contained in:
Vault Automation 2026-02-12 11:59:59 -05:00 committed by GitHub
parent a407faa971
commit b6e3759673
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 21 additions and 0 deletions

3
changelog/_12290.txt Normal file
View file

@ -0,0 +1,3 @@
```release-note:bug
core (enterprise): Buffer the POST body on binary paths to allow re-reading on non-logical forwarding attempts. Addresses an issue for SCEP, EST and CMPv2 certificate issuances with slow replication of entities
```

View file

@ -5,6 +5,7 @@ package http
import (
"bufio"
"bytes"
"encoding/base64"
"encoding/json"
"fmt"
@ -430,6 +431,17 @@ func handleLogicalInternal(core *vault.Core, injectDataIntoTopLevel bool, noForw
return
}
// For binary paths we expect the plugin to read directly from the body so we need to ensure
// the original body is still available for the forwarding case on entity creation on a perf standby
var binaryBuf *bytes.Buffer
ra := core.RouterAccess()
if ra.IsBinaryPath(r.Context(), trimmedPath) {
binaryBuf = &bytes.Buffer{}
binaryTeeReader := io.NopCloser(io.TeeReader(r.Body, binaryBuf))
r.Body = binaryTeeReader
r = r.WithContext(logical.CreateContextOriginalBody(r.Context(), binaryTeeReader))
}
// Make the internal request. We attach the connection info
// as well in case this is an authentication request that requires
// it. Vault core handles stripping this if we need to. This also
@ -445,6 +457,12 @@ func handleLogicalInternal(core *vault.Core, injectDataIntoTopLevel bool, noForw
return
case needsForward && !noForward:
if origBody != nil {
if binaryBuf != nil && binaryBuf.Len() > 0 {
// If this is a binary path, we may need to use the buffered body for forwarding
// since the original body has been consumed by the plugin. We can use the buffered
// data to create a new reader for the forward request.
origBody = newMultiReaderCloser(origBody, binaryBuf)
}
r.Body = origBody
}
forwardRequest(core, w, r)