acl: remove legacy bootstrap
Return an explicit error from the RPC, and remove the flag from the HTTP API.
This commit is contained in:
parent
d77ea40203
commit
be0358df02
|
@ -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) {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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")
|
||||||
|
|
Loading…
Reference in New Issue