2023-03-15 16:00:52 +00:00
|
|
|
// Copyright (c) HashiCorp, Inc.
|
|
|
|
// SPDX-License-Identifier: MPL-2.0
|
|
|
|
|
2015-03-12 06:05:16 +00:00
|
|
|
package http
|
|
|
|
|
|
|
|
import (
|
2018-01-19 06:44:44 +00:00
|
|
|
"context"
|
2016-08-15 20:01:15 +00:00
|
|
|
"encoding/base64"
|
2015-03-12 18:12:44 +00:00
|
|
|
"encoding/hex"
|
2015-03-12 06:05:16 +00:00
|
|
|
"errors"
|
|
|
|
"net/http"
|
|
|
|
|
2015-03-12 18:26:59 +00:00
|
|
|
"github.com/hashicorp/errwrap"
|
2019-04-12 21:54:35 +00:00
|
|
|
"github.com/hashicorp/vault/sdk/helper/consts"
|
|
|
|
"github.com/hashicorp/vault/sdk/logical"
|
2019-04-13 07:44:06 +00:00
|
|
|
"github.com/hashicorp/vault/vault"
|
2015-03-12 06:05:16 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
func handleSysSeal(core *vault.Core) http.Handler {
|
|
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
2020-07-07 04:05:28 +00:00
|
|
|
req, _, statusCode, err := buildLogicalRequest(core, w, r)
|
2016-05-20 17:03:54 +00:00
|
|
|
if err != nil || statusCode != 0 {
|
|
|
|
respondError(w, statusCode, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
switch req.Operation {
|
|
|
|
case logical.UpdateOperation:
|
2015-08-31 21:55:22 +00:00
|
|
|
default:
|
2015-03-12 06:05:16 +00:00
|
|
|
respondError(w, http.StatusMethodNotAllowed, nil)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2015-03-31 18:45:44 +00:00
|
|
|
// Seal with the token above
|
2018-01-19 06:44:44 +00:00
|
|
|
// We use context.Background since there won't be a request context if the node isn't active
|
2018-07-24 21:50:49 +00:00
|
|
|
if err := core.SealWithRequest(r.Context(), req); err != nil {
|
2016-11-16 19:08:09 +00:00
|
|
|
if errwrap.Contains(err, logical.ErrPermissionDenied.Error()) {
|
|
|
|
respondError(w, http.StatusForbidden, err)
|
|
|
|
return
|
|
|
|
}
|
2018-09-18 03:03:00 +00:00
|
|
|
respondError(w, http.StatusInternalServerError, err)
|
|
|
|
return
|
2015-03-12 06:05:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
respondOk(w, nil)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2016-02-27 00:43:55 +00:00
|
|
|
func handleSysStepDown(core *vault.Core) http.Handler {
|
|
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
2020-07-07 04:05:28 +00:00
|
|
|
req, _, statusCode, err := buildLogicalRequest(core, w, r)
|
2016-05-20 17:03:54 +00:00
|
|
|
if err != nil || statusCode != 0 {
|
|
|
|
respondError(w, statusCode, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
switch req.Operation {
|
|
|
|
case logical.UpdateOperation:
|
2016-02-27 00:43:55 +00:00
|
|
|
default:
|
|
|
|
respondError(w, http.StatusMethodNotAllowed, nil)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Seal with the token above
|
2018-07-24 21:50:49 +00:00
|
|
|
if err := core.StepDown(r.Context(), req); err != nil {
|
2018-09-18 03:03:00 +00:00
|
|
|
if errwrap.Contains(err, logical.ErrPermissionDenied.Error()) {
|
|
|
|
respondError(w, http.StatusForbidden, err)
|
|
|
|
return
|
|
|
|
}
|
2016-02-27 00:43:55 +00:00
|
|
|
respondError(w, http.StatusInternalServerError, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
respondOk(w, nil)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2015-03-12 06:05:16 +00:00
|
|
|
func handleSysUnseal(core *vault.Core) http.Handler {
|
|
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
2015-08-31 21:55:22 +00:00
|
|
|
switch r.Method {
|
|
|
|
case "PUT":
|
|
|
|
case "POST":
|
|
|
|
default:
|
2015-03-12 06:05:16 +00:00
|
|
|
respondError(w, http.StatusMethodNotAllowed, nil)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Parse the request
|
|
|
|
var req UnsealRequest
|
2020-02-12 22:20:22 +00:00
|
|
|
if _, err := parseJSONRequest(core.PerfStandby(), r, w, &req); err != nil {
|
2015-03-12 06:05:16 +00:00
|
|
|
respondError(w, http.StatusBadRequest, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2015-10-28 19:59:39 +00:00
|
|
|
if req.Reset {
|
2018-07-24 20:57:25 +00:00
|
|
|
if !core.Sealed() {
|
2015-10-28 19:59:39 +00:00
|
|
|
respondError(w, http.StatusBadRequest, errors.New("vault is unsealed"))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
core.ResetUnsealProcess()
|
2018-10-23 06:34:02 +00:00
|
|
|
handleSysSealStatusRaw(core, w, r)
|
|
|
|
return
|
|
|
|
}
|
2015-10-28 19:59:39 +00:00
|
|
|
|
2018-10-23 06:34:02 +00:00
|
|
|
if req.Key == "" {
|
|
|
|
respondError(
|
|
|
|
w, http.StatusBadRequest,
|
|
|
|
errors.New("'key' must be specified in request body as JSON, or 'reset' set to true"))
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Decode the key, which is base64 or hex encoded
|
|
|
|
min, max := core.BarrierKeyLength()
|
|
|
|
key, err := hex.DecodeString(req.Key)
|
|
|
|
// We check min and max here to ensure that a string that is base64
|
|
|
|
// encoded but also valid hex will not be valid and we instead base64
|
|
|
|
// decode it
|
|
|
|
if err != nil || len(key) < min || len(key) > max {
|
|
|
|
key, err = base64.StdEncoding.DecodeString(req.Key)
|
2017-11-07 20:15:39 +00:00
|
|
|
if err != nil {
|
2018-10-23 06:34:02 +00:00
|
|
|
respondError(
|
|
|
|
w, http.StatusBadRequest,
|
|
|
|
errors.New("'key' must be a valid hex or base64 string"))
|
2016-08-24 18:15:25 +00:00
|
|
|
return
|
2015-10-28 19:59:39 +00:00
|
|
|
}
|
2015-03-12 06:05:16 +00:00
|
|
|
}
|
|
|
|
|
2020-10-23 18:16:04 +00:00
|
|
|
// Attempt the unseal. If migrate was specified, the key should correspond
|
|
|
|
// to the old seal.
|
|
|
|
if req.Migrate {
|
|
|
|
_, err = core.UnsealMigrate(key)
|
2018-10-23 06:34:02 +00:00
|
|
|
} else {
|
|
|
|
_, err = core.Unseal(key)
|
|
|
|
}
|
|
|
|
if err != nil {
|
|
|
|
switch {
|
|
|
|
case errwrap.ContainsType(err, new(vault.ErrInvalidKey)):
|
|
|
|
case errwrap.Contains(err, vault.ErrBarrierInvalidKey.Error()):
|
|
|
|
case errwrap.Contains(err, vault.ErrBarrierNotInit.Error()):
|
|
|
|
case errwrap.Contains(err, vault.ErrBarrierSealed.Error()):
|
|
|
|
case errwrap.Contains(err, consts.ErrStandby.Error()):
|
|
|
|
default:
|
|
|
|
respondError(w, http.StatusInternalServerError, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
respondError(w, http.StatusBadRequest, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2015-03-12 06:05:16 +00:00
|
|
|
// Return the seal status
|
|
|
|
handleSysSealStatusRaw(core, w, r)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func handleSysSealStatus(core *vault.Core) http.Handler {
|
|
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
if r.Method != "GET" {
|
|
|
|
respondError(w, http.StatusMethodNotAllowed, nil)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
handleSysSealStatusRaw(core, w, r)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
func handleSysSealStatusRaw(core *vault.Core, w http.ResponseWriter, r *http.Request) {
|
2018-01-19 06:44:44 +00:00
|
|
|
ctx := context.Background()
|
2021-01-20 20:04:24 +00:00
|
|
|
status, err := core.GetSealStatus(ctx)
|
2015-03-12 06:05:16 +00:00
|
|
|
if err != nil {
|
|
|
|
respondError(w, http.StatusInternalServerError, err)
|
|
|
|
return
|
|
|
|
}
|
2017-11-07 20:15:39 +00:00
|
|
|
|
2021-01-20 20:04:24 +00:00
|
|
|
respondOk(w, status)
|
2015-03-12 06:05:16 +00:00
|
|
|
}
|
|
|
|
|
2018-10-23 06:34:02 +00:00
|
|
|
// Note: because we didn't provide explicit tagging in the past we can't do it
|
|
|
|
// now because if it then no longer accepts capitalized versions it could break
|
|
|
|
// clients
|
2015-03-12 06:05:16 +00:00
|
|
|
type UnsealRequest struct {
|
2018-10-23 06:34:02 +00:00
|
|
|
Key string
|
|
|
|
Reset bool
|
|
|
|
Migrate bool
|
2015-03-12 06:05:16 +00:00
|
|
|
}
|