Recovery Mode (#7559)

* Initial work

* rework

* s/dr/recovery

* Add sys/raw support to recovery mode (#7577)

* Factor the raw paths out so they can be run with a SystemBackend.

# Conflicts:
#	vault/logical_system.go

* Add handleLogicalRecovery which is like handleLogical but is only
sufficient for use with the sys-raw endpoint in recovery mode.  No
authentication is done yet.

* Integrate with recovery-mode.  We now handle unauthenticated sys/raw
requests, albeit on path v1/raw instead v1/sys/raw.

* Use sys/raw instead raw during recovery.

* Don't bother persisting the recovery token.  Authenticate sys/raw
requests with it.

* RecoveryMode: Support generate-root for autounseals (#7591)

* Recovery: Abstract config creation and log settings

* Recovery mode integration test. (#7600)

* Recovery: Touch up (#7607)

* Recovery: Touch up

* revert the raw backend creation changes

* Added recovery operation token prefix

* Move RawBackend to its own file

* Update API path and hit it using CLI flag on generate-root

* Fix a panic triggered when handling a request that yields a nil response. (#7618)

* Improve integ test to actually make changes while in recovery mode and
verify they're still there after coming back in regular mode.

* Refuse to allow a second recovery token to be generated.

* Resize raft cluster to size 1 and start as leader (#7626)

* RecoveryMode: Setup raft cluster post unseal (#7635)

* Setup raft cluster post unseal in recovery mode

* Remove marking as unsealed as its not needed

* Address review comments

* Accept only one seal config in recovery mode as there is no scope for migration
This commit is contained in:
Vishal Nayak
2019-10-15 00:55:31 -04:00
committed by GitHub
parent 9de6e1bfd0
commit 2f4ae7f215
24 changed files with 1264 additions and 413 deletions

View File

@@ -4,6 +4,8 @@ import (
"encoding/base64"
"encoding/json"
"fmt"
"github.com/hashicorp/vault/sdk/helper/consts"
"go.uber.org/atomic"
"io"
"net"
"net/http"
@@ -18,7 +20,7 @@ import (
"github.com/hashicorp/vault/vault"
)
func buildLogicalRequest(core *vault.Core, w http.ResponseWriter, r *http.Request) (*logical.Request, io.ReadCloser, int, error) {
func buildLogicalRequestNoAuth(perfStandby bool, w http.ResponseWriter, r *http.Request) (*logical.Request, io.ReadCloser, int, error) {
ns, err := namespace.FromContext(r.Context())
if err != nil {
return nil, nil, http.StatusBadRequest, nil
@@ -78,7 +80,7 @@ func buildLogicalRequest(core *vault.Core, w http.ResponseWriter, r *http.Reques
passHTTPReq = true
origBody = r.Body
} else {
origBody, err = parseRequest(core, r, w, &data)
origBody, err = parseRequest(perfStandby, r, w, &data)
if err == io.EOF {
data = nil
err = nil
@@ -105,14 +107,32 @@ func buildLogicalRequest(core *vault.Core, w http.ResponseWriter, r *http.Reques
return nil, nil, http.StatusBadRequest, errwrap.Wrapf("failed to generate identifier for the request: {{err}}", err)
}
req, err := requestAuth(core, r, &logical.Request{
req := &logical.Request{
ID: request_id,
Operation: op,
Path: path,
Data: data,
Connection: getConnection(r),
Headers: r.Header,
})
}
if passHTTPReq {
req.HTTPRequest = r
}
if responseWriter != nil {
req.ResponseWriter = logical.NewHTTPResponseWriter(responseWriter)
}
return req, origBody, 0, nil
}
func buildLogicalRequest(core *vault.Core, w http.ResponseWriter, r *http.Request) (*logical.Request, io.ReadCloser, int, error) {
req, origBody, status, err := buildLogicalRequestNoAuth(core.PerfStandby(), w, r)
if err != nil {
return nil, nil, status, err
}
req, err = requestAuth(core, r, req)
if err != nil {
if errwrap.Contains(err, logical.ErrPermissionDenied.Error()) {
return nil, nil, http.StatusForbidden, nil
@@ -135,12 +155,6 @@ func buildLogicalRequest(core *vault.Core, w http.ResponseWriter, r *http.Reques
return nil, nil, http.StatusBadRequest, errwrap.Wrapf(fmt.Sprintf(`failed to parse %s header: {{err}}`, PolicyOverrideHeaderName), err)
}
if passHTTPReq {
req.HTTPRequest = r
}
if responseWriter != nil {
req.ResponseWriter = logical.NewHTTPResponseWriter(responseWriter)
}
return req, origBody, 0, nil
}
@@ -168,6 +182,32 @@ func handleLogicalNoForward(core *vault.Core) http.Handler {
return handleLogicalInternal(core, false, true)
}
func handleLogicalRecovery(raw *vault.RawBackend, token *atomic.String) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
req, _, statusCode, err := buildLogicalRequestNoAuth(false, w, r)
if err != nil || statusCode != 0 {
respondError(w, statusCode, err)
return
}
reqToken := r.Header.Get(consts.AuthHeaderName)
if reqToken == "" || token.Load() == "" || reqToken != token.Load() {
respondError(w, http.StatusForbidden, nil)
}
resp, err := raw.HandleRequest(r.Context(), req)
if respondErrorCommon(w, req, resp, err) {
return
}
var httpResp *logical.HTTPResponse
if resp != nil {
httpResp = logical.LogicalResponseToHTTPResponse(resp)
httpResp.RequestID = req.ID
}
respondOk(w, httpResp)
})
}
// handleLogicalInternal is a common helper that returns a handler for
// processing logical requests. The behavior depends on the various boolean
// toggles. Refer to usage on functions for possible behaviors.