diff --git a/changelog/_12290.txt b/changelog/_12290.txt new file mode 100644 index 0000000000..49f37e8258 --- /dev/null +++ b/changelog/_12290.txt @@ -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 +``` diff --git a/http/logical.go b/http/logical.go index 00160d3eac..95a5fe4ee9 100644 --- a/http/logical.go +++ b/http/logical.go @@ -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)