acl: remove legacy bootstrap

Return an explicit error from the RPC, and remove the flag from the HTTP API.
This commit is contained in:
Daniel Nephin 2021-08-13 18:31:32 -04:00
parent d77ea40203
commit be0358df02
3 changed files with 12 additions and 128 deletions

View File

@ -4,7 +4,6 @@ import (
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
"strconv"
"strings" "strings"
"github.com/hashicorp/consul/acl" "github.com/hashicorp/consul/acl"
@ -40,40 +39,18 @@ func (s *HTTPHandlers) ACLBootstrap(resp http.ResponseWriter, req *http.Request)
args := structs.DCSpecificRequest{ args := structs.DCSpecificRequest{
Datacenter: s.agent.config.Datacenter, Datacenter: s.agent.config.Datacenter,
} }
var out structs.ACLToken
legacy := false err := s.agent.RPC("ACL.BootstrapTokens", &args, &out)
legacyStr := req.URL.Query().Get("legacy") if err != nil {
if legacyStr != "" { if strings.Contains(err.Error(), structs.ACLBootstrapNotAllowedErr.Error()) {
legacy, _ = strconv.ParseBool(legacyStr) resp.WriteHeader(http.StatusForbidden)
} fmt.Fprint(resp, acl.PermissionDeniedError{Cause: err.Error()}.Error())
return nil, nil
if legacy && s.agent.delegate.UseLegacyACLs() { } else {
var out structs.ACL return nil, err
err := s.agent.RPC("ACL.Bootstrap", &args, &out)
if err != nil {
if strings.Contains(err.Error(), structs.ACLBootstrapNotAllowedErr.Error()) {
resp.WriteHeader(http.StatusForbidden)
fmt.Fprint(resp, acl.PermissionDeniedError{Cause: err.Error()}.Error())
return nil, nil
} else {
return nil, err
}
} }
return &aclBootstrapResponse{ID: out.ID}, nil
} else {
var out structs.ACLToken
err := s.agent.RPC("ACL.BootstrapTokens", &args, &out)
if err != nil {
if strings.Contains(err.Error(), structs.ACLBootstrapNotAllowedErr.Error()) {
resp.WriteHeader(http.StatusForbidden)
fmt.Fprint(resp, acl.PermissionDeniedError{Cause: err.Error()}.Error())
return nil, nil
} else {
return nil, err
}
}
return &aclBootstrapResponse{ID: out.SecretID, ACLToken: out}, nil
} }
return &aclBootstrapResponse{ID: out.SecretID, ACLToken: out}, nil
} }
func (s *HTTPHandlers) ACLReplicationStatus(resp http.ResponseWriter, req *http.Request) (interface{}, error) { func (s *HTTPHandlers) ACLReplicationStatus(resp http.ResponseWriter, req *http.Request) (interface{}, error) {

View File

@ -21,65 +21,8 @@ var ACLEndpointLegacySummaries = []prometheus.SummaryDefinition{
}, },
} }
// Bootstrap is used to perform a one-time ACL bootstrap operation on func (a *ACL) Bootstrap(*structs.DCSpecificRequest, *structs.ACL) error {
// a cluster to get the first management token. return fmt.Errorf("ACL.Bootstrap: the legacy ACL system has been removed")
func (a *ACL) Bootstrap(args *structs.DCSpecificRequest, reply *structs.ACL) error {
if done, err := a.srv.ForwardRPC("ACL.Bootstrap", args, reply); done {
return err
}
// Verify we are allowed to serve this request
if !a.srv.InACLDatacenter() {
return acl.ErrDisabled
}
if err := a.srv.aclBootstrapAllowed(); err != nil {
return err
}
// By doing some pre-checks we can head off later bootstrap attempts
// without having to run them through Raft, which should curb abuse.
state := a.srv.fsm.State()
allowed, _, err := state.CanBootstrapACLToken()
if err != nil {
return err
}
if !allowed {
return structs.ACLBootstrapNotAllowedErr
}
// Propose a new token.
token, err := lib.GenerateUUID(a.srv.checkTokenUUID)
if err != nil {
return fmt.Errorf("failed to make random token: %v", err)
}
// Attempt a bootstrap.
req := structs.ACLRequest{
Datacenter: a.srv.config.PrimaryDatacenter,
Op: structs.ACLBootstrapNow,
ACL: structs.ACL{
ID: token,
Name: "Bootstrap Token",
Type: structs.ACLTokenTypeManagement,
},
}
resp, err := a.srv.raftApply(structs.ACLRequestType, &req)
if err != nil {
return err
}
switch v := resp.(type) {
case *structs.ACL:
*reply = *v
default:
// Just log this, since it looks like the bootstrap may have
// completed.
a.logger.Error("Unexpected response during bootstrap", "type", fmt.Sprintf("%T", v))
}
a.logger.Info("ACL bootstrap completed")
return nil
} }
// aclApplyInternal is used to apply an ACL request after it has been vetted that // aclApplyInternal is used to apply an ACL request after it has been vetted that

View File

@ -25,42 +25,6 @@ import (
"github.com/hashicorp/consul/sdk/testutil/retry" "github.com/hashicorp/consul/sdk/testutil/retry"
) )
func TestACLEndpoint_Bootstrap(t *testing.T) {
if testing.Short() {
t.Skip("too slow for testing.Short")
}
t.Parallel()
_, srv, codec := testACLServerWithConfig(t, func(c *Config) {
c.Build = "0.8.0" // Too low for auto init of bootstrap.
c.PrimaryDatacenter = "dc1"
c.ACLsEnabled = true
// remove the default as we want to bootstrap
c.ACLMasterToken = ""
}, false)
waitForLeaderEstablishment(t, srv)
// Expect an error initially since ACL bootstrap is not initialized.
arg := structs.DCSpecificRequest{
Datacenter: "dc1",
}
var out structs.ACL
// We can only do some high
// level checks on the ACL since we don't have control over the UUID or
// Raft indexes at this level.
err := msgpackrpc.CallWithCodec(codec, "ACL.Bootstrap", &arg, &out)
require.NoError(t, err)
require.Len(t, out.ID, len("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"))
require.True(t, strings.HasPrefix(out.Name, "Bootstrap Token"))
require.Equal(t, structs.ACLTokenTypeManagement, out.Type)
require.NotEqual(t, uint64(0), out.CreateIndex)
require.NotEqual(t, uint64(0), out.ModifyIndex)
// Finally, make sure that another attempt is rejected.
err = msgpackrpc.CallWithCodec(codec, "ACL.Bootstrap", &arg, &out)
testutil.RequireErrorContains(t, err, structs.ACLBootstrapNotAllowedErr.Error())
}
func TestACLEndpoint_BootstrapTokens(t *testing.T) { func TestACLEndpoint_BootstrapTokens(t *testing.T) {
if testing.Short() { if testing.Short() {
t.Skip("too slow for testing.Short") t.Skip("too slow for testing.Short")