diff --git a/.changelog/15947.txt b/.changelog/15947.txt new file mode 100644 index 000000000..faec894c3 --- /dev/null +++ b/.changelog/15947.txt @@ -0,0 +1,3 @@ +```release-note:breaking-change +acl: remove all acl migration functionality and references to the legacy acl system. +``` \ No newline at end of file diff --git a/acl/errors.go b/acl/errors.go index e3eb6c7ea..5241494de 100644 --- a/acl/errors.go +++ b/acl/errors.go @@ -96,9 +96,7 @@ func (e PermissionDeniedError) Error() string { return message.String() } - if e.Accessor == "" { - message.WriteString(": provided token") - } else if e.Accessor == AnonymousTokenID { + if e.Accessor == AnonymousTokenID { message.WriteString(": anonymous token") } else { fmt.Fprintf(&message, ": token with AccessorID '%s'", e.Accessor) diff --git a/acl/errors_test.go b/acl/errors_test.go index 5910c08e9..963b2cbb1 100644 --- a/acl/errors_test.go +++ b/acl/errors_test.go @@ -17,6 +17,7 @@ func TestPermissionDeniedError(t *testing.T) { } auth1 := MockAuthorizer{} + auth2 := AllowAuthorizer{nil, AnonymousTokenID} cases := []testCase{ { @@ -29,11 +30,15 @@ func TestPermissionDeniedError(t *testing.T) { }, { err: PermissionDeniedByACL(&auth1, nil, ResourceService, AccessRead, "foobar"), - expected: "Permission denied: provided token lacks permission 'service:read' on \"foobar\"", + expected: "Permission denied: token with AccessorID '' lacks permission 'service:read' on \"foobar\"", }, { err: PermissionDeniedByACLUnnamed(&auth1, nil, ResourceService, AccessRead), - expected: "Permission denied: provided token lacks permission 'service:read'", + expected: "Permission denied: token with AccessorID '' lacks permission 'service:read'", + }, + { + err: PermissionDeniedByACLUnnamed(auth2, nil, ResourceService, AccessRead), + expected: "Permission denied: anonymous token lacks permission 'service:read'. The anonymous token is used implicitly when a request does not specify a token.", }, } diff --git a/agent/acl_endpoint.go b/agent/acl_endpoint.go index cd5664d58..54f4b5c12 100644 --- a/agent/acl_endpoint.go +++ b/agent/acl_endpoint.go @@ -428,10 +428,8 @@ func (s *HTTPHandlers) aclTokenSetInternal(req *http.Request, tokenID string, cr } if !create { - if args.ACLToken.AccessorID != "" && args.ACLToken.AccessorID != tokenID { + if args.ACLToken.AccessorID != tokenID { return nil, HTTPError{StatusCode: http.StatusBadRequest, Reason: "Token Accessor ID in URL and payload do not match"} - } else if args.ACLToken.AccessorID == "" { - args.ACLToken.AccessorID = tokenID } } diff --git a/agent/acl_endpoint_legacy.go b/agent/acl_endpoint_legacy.go deleted file mode 100644 index 5a1be1514..000000000 --- a/agent/acl_endpoint_legacy.go +++ /dev/null @@ -1,13 +0,0 @@ -package agent - -import ( - "fmt" - "net/http" -) - -func (s *HTTPHandlers) ACLLegacy(resp http.ResponseWriter, req *http.Request) (interface{}, error) { - resp.WriteHeader(http.StatusGone) - msg := "Endpoint %v for the legacy ACL system was removed in Consul 1.11." - fmt.Fprintf(resp, msg, req.URL.Path) - return nil, nil -} diff --git a/agent/acl_endpoint_legacy_test.go b/agent/acl_endpoint_legacy_test.go deleted file mode 100644 index 8c7fc251c..000000000 --- a/agent/acl_endpoint_legacy_test.go +++ /dev/null @@ -1,49 +0,0 @@ -package agent - -import ( - "net/http" - "net/http/httptest" - "testing" - - "github.com/stretchr/testify/require" -) - -func TestHTTPHandlers_ACLLegacy(t *testing.T) { - if testing.Short() { - t.Skip("too slow for testing.Short") - } - - t.Parallel() - a := NewTestAgent(t, "") - defer a.Shutdown() - - type testCase struct { - method string - path string - } - - run := func(t *testing.T, tc testCase) { - req, err := http.NewRequest(tc.method, tc.path, nil) - require.NoError(t, err) - resp := httptest.NewRecorder() - - a.srv.h.ServeHTTP(resp, req) - require.Equal(t, http.StatusGone, resp.Code) - require.Contains(t, resp.Body.String(), "the legacy ACL system was removed") - } - - var testCases = []testCase{ - {method: http.MethodPut, path: "/v1/acl/create"}, - {method: http.MethodPut, path: "/v1/acl/update"}, - {method: http.MethodPut, path: "/v1/acl/destroy/ID"}, - {method: http.MethodGet, path: "/v1/acl/info/ID"}, - {method: http.MethodPut, path: "/v1/acl/clone/ID"}, - {method: http.MethodGet, path: "/v1/acl/list"}, - } - - for _, tc := range testCases { - t.Run(tc.method+tc.path, func(t *testing.T) { - run(t, tc) - }) - } -} diff --git a/agent/acl_endpoint_test.go b/agent/acl_endpoint_test.go index 85924a922..0708d2196 100644 --- a/agent/acl_endpoint_test.go +++ b/agent/acl_endpoint_test.go @@ -864,8 +864,9 @@ func TestACL_HTTP(t *testing.T) { t.Run("Update", func(t *testing.T) { originalToken := tokenMap[idMap["token-cloned"]] - // Accessor and Secret will be filled in + // Secret will be filled in tokenInput := &structs.ACLToken{ + AccessorID: tokenMap[idMap["token-cloned"]].AccessorID, Description: "Better description for this cloned token", Policies: []structs.ACLTokenPolicyLink{ { diff --git a/agent/acl_test.go b/agent/acl_test.go index 23c0e056d..7066f69f5 100644 --- a/agent/acl_test.go +++ b/agent/acl_test.go @@ -180,10 +180,9 @@ func authzFromPolicy(policy *acl.Policy, cfg *acl.Config) (acl.Authorizer, error return acl.NewPolicyAuthorizerWithDefaults(acl.DenyAll(), []*acl.Policy{policy}, cfg) } -type testToken struct { +type testTokenRules struct { token structs.ACLToken - // yes the rules can exist on the token itself but that is legacy behavior - // that I would prefer these tests not rely on + // rules to create associated policy rules string } @@ -194,7 +193,7 @@ var ( serviceRWSecret = "4a1017a2-f788-4be3-93f2-90566f1340bb" otherRWSecret = "a38e8016-91b6-4876-b3e7-a307abbb2002" - testTokens = map[string]testToken{ + testACLs = map[string]testTokenRules{ nodeROSecret: { token: structs.ACLToken{ AccessorID: "9df2d1a4-2d07-414e-8ead-6053f56ed2eb", @@ -233,8 +232,8 @@ var ( } ) -func catalogPolicy(token string) (structs.ACLIdentity, acl.Authorizer, error) { - tok, ok := testTokens[token] +func catalogPolicy(testACL string) (structs.ACLIdentity, acl.Authorizer, error) { + tok, ok := testACLs[testACL] if !ok { return nil, nil, acl.ErrNotFound } @@ -248,8 +247,8 @@ func catalogPolicy(token string) (structs.ACLIdentity, acl.Authorizer, error) { return &tok.token, authz, err } -func catalogIdent(token string) (structs.ACLIdentity, error) { - tok, ok := testTokens[token] +func catalogIdent(testACL string) (structs.ACLIdentity, error) { + tok, ok := testACLs[testACL] if !ok { return nil, acl.ErrNotFound } diff --git a/agent/consul/acl_endpoint.go b/agent/consul/acl_endpoint.go index e149ca420..4994baeb9 100644 --- a/agent/consul/acl_endpoint.go +++ b/agent/consul/acl_endpoint.go @@ -470,10 +470,6 @@ func (a *ACL) TokenClone(args *structs.ACLTokenSetRequest, reply *structs.ACLTok return fmt.Errorf("Cannot clone a token created from an auth method") } - if token.Rules != "" { - return fmt.Errorf("Cannot clone a legacy ACL with this endpoint") - } - clone := &structs.ACLToken{ Policies: token.Policies, Roles: token.Roles, diff --git a/agent/consul/acl_endpoint_test.go b/agent/consul/acl_endpoint_test.go index 84930df55..618b0a427 100644 --- a/agent/consul/acl_endpoint_test.go +++ b/agent/consul/acl_endpoint_test.go @@ -483,7 +483,6 @@ func TestACLEndpoint_TokenClone(t *testing.T) { require.Equal(t, t1.Roles, t2.Roles) require.Equal(t, t1.ServiceIdentities, t2.ServiceIdentities) require.Equal(t, t1.NodeIdentities, t2.NodeIdentities) - require.Equal(t, t1.Rules, t2.Rules) require.Equal(t, t1.Local, t2.Local) require.NotEqual(t, t1.AccessorID, t2.AccessorID) require.NotEqual(t, t1.SecretID, t2.SecretID) diff --git a/agent/consul/auth/token_writer.go b/agent/consul/auth/token_writer.go index ae5957045..f6d797660 100644 --- a/agent/consul/auth/token_writer.go +++ b/agent/consul/auth/token_writer.go @@ -306,10 +306,6 @@ func (w *TokenWriter) write(token, existing *structs.ACLToken, fromLogin bool) ( } token.NodeIdentities = nodeIdentities - if token.Rules != "" { - return nil, errors.New("Rules cannot be specified for this token") - } - if token.Type != "" { return nil, errors.New("Type cannot be specified for this token") } diff --git a/agent/consul/auth/token_writer_test.go b/agent/consul/auth/token_writer_test.go index b04edef8a..b2fef1c11 100644 --- a/agent/consul/auth/token_writer_test.go +++ b/agent/consul/auth/token_writer_test.go @@ -98,10 +98,6 @@ func TestTokenWriter_Create_Validation(t *testing.T) { fromLogin: false, errorContains: "AuthMethod field is disallowed outside of login", }, - "Rules set": { - token: structs.ACLToken{Rules: "some rules"}, - errorContains: "Rules cannot be specified for this token", - }, "Type set": { token: structs.ACLToken{Type: "some-type"}, errorContains: "Type cannot be specified for this token", @@ -498,10 +494,6 @@ func TestTokenWriter_Update_Validation(t *testing.T) { token: structs.ACLToken{AccessorID: token.AccessorID, ExpirationTime: timePointer(token.ExpirationTime.Add(1 * time.Minute))}, errorContains: "Cannot change expiration time", }, - "Rules set": { - token: structs.ACLToken{AccessorID: token.AccessorID, Rules: "some rules"}, - errorContains: "Rules cannot be specified for this token", - }, "Type set": { token: structs.ACLToken{AccessorID: token.AccessorID, Type: "some-type"}, errorContains: "Type cannot be specified for this token", diff --git a/agent/consul/fsm/snapshot_oss.go b/agent/consul/fsm/snapshot_oss.go index 7fa53381a..3d0cd8343 100644 --- a/agent/consul/fsm/snapshot_oss.go +++ b/agent/consul/fsm/snapshot_oss.go @@ -20,8 +20,6 @@ func init() { registerRestorer(structs.KVSRequestType, restoreKV) registerRestorer(structs.TombstoneRequestType, restoreTombstone) registerRestorer(structs.SessionRequestType, restoreSession) - registerRestorer(structs.DeprecatedACLRequestType, restoreACL) // TODO(ACL-Legacy-Compat) - remove in phase 2 - registerRestorer(structs.ACLBootstrapRequestType, restoreACLBootstrap) registerRestorer(structs.CoordinateBatchUpdateType, restoreCoordinates) registerRestorer(structs.PreparedQueryRequestType, restorePreparedQuery) registerRestorer(structs.AutopilotRequestType, restoreAutopilot) @@ -660,73 +658,6 @@ func restoreSession(header *SnapshotHeader, restore *state.Restore, decoder *cod return nil } -// TODO(ACL-Legacy-Compat) - remove in phase 2 -func restoreACL(_ *SnapshotHeader, restore *state.Restore, decoder *codec.Decoder) error { - var req LegacyACL - if err := decoder.Decode(&req); err != nil { - return err - } - - if err := restore.ACLToken(req.Convert()); err != nil { - return err - } - return nil -} - -// TODO(ACL-Legacy-Compat) - remove in phase 2 -type LegacyACL struct { - ID string - Name string - Type string - Rules string - - structs.RaftIndex -} - -// TODO(ACL-Legacy-Compat): remove in phase 2, used by snapshot restore -func (a LegacyACL) Convert() *structs.ACLToken { - correctedRules := structs.SanitizeLegacyACLTokenRules(a.Rules) - if correctedRules != "" { - a.Rules = correctedRules - } - - token := &structs.ACLToken{ - AccessorID: "", - SecretID: a.ID, - Description: a.Name, - Policies: nil, - ServiceIdentities: nil, - NodeIdentities: nil, - Type: a.Type, - Rules: a.Rules, - Local: false, - RaftIndex: a.RaftIndex, - } - - token.SetHash(true) - return token -} - -// TODO(ACL-Legacy-Compat) - remove in phase 2 -func restoreACLBootstrap(_ *SnapshotHeader, restore *state.Restore, decoder *codec.Decoder) error { - type ACLBootstrap struct { - // AllowBootstrap will only be true if no existing management tokens - // have been found. - AllowBootstrap bool - - structs.RaftIndex - } - - var req ACLBootstrap - if err := decoder.Decode(&req); err != nil { - return err - } - - // With V2 ACLs whether bootstrapping has been performed is stored in the index table like nomad - // so this "restores" into that index table. - return restore.IndexRestore(&state.IndexEntry{Key: "acl-token-bootstrap", Value: req.ModifyIndex}) -} - func restoreCoordinates(header *SnapshotHeader, restore *state.Restore, decoder *codec.Decoder) error { var req structs.Coordinates if err := decoder.Decode(&req); err != nil { @@ -819,14 +750,6 @@ func restoreToken(header *SnapshotHeader, restore *state.Restore, decoder *codec return err } - // DEPRECATED (ACL-Legacy-Compat) - if req.Rules != "" { - // When we restore a snapshot we may have to correct old HCL in legacy - // tokens to prevent the in-memory representation from using an older - // syntax. - structs.SanitizeLegacyACLToken(&req) - } - // only set if unset - mitigates a bug where converted legacy tokens could end up without a hash req.SetHash(false) diff --git a/agent/consul/fsm/snapshot_test.go b/agent/consul/fsm/snapshot_test.go index d892e2578..75f159e07 100644 --- a/agent/consul/fsm/snapshot_test.go +++ b/agent/consul/fsm/snapshot_test.go @@ -2,7 +2,6 @@ package fsm import ( "bytes" - "fmt" "net" "testing" "time" @@ -12,7 +11,6 @@ import ( "github.com/hashicorp/consul-net-rpc/go-msgpack/codec" - "github.com/hashicorp/consul/acl" "github.com/hashicorp/consul/agent/connect" "github.com/hashicorp/consul/agent/consul/state" "github.com/hashicorp/consul/agent/structs" @@ -87,7 +85,6 @@ func TestFSM_SnapshotRestore_OSS(t *testing.T) { Name: "global-management", Description: "Builtin Policy that grants unlimited access", Rules: structs.ACLPolicyGlobalManagement, - Syntax: acl.SyntaxCurrent, } policy.SetHash(true) require.NoError(t, fsm.state.ACLPolicySet(1, policy)) @@ -537,21 +534,6 @@ func TestFSM_SnapshotRestore_OSS(t *testing.T) { // be persisted but that we still need to be able to restore encoder := codec.NewEncoder(sink, structs.MsgpackHandle) - // Persist a legacy ACL token - this is not done in newer code - // but we want to ensure that restoring legacy tokens works as - // expected so we must inject one here manually - _, err = sink.Write([]byte{byte(structs.DeprecatedACLRequestType)}) - require.NoError(t, err) - - acl := LegacyACL{ - ID: "1057354f-69ef-4487-94ab-aead3c755445", - Name: "test-legacy", - Type: "client", - Rules: `operator = "read"`, - RaftIndex: structs.RaftIndex{CreateIndex: 1, ModifyIndex: 2}, - } - require.NoError(t, encoder.Encode(&acl)) - // Persist a ACLToken without a Hash - the state store will // now tack these on but we want to ensure we can restore // tokens without a hash and have the hash be set. @@ -561,8 +543,13 @@ func TestFSM_SnapshotRestore_OSS(t *testing.T) { Description: "Test No Hash", CreateTime: time.Now(), Local: false, - Rules: `operator = "read"`, - RaftIndex: structs.RaftIndex{CreateIndex: 1, ModifyIndex: 2}, + Policies: []structs.ACLTokenPolicyLink{ + { + Name: "global-management", + ID: structs.ACLPolicyGlobalManagementID, + }, + }, + RaftIndex: structs.RaftIndex{CreateIndex: 1, ModifyIndex: 2}, } _, err = sink.Write([]byte{byte(structs.ACLTokenSetRequestType)}) @@ -673,16 +660,6 @@ func TestFSM_SnapshotRestore_OSS(t *testing.T) { // adds the Hash to our local var. require.Equal(t, token, rtoken) - // Verify legacy ACL is restored - _, rtoken, err = fsm2.state.ACLTokenGetBySecret(nil, acl.ID, nil) - require.NoError(t, err) - require.NotNil(t, rtoken) - require.NotEmpty(t, rtoken.Hash) - - restoredACL, err := convertACLTokenToLegacy(rtoken) - require.NoError(t, err) - require.Equal(t, &acl, restoredACL) - // Verify ACLToken without hash computes the Hash during restoration _, rtoken, err = fsm2.state.ACLTokenGetByAccessor(nil, token2.AccessorID, nil) require.NoError(t, err) @@ -884,23 +861,6 @@ func TestFSM_SnapshotRestore_OSS(t *testing.T) { } } -// convertACLTokenToLegacy attempts to convert an ACLToken into an legacy ACL. -// TODO(ACL-Legacy-Compat): remove in phase 2, used by snapshot restore -func convertACLTokenToLegacy(tok *structs.ACLToken) (*LegacyACL, error) { - if tok.Type == "" { - return nil, fmt.Errorf("Cannot convert ACLToken into compat token") - } - - compat := &LegacyACL{ - ID: tok.SecretID, - Name: tok.Description, - Type: tok.Type, - Rules: tok.Rules, - RaftIndex: tok.RaftIndex, - } - return compat, nil -} - func TestFSM_BadRestore_OSS(t *testing.T) { t.Parallel() // Create an FSM with some state. diff --git a/agent/consul/leader.go b/agent/consul/leader.go index fde95684d..efd26ba50 100644 --- a/agent/consul/leader.go +++ b/agent/consul/leader.go @@ -364,8 +364,6 @@ func (s *Server) revokeLeadership() { s.stopACLTokenReaping() - s.stopACLUpgrade() - s.resetConsistentReadReady() s.autopilot.DisableReconciliation() @@ -541,9 +539,6 @@ func (s *Server) initializeACLs(ctx context.Context) error { if err := s.setSystemMetadataKey(structs.ServerManagementTokenAccessorID, secretID); err != nil { return fmt.Errorf("failed to persist server management token: %w", err) } - - // launch the upgrade go routine to generate accessors for everything - s.startACLUpgrade(ctx) } else { s.startACLReplication(ctx) } @@ -553,100 +548,6 @@ func (s *Server) initializeACLs(ctx context.Context) error { return nil } -// legacyACLTokenUpgrade runs a single time to upgrade any tokens that may -// have been created immediately before the Consul upgrade, or any legacy tokens -// from a restored snapshot. -// TODO(ACL-Legacy-Compat): remove in phase 2 -func (s *Server) legacyACLTokenUpgrade(ctx context.Context) error { - // aclUpgradeRateLimit is the number of batch upgrade requests per second allowed. - const aclUpgradeRateLimit rate.Limit = 1.0 - - // aclUpgradeBatchSize controls how many tokens we look at during each round of upgrading. Individual raft logs - // will be further capped using the aclBatchUpsertSize. This limit just prevents us from creating a single slice - // with all tokens in it. - const aclUpgradeBatchSize = 128 - - limiter := rate.NewLimiter(aclUpgradeRateLimit, int(aclUpgradeRateLimit)) - for { - if err := limiter.Wait(ctx); err != nil { - return err - } - - // actually run the upgrade here - state := s.fsm.State() - tokens, _, err := state.ACLTokenListUpgradeable(aclUpgradeBatchSize) - if err != nil { - s.logger.Warn("encountered an error while searching for tokens without accessor ids", "error", err) - } - // No need to check expiration time here, as that only exists for v2 tokens. - - if len(tokens) == 0 { - // No new legacy tokens can be created, so we can exit - s.stopACLUpgrade() // required to prevent goroutine leak, according to TestAgentLeaks_Server - return nil - } - - var newTokens structs.ACLTokens - for _, token := range tokens { - // This should be entirely unnecessary but is just a small safeguard against changing accessor IDs - if token.AccessorID != "" { - continue - } - - newToken := *token - if token.SecretID == anonymousToken { - newToken.AccessorID = acl.AnonymousTokenID - } else { - accessor, err := lib.GenerateUUID(s.checkTokenUUID) - if err != nil { - s.logger.Warn("failed to generate accessor during token auto-upgrade", "error", err) - continue - } - newToken.AccessorID = accessor - } - - // Assign the global-management policy to legacy management tokens - if len(newToken.Policies) == 0 && - len(newToken.ServiceIdentities) == 0 && - len(newToken.NodeIdentities) == 0 && - len(newToken.Roles) == 0 && - newToken.Type == "management" { - newToken.Policies = append(newToken.Policies, structs.ACLTokenPolicyLink{ID: structs.ACLPolicyGlobalManagementID}) - } - - // need to copy these as we are going to do a CAS operation. - newToken.CreateIndex = token.CreateIndex - newToken.ModifyIndex = token.ModifyIndex - - newToken.SetHash(true) - - newTokens = append(newTokens, &newToken) - } - - req := &structs.ACLTokenBatchSetRequest{Tokens: newTokens, CAS: true} - - _, err = s.raftApply(structs.ACLTokenSetRequestType, req) - if err != nil { - s.logger.Error("failed to apply acl token upgrade batch", "error", err) - } - } -} - -// TODO(ACL-Legacy-Compat): remove in phase 2. Keeping it for now so that we -// can upgrade any tokens created immediately before the upgrade happens. -func (s *Server) startACLUpgrade(ctx context.Context) { - if s.config.PrimaryDatacenter != s.config.Datacenter { - // token upgrades should only run in the primary - return - } - - s.leaderRoutineManager.Start(ctx, aclUpgradeRoutineName, s.legacyACLTokenUpgrade) -} - -func (s *Server) stopACLUpgrade() { - s.leaderRoutineManager.Stop(aclUpgradeRoutineName) -} - func (s *Server) startACLReplication(ctx context.Context) { if s.InPrimaryDatacenter() { return diff --git a/agent/consul/server.go b/agent/consul/server.go index 94f4560a0..e81801035 100644 --- a/agent/consul/server.go +++ b/agent/consul/server.go @@ -118,7 +118,6 @@ const ( aclRoleReplicationRoutineName = "ACL role replication" aclTokenReplicationRoutineName = "ACL token replication" aclTokenReapingRoutineName = "acl token reaping" - aclUpgradeRoutineName = "legacy ACL token upgrade" caRootPruningRoutineName = "CA root pruning" caRootMetricRoutineName = "CA root expiration metric" caSigningMetricRoutineName = "CA signing expiration metric" diff --git a/agent/consul/state/acl.go b/agent/consul/state/acl.go index 3e604625c..03eedff7b 100644 --- a/agent/consul/state/acl.go +++ b/agent/consul/state/acl.go @@ -422,14 +422,10 @@ type ACLTokenSetOptions struct { CAS bool AllowMissingPolicyAndRoleIDs bool ProhibitUnprivileged bool - Legacy bool // TODO(ACL-Legacy-Compat): remove FromReplication bool } func (s *Store) ACLTokenBatchSet(idx uint64, tokens structs.ACLTokens, opts ACLTokenSetOptions) error { - if opts.Legacy { - return fmt.Errorf("failed inserting acl token: cannot use this endpoint to persist legacy tokens") - } tx := s.db.WriteTxn(idx) defer tx.Abort() @@ -451,25 +447,13 @@ func aclTokenSetTxn(tx WriteTxn, idx uint64, token *structs.ACLToken, opts ACLTo return ErrMissingACLTokenSecret } - if !opts.Legacy && token.AccessorID == "" { + if token.AccessorID == "" { return ErrMissingACLTokenAccessor } - if opts.FromReplication && token.Local { return fmt.Errorf("Cannot replicate local tokens") } - // DEPRECATED (ACL-Legacy-Compat) - if token.Rules != "" { - // When we update a legacy acl token we may have to correct old HCL to - // prevent the propagation of older syntax into the state store and - // into in-memory representations. - correctedRules := structs.SanitizeLegacyACLTokenRules(token.Rules) - if correctedRules != "" { - token.Rules = correctedRules - } - } - // Check for an existing ACL // DEPRECATED (ACL-Legacy-Compat) - transition to using accessor index instead of secret once v1 compat is removed _, existing, err := aclTokenGetFromIndex(tx, token.SecretID, "id", nil) @@ -498,10 +482,6 @@ func aclTokenSetTxn(tx WriteTxn, idx uint64, token *structs.ACLToken, opts ACLTo } } - if opts.Legacy && original != nil { - return fmt.Errorf("legacy tokens can not be modified") - } - if err := aclTokenUpsertValidateEnterprise(tx, token, original); err != nil { return err } @@ -719,29 +699,6 @@ func (s *Store) ACLTokenList(ws memdb.WatchSet, local, global bool, policy, role return idx, result, nil } -// TODO(ACL-Legacy-Compat): remove in phase 2 -func (s *Store) ACLTokenListUpgradeable(max int) (structs.ACLTokens, <-chan struct{}, error) { - tx := s.db.Txn(false) - defer tx.Abort() - - iter, err := tx.Get(tableACLTokens, "needs-upgrade", true) - if err != nil { - return nil, nil, fmt.Errorf("failed acl token listing: %v", err) - } - - var tokens structs.ACLTokens - i := 0 - for token := iter.Next(); token != nil; token = iter.Next() { - tokens = append(tokens, token.(*structs.ACLToken)) - i += 1 - if i >= max { - return tokens, nil, nil - } - } - - return tokens, iter.WatchCh(), nil -} - func (s *Store) ACLTokenMinExpirationTime(local bool) (time.Time, error) { tx := s.db.Txn(false) defer tx.Abort() diff --git a/agent/consul/state/acl_schema.go b/agent/consul/state/acl_schema.go index 485b5b92d..c3fdff40a 100644 --- a/agent/consul/state/acl_schema.go +++ b/agent/consul/state/acl_schema.go @@ -31,9 +31,8 @@ func tokensTableSchema() *memdb.TableSchema { Name: tableACLTokens, Indexes: map[string]*memdb.IndexSchema{ indexAccessor: { - Name: indexAccessor, - // DEPRECATED (ACL-Legacy-Compat) - we should not AllowMissing here once legacy compat is removed - AllowMissing: true, + Name: indexAccessor, + AllowMissing: false, Unique: true, Indexer: indexerSingle[string, *structs.ACLToken]{ readIndex: indexFromUUIDString, @@ -104,23 +103,6 @@ func tokensTableSchema() *memdb.TableSchema { writeIndex: indexExpiresLocalFromACLToken, }, }, - - // DEPRECATED (ACL-Legacy-Compat) - This index is only needed while we support upgrading v1 to v2 acls - // This table indexes all the ACL tokens that do not have an AccessorID - // TODO(ACL-Legacy-Compat): remove in phase 2 - "needs-upgrade": { - Name: "needs-upgrade", - AllowMissing: false, - Unique: false, - Indexer: &memdb.ConditionalIndex{ - Conditional: func(obj interface{}) (bool, error) { - if token, ok := obj.(*structs.ACLToken); ok { - return token.AccessorID == "", nil - } - return false, nil - }, - }, - }, }, } } diff --git a/agent/consul/state/acl_test.go b/agent/consul/state/acl_test.go index 5c9e097e9..15491e437 100644 --- a/agent/consul/state/acl_test.go +++ b/agent/consul/state/acl_test.go @@ -768,112 +768,6 @@ func TestStateStore_ACLTokens_UpsertBatchRead(t *testing.T) { }) } -func TestStateStore_ACLTokens_ListUpgradeable(t *testing.T) { - t.Parallel() - s := testACLTokensStateStore(t) - - aclTokenSetLegacy := func(idx uint64, token *structs.ACLToken) error { - tx := s.db.WriteTxn(idx) - defer tx.Abort() - - opts := ACLTokenSetOptions{Legacy: true} - if err := aclTokenSetTxn(tx, idx, token, opts); err != nil { - return err - } - - return tx.Commit() - } - - const ACLTokenTypeManagement = "management" - - require.NoError(t, aclTokenSetLegacy(2, &structs.ACLToken{ - SecretID: "34ec8eb3-095d-417a-a937-b439af7a8e8b", - Type: ACLTokenTypeManagement, - })) - - require.NoError(t, aclTokenSetLegacy(3, &structs.ACLToken{ - SecretID: "8de2dd39-134d-4cb1-950b-b7ab96ea20ba", - Type: ACLTokenTypeManagement, - })) - - require.NoError(t, aclTokenSetLegacy(4, &structs.ACLToken{ - SecretID: "548bdb8e-c0d6-477b-bcc4-67fb836e9e61", - Type: ACLTokenTypeManagement, - })) - - require.NoError(t, aclTokenSetLegacy(5, &structs.ACLToken{ - SecretID: "3ee33676-d9b8-4144-bf0b-92618cff438b", - Type: ACLTokenTypeManagement, - })) - - require.NoError(t, aclTokenSetLegacy(6, &structs.ACLToken{ - SecretID: "fa9d658a-6e26-42ab-a5f0-1ea05c893dee", - Type: ACLTokenTypeManagement, - })) - - tokens, _, err := s.ACLTokenListUpgradeable(3) - require.NoError(t, err) - require.Len(t, tokens, 3) - - tokens, _, err = s.ACLTokenListUpgradeable(10) - require.NoError(t, err) - require.Len(t, tokens, 5) - - updates := structs.ACLTokens{ - &structs.ACLToken{ - AccessorID: "f1093997-b6c7-496d-bfb8-6b1b1895641b", - SecretID: "34ec8eb3-095d-417a-a937-b439af7a8e8b", - Policies: []structs.ACLTokenPolicyLink{ - { - ID: structs.ACLPolicyGlobalManagementID, - }, - }, - }, - &structs.ACLToken{ - AccessorID: "54866514-3cf2-4fec-8a8a-710583831834", - SecretID: "8de2dd39-134d-4cb1-950b-b7ab96ea20ba", - Policies: []structs.ACLTokenPolicyLink{ - { - ID: structs.ACLPolicyGlobalManagementID, - }, - }, - }, - &structs.ACLToken{ - AccessorID: "47eea4da-bda1-48a6-901c-3e36d2d9262f", - SecretID: "548bdb8e-c0d6-477b-bcc4-67fb836e9e61", - Policies: []structs.ACLTokenPolicyLink{ - { - ID: structs.ACLPolicyGlobalManagementID, - }, - }, - }, - &structs.ACLToken{ - AccessorID: "af1dffe5-8ac2-4282-9336-aeed9f7d951a", - SecretID: "3ee33676-d9b8-4144-bf0b-92618cff438b", - Policies: []structs.ACLTokenPolicyLink{ - { - ID: structs.ACLPolicyGlobalManagementID, - }, - }, - }, - &structs.ACLToken{ - AccessorID: "511df589-3316-4784-b503-6e25ead4d4e1", - SecretID: "fa9d658a-6e26-42ab-a5f0-1ea05c893dee", - Policies: []structs.ACLTokenPolicyLink{ - { - ID: structs.ACLPolicyGlobalManagementID, - }, - }, - }, - } - - require.NoError(t, s.ACLTokenBatchSet(7, updates, ACLTokenSetOptions{})) - - tokens, _, err = s.ACLTokenListUpgradeable(10) - require.NoError(t, err) - require.Len(t, tokens, 0) -} - func TestStateStore_ACLToken_List(t *testing.T) { t.Parallel() s := testACLTokensStateStore(t) diff --git a/agent/grpc-internal/services/subscribe/subscribe_test.go b/agent/grpc-internal/services/subscribe/subscribe_test.go index 749be4b5e..c04d60a26 100644 --- a/agent/grpc-internal/services/subscribe/subscribe_test.go +++ b/agent/grpc-internal/services/subscribe/subscribe_test.go @@ -945,7 +945,6 @@ node "node1" { aclToken := &structs.ACLToken{ AccessorID: tokenID, SecretID: token, - Rules: "", } require.NoError(t, backend.store.ACLTokenSet(ids.Next("update"), aclToken)) diff --git a/agent/http_register.go b/agent/http_register.go index caa55d5ca..b0ff2c353 100644 --- a/agent/http_register.go +++ b/agent/http_register.go @@ -123,14 +123,4 @@ func init() { registerEndpoint("/v1/status/peers", []string{"GET"}, (*HTTPHandlers).StatusPeers) registerEndpoint("/v1/snapshot", []string{"GET", "PUT"}, (*HTTPHandlers).Snapshot) registerEndpoint("/v1/txn", []string{"PUT"}, (*HTTPHandlers).Txn) - - // Deprecated ACL endpoints, they do nothing but return an error - registerEndpoint("/v1/acl/create", []string{"PUT"}, (*HTTPHandlers).ACLLegacy) - registerEndpoint("/v1/acl/update", []string{"PUT"}, (*HTTPHandlers).ACLLegacy) - registerEndpoint("/v1/acl/destroy/", []string{"PUT"}, (*HTTPHandlers).ACLLegacy) - registerEndpoint("/v1/acl/info/", []string{"GET"}, (*HTTPHandlers).ACLLegacy) - registerEndpoint("/v1/acl/clone/", []string{"PUT"}, (*HTTPHandlers).ACLLegacy) - registerEndpoint("/v1/acl/list", []string{"GET"}, (*HTTPHandlers).ACLLegacy) - registerEndpoint("/v1/acl/rules/translate", []string{"POST"}, (*HTTPHandlers).ACLLegacy) - registerEndpoint("/v1/acl/rules/translate/", []string{"GET"}, (*HTTPHandlers).ACLLegacy) } diff --git a/agent/proxycfg-glue/peering_list_test.go b/agent/proxycfg-glue/peering_list_test.go index 7b9aa0088..cc608086c 100644 --- a/agent/proxycfg-glue/peering_list_test.go +++ b/agent/proxycfg-glue/peering_list_test.go @@ -114,6 +114,6 @@ func TestServerPeeringList_ACLEnforcement(t *testing.T) { require.NoError(t, err) err = getEventError(t, eventCh) - require.Contains(t, err.Error(), "provided token lacks permission 'peering:read'") + require.Contains(t, err.Error(), "token with AccessorID '' lacks permission 'peering:read'") }) } diff --git a/agent/proxycfg-glue/trust_bundle_test.go b/agent/proxycfg-glue/trust_bundle_test.go index c5c98499d..878b42df8 100644 --- a/agent/proxycfg-glue/trust_bundle_test.go +++ b/agent/proxycfg-glue/trust_bundle_test.go @@ -124,7 +124,7 @@ func TestServerTrustBundle_ACLEnforcement(t *testing.T) { require.NoError(t, err) err = getEventError(t, eventCh) - require.Contains(t, err.Error(), "provided token lacks permission 'service:write' on \"any service\"") + require.Contains(t, err.Error(), "token with AccessorID '' lacks permission 'service:write' on \"any service\"") }) } @@ -324,7 +324,7 @@ func TestServerTrustBundleList_ACLEnforcement(t *testing.T) { require.NoError(t, err) err = getEventError(t, eventCh) - require.Contains(t, err.Error(), "provided token lacks permission 'service:write' on \"web\"") + require.Contains(t, err.Error(), "token with AccessorID '' lacks permission 'service:write' on \"web\"") }) }) @@ -391,7 +391,7 @@ func TestServerTrustBundleList_ACLEnforcement(t *testing.T) { require.NoError(t, err) err = getEventError(t, eventCh) - require.Contains(t, err.Error(), "provided token lacks permission 'service:write'") + require.Contains(t, err.Error(), "token with AccessorID '' lacks permission 'service:write'") }) }) } diff --git a/agent/rpc/operator/service_test.go b/agent/rpc/operator/service_test.go index 7686c4324..f9d7c52ae 100644 --- a/agent/rpc/operator/service_test.go +++ b/agent/rpc/operator/service_test.go @@ -3,16 +3,17 @@ package operator import ( "context" "fmt" + "testing" + + "github.com/hashicorp/go-hclog" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + "google.golang.org/grpc" + "github.com/hashicorp/consul/acl" "github.com/hashicorp/consul/acl/resolver" "github.com/hashicorp/consul/agent/structs" "github.com/hashicorp/consul/proto/pboperator" - "github.com/hashicorp/go-hclog" - "github.com/stretchr/testify/mock" - "google.golang.org/grpc" - "testing" - - "github.com/stretchr/testify/require" ) type MockBackend struct { @@ -40,7 +41,7 @@ func TestLeaderTransfer_ACL_Deny(t *testing.T) { _, err := server.TransferLeader(context.Background(), &pboperator.TransferLeaderRequest{}) require.Error(t, err) - require.Equal(t, "Permission denied: provided token lacks permission 'operator:write'", err.Error()) + require.Equal(t, "Permission denied: token with AccessorID '' lacks permission 'operator:write'", err.Error()) } func TestLeaderTransfer_ACL_Allowed(t *testing.T) { diff --git a/agent/structs/acl.go b/agent/structs/acl.go index 46bc46acf..3cb516778 100644 --- a/agent/structs/acl.go +++ b/agent/structs/acl.go @@ -293,10 +293,6 @@ type ACLToken struct { // so this field is being kept to identify legacy tokens even after an auto-upgrade Type string `json:"-"` - // Rules is the V1 acl rules associated with - // DEPRECATED (ACL-Legacy-Compat) - remove once we no longer support v1 ACL compat - Rules string `json:",omitempty"` - // Whether this token is DC local. This means that it will not be synced // to the ACL datacenter and replicated to others. Local bool @@ -484,7 +480,6 @@ func (t *ACLToken) SetHash(force bool) []byte { // Write all the user set fields hash.Write([]byte(t.Description)) hash.Write([]byte(t.Type)) - hash.Write([]byte(t.Rules)) if t.Local { hash.Write([]byte("local")) @@ -521,7 +516,7 @@ func (t *ACLToken) SetHash(force bool) []byte { func (t *ACLToken) EstimateSize() int { // 41 = 16 (RaftIndex) + 8 (Hash) + 8 (ExpirationTime) + 8 (CreateTime) + 1 (Local) - size := 41 + len(t.AccessorID) + len(t.SecretID) + len(t.Description) + len(t.Type) + len(t.Rules) + len(t.AuthMethod) + size := 41 + len(t.AccessorID) + len(t.SecretID) + len(t.Description) + len(t.Type) + len(t.AuthMethod) for _, link := range t.Policies { size += len(link.ID) + len(link.Name) } @@ -555,7 +550,6 @@ type ACLTokenListStub struct { Hash []byte CreateIndex uint64 ModifyIndex uint64 - Legacy bool `json:",omitempty"` acl.EnterpriseMeta ACLAuthMethodEnterpriseMeta } @@ -578,7 +572,6 @@ func (token *ACLToken) Stub() *ACLTokenListStub { Hash: token.Hash, CreateIndex: token.CreateIndex, ModifyIndex: token.ModifyIndex, - Legacy: token.Rules != "", EnterpriseMeta: token.EnterpriseMeta, ACLAuthMethodEnterpriseMeta: token.ACLAuthMethodEnterpriseMeta, } diff --git a/agent/structs/acl_test.go b/agent/structs/acl_test.go index e0aae4c0a..36ccc7ec3 100644 --- a/agent/structs/acl_test.go +++ b/agent/structs/acl_test.go @@ -215,7 +215,6 @@ func TestStructs_ACLToken_Stub(t *testing.T) { require.Equal(t, token.Hash, stub.Hash) require.Equal(t, token.CreateIndex, stub.CreateIndex) require.Equal(t, token.ModifyIndex, stub.ModifyIndex) - require.False(t, stub.Legacy) }) } diff --git a/agent/structs/sanitize_oss.go b/agent/structs/sanitize_oss.go deleted file mode 100644 index 2834ebf59..000000000 --- a/agent/structs/sanitize_oss.go +++ /dev/null @@ -1,26 +0,0 @@ -//go:build !consulent -// +build !consulent - -package structs - -// SanitizeLegacyACLToken does nothing in the OSS builds. It does not mutate -// the input argument at all. -// -// In enterprise builds this hook is necessary to support fixing old multiline -// HCL strings in legacy token Sentinel policies into heredocs. If the token -// was updated and previously had a Hash set, this will also update it. -// -// DEPRECATED (ACL-Legacy-Compat) -func SanitizeLegacyACLToken(token *ACLToken) { -} - -// SanitizeLegacyACLTokenRules does nothing in the OSS builds. It always -// returns an empty string. -// -// In enterprise builds this hook is necessary to support fixing any old -// multiline HCL strings in legacy token Sentinel policies into heredocs. -// -// DEPRECATED (ACL-Legacy-Compat) -func SanitizeLegacyACLTokenRules(rules string) string { - return "" -} diff --git a/api/acl.go b/api/acl.go index 6c131093c..89a6a5618 100644 --- a/api/acl.go +++ b/api/acl.go @@ -45,8 +45,8 @@ type ACLToken struct { Hash []byte `json:",omitempty"` // DEPRECATED (ACL-Legacy-Compat) - // Rules will only be present for legacy tokens returned via the new APIs - Rules string `json:",omitempty"` + // Rules are an artifact of legacy tokens deprecated in Consul 1.4 + Rules string `json:"-"` // Namespace is the namespace the ACLToken is associated with. // Namespaces are a Consul Enterprise feature. @@ -90,7 +90,7 @@ type ACLTokenListEntry struct { ExpirationTime *time.Time `json:",omitempty"` CreateTime time.Time Hash []byte - Legacy bool + Legacy bool `json:"-"` // DEPRECATED // Namespace is the namespace the ACLTokenListEntry is associated with. // Namespacing is a Consul Enterprise feature. @@ -1042,58 +1042,19 @@ func (a *ACL) PolicyList(q *QueryOptions) ([]*ACLPolicyListEntry, *QueryMeta, er // RulesTranslate translates the legacy rule syntax into the current syntax. // -// Deprecated: Support for the legacy syntax translation will be removed -// when legacy ACL support is removed. +// Deprecated: Support for the legacy syntax translation has been removed. +// This function always returns an error. func (a *ACL) RulesTranslate(rules io.Reader) (string, error) { - r := a.c.newRequest("POST", "/v1/acl/rules/translate") - r.body = rules - r.header.Set("Content-Type", "text/plain") - rtt, resp, err := a.c.doRequest(r) - if err != nil { - return "", err - } - defer closeResponseBody(resp) - if err := requireOK(resp); err != nil { - return "", err - } - - qm := &QueryMeta{} - parseQueryMeta(resp, qm) - qm.RequestTime = rtt - - ruleBytes, err := io.ReadAll(resp.Body) - if err != nil { - return "", fmt.Errorf("Failed to read translated rule body: %v", err) - } - - return string(ruleBytes), nil + return "", fmt.Errorf("Legacy ACL rules were deprecated in Consul 1.4") } // RulesTranslateToken translates the rules associated with the legacy syntax // into the current syntax and returns the results. // -// Deprecated: Support for the legacy syntax translation will be removed -// when legacy ACL support is removed. +// Deprecated: Support for the legacy syntax translation has been removed. +// This function always returns an error. func (a *ACL) RulesTranslateToken(tokenID string) (string, error) { - r := a.c.newRequest("GET", "/v1/acl/rules/translate/"+tokenID) - rtt, resp, err := a.c.doRequest(r) - if err != nil { - return "", err - } - defer closeResponseBody(resp) - if err := requireOK(resp); err != nil { - return "", err - } - qm := &QueryMeta{} - parseQueryMeta(resp, qm) - qm.RequestTime = rtt - - ruleBytes, err := io.ReadAll(resp.Body) - if err != nil { - return "", fmt.Errorf("Failed to read translated rule body: %v", err) - } - - return string(ruleBytes), nil + return "", fmt.Errorf("Legacy ACL tokens and rules were deprecated in Consul 1.4") } // RoleCreate will create a new role. It is not allowed for the role parameters diff --git a/api/agent.go b/api/agent.go index bc8efc7fd..8db4d36cc 100644 --- a/api/agent.go +++ b/api/agent.go @@ -1268,35 +1268,35 @@ func (a *Agent) monitor(loglevel string, logJSON bool, stopCh <-chan struct{}, q } // UpdateACLToken updates the agent's "acl_token". See updateToken for more -// details. +// details. Deprecated in Consul 1.4. // // DEPRECATED (ACL-Legacy-Compat) - Prefer UpdateDefaultACLToken for v1.4.3 and above func (a *Agent) UpdateACLToken(token string, q *WriteOptions) (*WriteMeta, error) { - return a.updateToken("acl_token", token, q) + return nil, fmt.Errorf("Legacy ACL Tokens were deprecated in Consul 1.4") } // UpdateACLAgentToken updates the agent's "acl_agent_token". See updateToken -// for more details. +// for more details. Deprecated in Consul 1.4. // // DEPRECATED (ACL-Legacy-Compat) - Prefer UpdateAgentACLToken for v1.4.3 and above func (a *Agent) UpdateACLAgentToken(token string, q *WriteOptions) (*WriteMeta, error) { - return a.updateToken("acl_agent_token", token, q) + return nil, fmt.Errorf("Legacy ACL Tokens were deprecated in Consul 1.4") } // UpdateACLAgentMasterToken updates the agent's "acl_agent_master_token". See -// updateToken for more details. +// updateToken for more details. Deprecated in Consul 1.4. // // DEPRECATED (ACL-Legacy-Compat) - Prefer UpdateAgentMasterACLToken for v1.4.3 and above func (a *Agent) UpdateACLAgentMasterToken(token string, q *WriteOptions) (*WriteMeta, error) { - return a.updateToken("acl_agent_master_token", token, q) + return nil, fmt.Errorf("Legacy ACL Tokens were deprecated in Consul 1.4") } // UpdateACLReplicationToken updates the agent's "acl_replication_token". See -// updateToken for more details. +// updateToken for more details. Deprecated in Consul 1.4. // // DEPRECATED (ACL-Legacy-Compat) - Prefer UpdateReplicationACLToken for v1.4.3 and above func (a *Agent) UpdateACLReplicationToken(token string, q *WriteOptions) (*WriteMeta, error) { - return a.updateToken("acl_replication_token", token, q) + return nil, fmt.Errorf("Legacy ACL Tokens were deprecated in Consul 1.4") } // UpdateDefaultACLToken updates the agent's "default" token. See updateToken diff --git a/api/agent_test.go b/api/agent_test.go index 83a3e8d62..a36e35a94 100644 --- a/api/agent_test.go +++ b/api/agent_test.go @@ -14,10 +14,11 @@ import ( "testing" "time" - "github.com/hashicorp/serf/serf" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/hashicorp/serf/serf" + "github.com/hashicorp/consul/sdk/testutil" "github.com/hashicorp/consul/sdk/testutil/retry" ) @@ -1543,19 +1544,19 @@ func TestAPI_AgentUpdateToken(t *testing.T) { t.Run("deprecated", func(t *testing.T) { agent := c.Agent() if _, err := agent.UpdateACLToken("root", nil); err != nil { - t.Fatalf("err: %v", err) + require.Contains(t, err.Error(), "Legacy ACL Tokens were deprecated in Consul 1.4") } if _, err := agent.UpdateACLAgentToken("root", nil); err != nil { - t.Fatalf("err: %v", err) + require.Contains(t, err.Error(), "Legacy ACL Tokens were deprecated in Consul 1.4") } if _, err := agent.UpdateACLAgentMasterToken("root", nil); err != nil { - t.Fatalf("err: %v", err) + require.Contains(t, err.Error(), "Legacy ACL Tokens were deprecated in Consul 1.4") } if _, err := agent.UpdateACLReplicationToken("root", nil); err != nil { - t.Fatalf("err: %v", err) + require.Contains(t, err.Error(), "Legacy ACL Tokens were deprecated in Consul 1.4") } }) diff --git a/api/api_test.go b/api/api_test.go index 668fa1add..268105fc7 100644 --- a/api/api_test.go +++ b/api/api_test.go @@ -915,7 +915,7 @@ func TestAPI_Headers(t *testing.T) { `)) // ACL support is disabled require.Error(t, err) - require.Equal(t, "text/plain", request.Header.Get("Content-Type")) + require.Equal(t, "application/octet-stream", request.Header.Get("Content-Type")) _, _, err = c.Event().Fire(&UserEvent{ Name: "test", diff --git a/command/acl/acl_helpers.go b/command/acl/acl_helpers.go index e9e33d6c6..ea51fad80 100644 --- a/command/acl/acl_helpers.go +++ b/command/acl/acl_helpers.go @@ -94,37 +94,6 @@ func GetPolicyIDByName(client *api.Client, name string) (string, error) { return policy.ID, nil } -func GetRulesFromLegacyToken(client *api.Client, tokenID string, isSecret bool) (string, error) { - tokenID, err := GetTokenIDFromPartial(client, tokenID) - if err != nil { - return "", err - } - - var token *api.ACLToken - if isSecret { - qopts := api.QueryOptions{ - Token: tokenID, - } - token, _, err = client.ACL().TokenReadSelf(&qopts) - } else { - token, _, err = client.ACL().TokenRead(tokenID, nil) - } - - if err != nil { - return "", fmt.Errorf("Error reading token: %v", err) - } - - if token == nil { - return "", fmt.Errorf("Token not found for ID") - } - - if token.Rules == "" { - return "", fmt.Errorf("Token is not a legacy token with rules") - } - - return token.Rules, nil -} - func GetRoleIDFromPartial(client *api.Client, partialID string) (string, error) { // the full UUID string was given if len(partialID) == 36 { diff --git a/command/acl/policy/create/policy_create.go b/command/acl/policy/create/policy_create.go index 46bc2b596..a2e3690d4 100644 --- a/command/acl/policy/create/policy_create.go +++ b/command/acl/policy/create/policy_create.go @@ -8,9 +8,7 @@ import ( "github.com/mitchellh/cli" - "github.com/hashicorp/consul/acl" "github.com/hashicorp/consul/api" - aclhelpers "github.com/hashicorp/consul/command/acl" "github.com/hashicorp/consul/command/acl/policy" "github.com/hashicorp/consul/command/flags" "github.com/hashicorp/consul/command/helpers" @@ -33,10 +31,8 @@ type cmd struct { datacenters []string rules string - fromToken string - tokenIsSecret bool - showMeta bool - format string + showMeta bool + format string testStdin io.Reader } @@ -52,11 +48,6 @@ func (c *cmd) init() { c.flags.StringVar(&c.rules, "rules", "", "The policy rules. May be prefixed with '@' "+ "to indicate that the value is a file path to load the rules from. '-' may also be "+ "given to indicate that the rules are available on stdin") - c.flags.StringVar(&c.fromToken, "from-token", "", "The legacy token to retrieve the rules "+ - "for when creating this policy. When this is specified no other rules should be given. "+ - "Similar to the -rules option the token to use can be loaded from stdin or from a file") - c.flags.BoolVar(&c.tokenIsSecret, "token-secret", false, "Indicates the token provided with "+ - "-from-token is a SecretID and not an AccessorID") c.flags.StringVar( &c.format, "format", @@ -71,29 +62,6 @@ func (c *cmd) init() { c.help = flags.Usage(help, c.flags) } -func (c *cmd) getRules(client *api.Client) (string, error) { - if c.fromToken != "" && c.rules != "" { - return "", fmt.Errorf("Cannot specify both -rules and -from-token") - } - - if c.fromToken != "" { - tokenID, err := helpers.LoadDataSource(c.fromToken, c.testStdin) - if err != nil { - return "", fmt.Errorf("Invalid -from-token value: %v", err) - } - - rules, err := aclhelpers.GetRulesFromLegacyToken(client, tokenID, c.tokenIsSecret) - if err != nil { - return "", err - } - - translated, err := acl.TranslateLegacyRules([]byte(rules)) - return string(translated), err - } - - return helpers.LoadDataSource(c.rules, c.testStdin) -} - func (c *cmd) Run(args []string) int { if err := c.flags.Parse(args); err != nil { return 1 @@ -111,7 +79,7 @@ func (c *cmd) Run(args []string) int { return 1 } - rules, err := c.getRules(client) + rules, err := helpers.LoadDataSource(c.rules, c.testStdin) if err != nil { c.UI.Error(fmt.Sprintf("Error loading rules: %v", err)) return 1 @@ -160,10 +128,10 @@ const ( help = ` Usage: consul acl policy create -name NAME [options] - Both the -rules and -from-token option values allow loading the value - from stdin, a file or the raw value. To use stdin pass '-' as the value. - To load the value from a file prefix the value with an '@'. Any other - values will be used directly. + The -rules option values allows loading the value from stdin, a file + or the raw value. To use stdin pass '-' as the value. To load the value + from a file prefix the value with an '@'. Any other values will be used + directly. Create a new policy: @@ -172,11 +140,5 @@ Usage: consul acl policy create -name NAME [options] -datacenter "dc1" \ -datacenter "dc2" \ -rules @rules.hcl - - Creation a policy from a legacy token: - - $ consul acl policy create -name "legacy-policy" \ - -description "Token Converted to policy" \ - -from-token "c1e34113-e7ab-4451-b1a6-336ddcc58fc6" ` ) diff --git a/command/acl/rules/translate.go b/command/acl/rules/translate.go deleted file mode 100644 index b8053ba74..000000000 --- a/command/acl/rules/translate.go +++ /dev/null @@ -1,147 +0,0 @@ -package rules - -import ( - "flag" - "fmt" - "io" - "strings" - - "github.com/mitchellh/cli" - - "github.com/hashicorp/consul/acl" - aclhelpers "github.com/hashicorp/consul/command/acl" - "github.com/hashicorp/consul/command/flags" - "github.com/hashicorp/consul/command/helpers" -) - -func New(ui cli.Ui) *cmd { - c := &cmd{UI: ui} - c.init() - return c -} - -type cmd struct { - UI cli.Ui - flags *flag.FlagSet - http *flags.HTTPFlags - help string - - tokenAccessor bool - tokenSecret bool - - // testStdin is the input for testing - testStdin io.Reader -} - -func (c *cmd) init() { - c.flags = flag.NewFlagSet("", flag.ContinueOnError) - c.flags.BoolVar(&c.tokenAccessor, "token-accessor", false, "Specifies that "+ - "the TRANSLATE argument refers to a ACL token AccessorID. "+ - "The rules to translate will then be read from the retrieved token") - - c.flags.BoolVar(&c.tokenSecret, "token-secret", false, - "Specifies that the TRANSLATE argument refers to a ACL token SecretID. "+ - "The rules to translate will then be read from the retrieved token") - - c.http = &flags.HTTPFlags{} - flags.Merge(c.flags, c.http.ClientFlags()) - flags.Merge(c.flags, c.http.ServerFlags()) - c.help = flags.Usage(help, c.flags) -} - -func (c *cmd) Run(args []string) int { - if err := c.flags.Parse(args); err != nil { - return 1 - } - - if c.tokenSecret && c.tokenAccessor { - c.UI.Error(fmt.Sprintf("Error - cannot specify both -token-secret and -token-accessor")) - return 1 - } - - data, err := c.dataFromArgs(c.flags.Args()) - if err != nil { - c.UI.Error(fmt.Sprintf("Error! %v", err)) - return 1 - } - - if c.tokenSecret || c.tokenAccessor { - client, err := c.http.APIClient() - if err != nil { - c.UI.Error(fmt.Sprintf("Error connecting to Consul Agent: %s", err)) - return 1 - } - - // Trim whitespace and newlines (e.g. from echo without -n) - data = strings.TrimSpace(data) - - // It is not a bug that this doesn't look at tokenAccessor. We already know that we want the rules from - // a token and just need to tell the helper function whether it should be retrieved by its secret or accessor - if rules, err := aclhelpers.GetRulesFromLegacyToken(client, data, c.tokenSecret); err != nil { - c.UI.Error(err.Error()) - return 1 - } else { - data = rules - } - } - - translated, err := acl.TranslateLegacyRules([]byte(data)) - if err != nil { - c.UI.Error(fmt.Sprintf("Error translating rules: %s", err)) - return 1 - } - - c.UI.Info(string(translated)) - return 0 -} - -func (c *cmd) dataFromArgs(args []string) (string, error) { - switch len(args) { - case 0: - return "", fmt.Errorf("Missing TRANSLATE argument") - case 1: - data, err := helpers.LoadDataSource(args[0], c.testStdin) - if err != nil { - return "", err - } - - return data, nil - default: - return "", fmt.Errorf("Too many arguments: expected 1 got %d", len(args)) - } -} - -func (c *cmd) Synopsis() string { - return synopsis -} - -func (c *cmd) Help() string { - return flags.Usage(c.help, nil) -} - -const synopsis = "Translate the legacy rule syntax into the current syntax" -const help = ` -Usage: consul acl translate-rules [options] TRANSLATE - - Translates the legacy ACL rule syntax into the current syntax. - - Translate rules within a file: - - $ consul acl translate-rules @rules.hcl - - Translate rules from stdin: - - $ consul acl translate-rules - - - Translate rules from a string argument: - - $ consul acl translate-rules 'key "" { policy = "write"}' - - Translate rules for a legacy ACL token using its SecretID passed from stdin: - - $ consul acl translate-rules -token-secret - - - Translate rules for a legacy ACL token using its AccessorID: - - $ consul acl translate-rules -token-accessor 429cd746-03d5-4bbb-a83a-18b164171c89 -` diff --git a/command/acl/rules/translate_test.go b/command/acl/rules/translate_test.go deleted file mode 100644 index 6772d60d6..000000000 --- a/command/acl/rules/translate_test.go +++ /dev/null @@ -1,117 +0,0 @@ -package rules - -import ( - "io" - "os" - "strings" - "testing" - - "github.com/hashicorp/consul/agent" - "github.com/hashicorp/consul/sdk/testutil" - "github.com/hashicorp/consul/testrpc" - "github.com/mitchellh/cli" - "github.com/stretchr/testify/require" -) - -func TestRulesTranslateCommand_noTabs(t *testing.T) { - t.Parallel() - - if strings.ContainsRune(New(cli.NewMockUi()).Help(), '\t') { - t.Fatal("help has tabs") - } -} - -func TestRulesTranslateCommand(t *testing.T) { - if testing.Short() { - t.Skip("too slow for testing.Short") - } - - t.Parallel() - - testDir := testutil.TempDir(t, "acl") - - a := agent.NewTestAgent(t, ` - primary_datacenter = "dc1" - acl { - enabled = true - tokens { - initial_management = "root" - } - }`) - - defer a.Shutdown() - testrpc.WaitForLeader(t, a.RPC, "dc1") - stdinR, stdinW := io.Pipe() - - ui := cli.NewMockUi() - cmd := New(ui) - cmd.testStdin = stdinR - - rules := "service \"\" { policy = \"write\" }" - expected := "service_prefix \"\" {\n policy = \"write\"\n}" - - // From a file - t.Run("file", func(t *testing.T) { - err := os.WriteFile(testDir+"/rules.hcl", []byte(rules), 0644) - require.NoError(t, err) - - args := []string{ - "-http-addr=" + a.HTTPAddr(), - "-token=root", - "@" + testDir + "/rules.hcl", - } - - code := cmd.Run(args) - require.Equal(t, code, 0) - require.Empty(t, ui.ErrorWriter.String()) - require.Contains(t, ui.OutputWriter.String(), expected) - }) - - // From stdin - t.Run("stdin", func(t *testing.T) { - go func() { - stdinW.Write([]byte(rules)) - stdinW.Close() - }() - - args := []string{ - "-http-addr=" + a.HTTPAddr(), - "-token=root", - "-", - } - - code := cmd.Run(args) - require.Equal(t, code, 0) - require.Empty(t, ui.ErrorWriter.String()) - require.Contains(t, ui.OutputWriter.String(), expected) - }) - - // From arg - t.Run("arg", func(t *testing.T) { - args := []string{ - "-http-addr=" + a.HTTPAddr(), - "-token=root", - rules, - } - - code := cmd.Run(args) - require.Equal(t, code, 0) - require.Empty(t, ui.ErrorWriter.String()) - require.Contains(t, ui.OutputWriter.String(), expected) - }) - - // cannot specify both secret and accessor - t.Run("exclusive-options", func(t *testing.T) { - args := []string{ - "-http-addr=" + a.HTTPAddr(), - "-token=root", - "-token-secret", - "-token-accessor", - `token "" { policy = "write" }`, - } - - code := cmd.Run(args) - require.Equal(t, 1, code, 0) - require.Equal(t, "Error - cannot specify both -token-secret and -token-accessor\n", ui.ErrorWriter.String()) - }) -} diff --git a/command/acl/token/clone/token_clone_test.go b/command/acl/token/clone/token_clone_test.go index 582319ad4..88a393ecf 100644 --- a/command/acl/token/clone/token_clone_test.go +++ b/command/acl/token/clone/token_clone_test.go @@ -17,7 +17,6 @@ import ( ) func parseCloneOutput(t *testing.T, output string) *api.ACLToken { - // This will only work for non-legacy tokens re := regexp.MustCompile("AccessorID: ([a-zA-Z0-9\\-]{36})\n" + "SecretID: ([a-zA-Z0-9\\-]{36})\n" + "(?:Partition: default\n)?" + diff --git a/command/acl/token/formatter.go b/command/acl/token/formatter.go index 7844c9cc4..65790881a 100644 --- a/command/acl/token/formatter.go +++ b/command/acl/token/formatter.go @@ -106,10 +106,6 @@ func (f *prettyFormatter) FormatToken(token *api.ACLToken) (string, error) { buffer.WriteString(fmt.Sprintf(" %s (Datacenter: %s)\n", nodeid.NodeName, nodeid.Datacenter)) } } - if token.Rules != "" { - buffer.WriteString(fmt.Sprintln("Rules:")) - buffer.WriteString(fmt.Sprintln(token.Rules)) - } return buffer.String(), nil } @@ -303,7 +299,6 @@ func (f *prettyFormatter) formatTokenListEntry(token *api.ACLTokenListEntry) str if token.ExpirationTime != nil && !token.ExpirationTime.IsZero() { buffer.WriteString(fmt.Sprintf("Expiration Time: %v\n", *token.ExpirationTime)) } - buffer.WriteString(fmt.Sprintf("Legacy: %t\n", token.Legacy)) if f.showMeta { buffer.WriteString(fmt.Sprintf("Hash: %x\n", token.Hash)) buffer.WriteString(fmt.Sprintf("Create Index: %d\n", token.CreateIndex)) diff --git a/command/acl/token/formatter_test.go b/command/acl/token/formatter_test.go index 92df4105a..a97fb346b 100644 --- a/command/acl/token/formatter_test.go +++ b/command/acl/token/formatter_test.go @@ -9,8 +9,9 @@ import ( "testing" "time" - "github.com/hashicorp/consul/api" "github.com/stretchr/testify/require" + + "github.com/hashicorp/consul/api" ) // update allows golden files to be updated based on the current output. @@ -56,14 +57,6 @@ func TestFormatToken(t *testing.T) { ModifyIndex: 100, }, }, - "legacy": { - token: api.ACLToken{ - AccessorID: "8acc7486-ca54-4d3c-9aed-5cd85651b0ee", - SecretID: "legacy-secret", - Description: "legacy", - Rules: `operator = "read"`, - }, - }, "complex": { token: api.ACLToken{ AccessorID: "fbd2447f-7479-4329-ad13-b021d74f86ba", @@ -166,16 +159,6 @@ func TestFormatTokenList(t *testing.T) { }, }, }, - "legacy": { - tokens: []*api.ACLTokenListEntry{ - { - AccessorID: "8acc7486-ca54-4d3c-9aed-5cd85651b0ee", - SecretID: "257ade69-748c-4022-bafd-76d27d9143f8", - Description: "legacy", - Legacy: true, - }, - }, - }, "complex": { tokens: []*api.ACLTokenListEntry{ { diff --git a/command/acl/token/testdata/FormatToken/legacy.json.golden b/command/acl/token/testdata/FormatToken/legacy.json.golden deleted file mode 100644 index 71536fc2f..000000000 --- a/command/acl/token/testdata/FormatToken/legacy.json.golden +++ /dev/null @@ -1,10 +0,0 @@ -{ - "CreateIndex": 0, - "ModifyIndex": 0, - "AccessorID": "8acc7486-ca54-4d3c-9aed-5cd85651b0ee", - "SecretID": "legacy-secret", - "Description": "legacy", - "Local": false, - "CreateTime": "0001-01-01T00:00:00Z", - "Rules": "operator = \"read\"" -} \ No newline at end of file diff --git a/command/acl/token/testdata/FormatToken/legacy.pretty-meta.golden b/command/acl/token/testdata/FormatToken/legacy.pretty-meta.golden deleted file mode 100644 index cb477af5a..000000000 --- a/command/acl/token/testdata/FormatToken/legacy.pretty-meta.golden +++ /dev/null @@ -1,10 +0,0 @@ -AccessorID: 8acc7486-ca54-4d3c-9aed-5cd85651b0ee -SecretID: legacy-secret -Description: legacy -Local: false -Create Time: 0001-01-01 00:00:00 +0000 UTC -Hash: -Create Index: 0 -Modify Index: 0 -Rules: -operator = "read" diff --git a/command/acl/token/testdata/FormatToken/legacy.pretty.golden b/command/acl/token/testdata/FormatToken/legacy.pretty.golden deleted file mode 100644 index ea6c5b715..000000000 --- a/command/acl/token/testdata/FormatToken/legacy.pretty.golden +++ /dev/null @@ -1,7 +0,0 @@ -AccessorID: 8acc7486-ca54-4d3c-9aed-5cd85651b0ee -SecretID: legacy-secret -Description: legacy -Local: false -Create Time: 0001-01-01 00:00:00 +0000 UTC -Rules: -operator = "read" diff --git a/command/acl/token/testdata/FormatTokenList/basic.json.golden b/command/acl/token/testdata/FormatTokenList/basic.json.golden index 8e0b768de..d60d681d2 100644 --- a/command/acl/token/testdata/FormatTokenList/basic.json.golden +++ b/command/acl/token/testdata/FormatTokenList/basic.json.golden @@ -7,7 +7,6 @@ "Description": "test token", "Local": false, "CreateTime": "2020-05-22T18:52:31Z", - "Hash": "YWJjZGVmZ2g=", - "Legacy": false + "Hash": "YWJjZGVmZ2g=" } ] \ No newline at end of file diff --git a/command/acl/token/testdata/FormatTokenList/basic.pretty-meta.golden b/command/acl/token/testdata/FormatTokenList/basic.pretty-meta.golden index 6454b4f4c..3741695ef 100644 --- a/command/acl/token/testdata/FormatTokenList/basic.pretty-meta.golden +++ b/command/acl/token/testdata/FormatTokenList/basic.pretty-meta.golden @@ -3,7 +3,6 @@ SecretID: 257ade69-748c-4022-bafd-76d27d9143f8 Description: test token Local: false Create Time: 2020-05-22 18:52:31 +0000 UTC -Legacy: false Hash: 6162636465666768 Create Index: 42 Modify Index: 100 diff --git a/command/acl/token/testdata/FormatTokenList/basic.pretty.golden b/command/acl/token/testdata/FormatTokenList/basic.pretty.golden index 013a904bb..727d53961 100644 --- a/command/acl/token/testdata/FormatTokenList/basic.pretty.golden +++ b/command/acl/token/testdata/FormatTokenList/basic.pretty.golden @@ -3,4 +3,3 @@ SecretID: 257ade69-748c-4022-bafd-76d27d9143f8 Description: test token Local: false Create Time: 2020-05-22 18:52:31 +0000 UTC -Legacy: false diff --git a/command/acl/token/testdata/FormatTokenList/complex.json.golden b/command/acl/token/testdata/FormatTokenList/complex.json.golden index f61802d14..8bddb0f13 100644 --- a/command/acl/token/testdata/FormatTokenList/complex.json.golden +++ b/command/acl/token/testdata/FormatTokenList/complex.json.golden @@ -44,7 +44,6 @@ "ExpirationTime": "2020-05-22T19:52:31Z", "CreateTime": "2020-05-22T18:52:31Z", "Hash": "YWJjZGVmZ2g=", - "Legacy": false, "Namespace": "foo", "AuthMethodNamespace": "baz" } diff --git a/command/acl/token/testdata/FormatTokenList/complex.pretty-meta.golden b/command/acl/token/testdata/FormatTokenList/complex.pretty-meta.golden index 11e05cfe4..c14bd7058 100644 --- a/command/acl/token/testdata/FormatTokenList/complex.pretty-meta.golden +++ b/command/acl/token/testdata/FormatTokenList/complex.pretty-meta.golden @@ -6,7 +6,6 @@ Local: false Auth Method: bar (Namespace: baz) Create Time: 2020-05-22 18:52:31 +0000 UTC Expiration Time: 2020-05-22 19:52:31 +0000 UTC -Legacy: false Hash: 6162636465666768 Create Index: 5 Modify Index: 10 diff --git a/command/acl/token/testdata/FormatTokenList/complex.pretty.golden b/command/acl/token/testdata/FormatTokenList/complex.pretty.golden index 596d7aba0..4a3c01174 100644 --- a/command/acl/token/testdata/FormatTokenList/complex.pretty.golden +++ b/command/acl/token/testdata/FormatTokenList/complex.pretty.golden @@ -6,7 +6,6 @@ Local: false Auth Method: bar (Namespace: baz) Create Time: 2020-05-22 18:52:31 +0000 UTC Expiration Time: 2020-05-22 19:52:31 +0000 UTC -Legacy: false Policies: beb04680-815b-4d7c-9e33-3d707c24672c - hobbiton 18788457-584c-4812-80d3-23d403148a90 - bywater diff --git a/command/acl/token/testdata/FormatTokenList/legacy.json.golden b/command/acl/token/testdata/FormatTokenList/legacy.json.golden deleted file mode 100644 index 1a6622838..000000000 --- a/command/acl/token/testdata/FormatTokenList/legacy.json.golden +++ /dev/null @@ -1,13 +0,0 @@ -[ - { - "CreateIndex": 0, - "ModifyIndex": 0, - "AccessorID": "8acc7486-ca54-4d3c-9aed-5cd85651b0ee", - "SecretID": "257ade69-748c-4022-bafd-76d27d9143f8", - "Description": "legacy", - "Local": false, - "CreateTime": "0001-01-01T00:00:00Z", - "Hash": null, - "Legacy": true - } -] \ No newline at end of file diff --git a/command/acl/token/testdata/FormatTokenList/legacy.pretty-meta.golden b/command/acl/token/testdata/FormatTokenList/legacy.pretty-meta.golden deleted file mode 100644 index 76107205c..000000000 --- a/command/acl/token/testdata/FormatTokenList/legacy.pretty-meta.golden +++ /dev/null @@ -1,9 +0,0 @@ -AccessorID: 8acc7486-ca54-4d3c-9aed-5cd85651b0ee -SecretID: 257ade69-748c-4022-bafd-76d27d9143f8 -Description: legacy -Local: false -Create Time: 0001-01-01 00:00:00 +0000 UTC -Legacy: true -Hash: -Create Index: 0 -Modify Index: 0 diff --git a/command/acl/token/testdata/FormatTokenList/legacy.pretty.golden b/command/acl/token/testdata/FormatTokenList/legacy.pretty.golden deleted file mode 100644 index d0410e10a..000000000 --- a/command/acl/token/testdata/FormatTokenList/legacy.pretty.golden +++ /dev/null @@ -1,6 +0,0 @@ -AccessorID: 8acc7486-ca54-4d3c-9aed-5cd85651b0ee -SecretID: 257ade69-748c-4022-bafd-76d27d9143f8 -Description: legacy -Local: false -Create Time: 0001-01-01 00:00:00 +0000 UTC -Legacy: true diff --git a/command/acl/token/update/token_update.go b/command/acl/token/update/token_update.go index 7c9b4f20f..ad8d613a6 100644 --- a/command/acl/token/update/token_update.go +++ b/command/acl/token/update/token_update.go @@ -38,7 +38,6 @@ type cmd struct { mergeServiceIdents bool mergeNodeIdents bool showMeta bool - upgradeLegacy bool format string } @@ -72,11 +71,6 @@ func (c *cmd) init() { c.flags.Var((*flags.AppendSliceValue)(&c.nodeIdents), "node-identity", "Name of a "+ "node identity to use for this token. May be specified multiple times. Format is "+ "NODENAME:DATACENTER") - c.flags.BoolVar(&c.upgradeLegacy, "upgrade-legacy", false, "Add new polices "+ - "to a legacy token replacing all existing rules. This will cause the legacy "+ - "token to behave exactly like a new token but keep the same Secret.\n"+ - "WARNING: you must ensure that the new policy or policies specified grant "+ - "equivalent or appropriate access for the existing clients using this token.") c.flags.StringVar( &c.format, "format", @@ -119,18 +113,6 @@ func (c *cmd) Run(args []string) int { return 1 } - if c.upgradeLegacy { - if t.Rules == "" { - // This is just for convenience it should actually be harmless to allow it - // to go through anyway. - c.UI.Error(fmt.Sprintf("Can't use -upgrade-legacy on a non-legacy token")) - return 1 - } - // Reset the rules to nothing forcing this to be updated as a non-legacy - // token but with same secret. - t.Rules = "" - } - if c.description != "" { // Only update description if the user specified a new one. This does make // it impossible to completely clear descriptions from CLI but that seems diff --git a/command/acl/token/update/token_update_test.go b/command/acl/token/update/token_update_test.go index 2f5d68ab6..1117c1104 100644 --- a/command/acl/token/update/token_update_test.go +++ b/command/acl/token/update/token_update_test.go @@ -57,9 +57,6 @@ func TestTokenUpdateCommand(t *testing.T) { ) require.NoError(t, err) - // We fetch the legacy token later to give server time to async background - // upgrade it. - run := func(t *testing.T, args []string) *api.ACLToken { ui := cli.NewMockUi() cmd := New(ui) diff --git a/command/registry.go b/command/registry.go index 1d34f746c..bf369903e 100644 --- a/command/registry.go +++ b/command/registry.go @@ -2,7 +2,6 @@ package command import ( "fmt" - "github.com/hashicorp/consul/command/operator/raft/transferleader" "os" "os/signal" "syscall" @@ -34,7 +33,6 @@ import ( aclrlist "github.com/hashicorp/consul/command/acl/role/list" aclrread "github.com/hashicorp/consul/command/acl/role/read" aclrupdate "github.com/hashicorp/consul/command/acl/role/update" - aclrules "github.com/hashicorp/consul/command/acl/rules" acltoken "github.com/hashicorp/consul/command/acl/token" acltclone "github.com/hashicorp/consul/command/acl/token/clone" acltcreate "github.com/hashicorp/consul/command/acl/token/create" @@ -97,6 +95,7 @@ import ( operraft "github.com/hashicorp/consul/command/operator/raft" operraftlist "github.com/hashicorp/consul/command/operator/raft/listpeers" operraftremove "github.com/hashicorp/consul/command/operator/raft/removepeer" + "github.com/hashicorp/consul/command/operator/raft/transferleader" "github.com/hashicorp/consul/command/peering" peerdelete "github.com/hashicorp/consul/command/peering/delete" peerestablish "github.com/hashicorp/consul/command/peering/establish" @@ -139,7 +138,6 @@ func RegisteredCommands(ui cli.Ui) map[string]mcli.CommandFactory { entry{"acl policy read", func(ui cli.Ui) (cli.Command, error) { return aclpread.New(ui), nil }}, entry{"acl policy update", func(ui cli.Ui) (cli.Command, error) { return aclpupdate.New(ui), nil }}, entry{"acl policy delete", func(ui cli.Ui) (cli.Command, error) { return aclpdelete.New(ui), nil }}, - entry{"acl translate-rules", func(ui cli.Ui) (cli.Command, error) { return aclrules.New(ui), nil }}, entry{"acl set-agent-token", func(ui cli.Ui) (cli.Command, error) { return aclagent.New(ui), nil }}, entry{"acl token", func(cli.Ui) (cli.Command, error) { return acltoken.New(), nil }}, entry{"acl token create", func(ui cli.Ui) (cli.Command, error) { return acltcreate.New(ui), nil }}, diff --git a/website/content/api-docs/acl/index.mdx b/website/content/api-docs/acl/index.mdx index 0eeb7c722..835a8e28d 100644 --- a/website/content/api-docs/acl/index.mdx +++ b/website/content/api-docs/acl/index.mdx @@ -6,9 +6,7 @@ description: The /acl endpoints manage the Consul's ACL system. # ACL HTTP API --> **1.4.0+:** This API documentation is for Consul versions 1.4.0 and later. The documentation for the legacy ACL API is [here](/consul/api-docs/acl/legacy). - -The `/acl` endpoints are used to manage ACL tokens and policies in Consul, [bootstrap the ACL system](#bootstrap-acls), [check ACL replication status](#check-acl-replication), and [translate rules](#translate-rules). There are additional pages for managing [tokens](/consul/api-docs/acl/tokens) and [policies](/consul/api-docs/acl/policies) with the `/acl` endpoints. +The `/acl` endpoints are used to manage ACL tokens and policies in Consul, [bootstrap the ACL system](#bootstrap-acls) and [check ACL replication status](#check-acl-replication). There are additional pages for managing [tokens](/consul/api-docs/acl/tokens) and [policies](/consul/api-docs/acl/policies) with the `/acl` endpoints. For more information on how to setup ACLs, please check the [ACL tutorial](/consul/tutorials/security/access-control-setup-production). @@ -50,12 +48,8 @@ $ curl \ ### Sample Response --> **Deprecated** - The `ID` field in the response is for legacy compatibility and is a copy of the `SecretID` field. New -applications should ignore the `ID` field as it may be removed in a future major Consul version. - ```json { - "ID": "527347d3-9653-07dc-adc0-598b8f2b0f4d", "AccessorID": "b5b1a918-50bc-fc46-dec2-d481359da4e3", "SecretID": "527347d3-9653-07dc-adc0-598b8f2b0f4d", "Description": "Bootstrap Token (Global Management)", @@ -163,18 +157,13 @@ $ curl \ - `ReplicationType` - The type of replication that is currently in use. - - `legacy` - (removed in Consul 1.11.0) ACL replication is in legacy mode and is replicating legacy ACL tokens. - - `policies` - ACL replication is only replicating policies as token replication is disabled. - `tokens` - ACL replication is replicating both policies and tokens. - `ReplicatedIndex` - The last index that was successfully replicated. Which data - the replicated index refers to depends on the replication type. For `legacy` - replication this can be compared with the value of the `X-Consul-Index` header - returned by the [`/v1/acl/list`](/consul/api-docs/acl/legacy#list-acls) endpoint to - determine if the replication process has gotten all available ACLs. When in either + the replicated index refers to depends on the replication type. When in either `tokens` or `policies` mode, this index can be compared with the value of the `X-Consul-Index` header returned by the [`/v1/acl/policies`](/consul/api-docs/acl/policies#list-policies) endpoint to determine if the policy replication process has gotten all available @@ -201,94 +190,6 @@ $ curl \ - `LastErrorMessage` - The last error message produced at the time of `LastError`. An empty string indicates that no sync has resulted in an error. -## Translate Rules - --> **Deprecated** - This endpoint was removed in Consul 1.11.0. -This endpoint was introduced in Consul 1.4.0 for migration from the previous ACL system. - -This endpoint translates the legacy rule syntax into the latest syntax. It is intended -to be used by operators managing Consul's ACLs and performing legacy token to new policy -migrations. - -| Method | Path | Produces | -| ------ | ---------------------- | ------------ | -| `POST` | `/acl/rules/translate` | `text/plain` | - -The table below shows this endpoint's support for -[blocking queries](/consul/api-docs/features/blocking), -[consistency modes](/consul/api-docs/features/consistency), -[agent caching](/consul/api-docs/features/caching), and -[required ACLs](/consul/api-docs/api-structure#authentication). - -| Blocking Queries | Consistency Modes | Agent Caching | ACL Required | -| ---------------- | ----------------- | ------------- | ------------ | -| `NO` | `none` | `none` | `acl:read` | - -The corresponding CLI command is [`consul acl translate-rules`](/consul/commands/acl/translate-rules). - -### Sample Payload - -```hcl -agent "" { - policy = "read" -} -``` - -### Sample Request - -```shell-session -$ curl --request POST --data @rules.hcl http://127.0.0.1:8500/v1/acl/rules/translate -``` - -### Sample Response - -```hcl -agent_prefix "" { - policy = "read" -} -``` - -## Translate a Legacy Token's Rules - --> **Deprecated** - This endpoint was removed in Consul 1.11.0. -This endpoint was introduced in Consul 1.4.0 for migration from the previous ACL system. - -This endpoint translates the legacy rules embedded within a legacy ACL into the latest -syntax. It is intended to be used by operators managing Consul's ACLs and performing -legacy token to new policy migrations. Note that this API requires the auto-generated -Accessor ID of the legacy token. This ID can be retrieved using the -[`/v1/acl/token/self`](/consul/api-docs/acl/tokens#read-self-token) endpoint. - -| Method | Path | Produces | -| ------ | ----------------------------------- | ------------ | -| `GET` | `/acl/rules/translate/:accessor_id` | `text/plain` | - -The table below shows this endpoint's support for -[blocking queries](/consul/api-docs/features/blocking), -[consistency modes](/consul/api-docs/features/consistency), -[agent caching](/consul/api-docs/features/caching), and -[required ACLs](/consul/api-docs/api-structure#authentication). - -| Blocking Queries | Consistency Modes | Agent Caching | ACL Required | -| ---------------- | ----------------- | ------------- | ------------ | -| `NO` | `none` | `none` | `acl:read` | - -The corresponding CLI command is [`consul acl translate-rules`](/consul/commands/acl/translate-rules). - -### Sample Request - -```shell-session -$ curl --request GET http://127.0.0.1:8500/v1/acl/rules/translate/4f48f7e6-9359-4890-8e67-6144a962b0a5 -``` - -### Sample Response - -```hcl -agent_prefix "" { - policy = "read" -} -``` - ## Login to Auth Method This endpoint was added in Consul 1.5.0 and is used to exchange an [auth diff --git a/website/content/api-docs/acl/legacy.mdx b/website/content/api-docs/acl/legacy.mdx deleted file mode 100644 index 3dd88d57f..000000000 --- a/website/content/api-docs/acl/legacy.mdx +++ /dev/null @@ -1,299 +0,0 @@ ---- -layout: api -page_title: Legacy ACLs - HTTP API -description: >- - The legacy /acl endpoints to create, update, destroy, and query legacy ACL tokens in - Consul. ---- - -# ACL HTTP API - --> **The legacy ACL system was deprecated in Consul 1.4.0 and removed in Consul 1.11.0.** It's _strongly_ -recommended you do not build anything using the legacy system and use -the new ACL [Token](/consul/api-docs/acl/tokens) and [Policy](/consul/api-docs/acl/policies) APIs instead. - -The legacy `/acl` endpoints to create, update, destroy, and query legacy ACL tokens in Consul. - -For more information about ACLs, please check the [ACL tutorial](/consul/tutorials/security/access-control-setup-production). - -## Create ACL Token - -This endpoint makes a new ACL token. - -| Method | Path | Produces | -| ------ | ------------- | ------------------ | -| `PUT` | `/acl/create` | `application/json` | - -The table below shows this endpoint's support for -[blocking queries](/consul/api-docs/features/blocking), -[consistency modes](/consul/api-docs/features/consistency), -[agent caching](/consul/api-docs/features/caching), and -[required ACLs](/consul/api-docs/api-structure#authentication). - -| Blocking Queries | Consistency Modes | Agent Caching | ACL Required | -| ---------------- | ----------------- | ------------- | ------------ | -| `NO` | `none` | `none` | `management` | - -### Parameters - -- `ID` `(string: "")` - Specifies the ID of the ACL. If not provided, a UUID is - generated. - -- `Name` `(string: "")` - Specifies a human-friendly name for the ACL token. - -- `Type` `(string: "client")` - Specifies the type of ACL token. Valid values - are: `client` and `management`. - -- `Rules` `(string: "")` - Specifies rules for this ACL token. The format of the - `Rules` property is detailed in the [ACL Rule documentation](/consul/docs/security/acl/acl-rules). - -### Sample Payload - -```json -{ - "Name": "my-app-token", - "Type": "client", - "Rules": "" -} -``` - -### Sample Request - -```shell-session -$ curl \ - --request PUT \ - --data @payload.json \ - http://127.0.0.1:8500/v1/acl/create -``` - -### Sample Response - -```json -{ - "ID": "adf4238a-882b-9ddc-4a9d-5b6758e4159e" -} -``` - -## Update ACL Token - -This endpoint is used to modify the policy for a given ACL token. Instead of -generating a new token ID, the `ID` field must be provided. - -| Method | Path | Produces | -| ------ | ------------- | ------------------ | -| `PUT` | `/acl/update` | `application/json` | - -The table below shows this endpoint's support for -[blocking queries](/consul/api-docs/features/blocking), -[consistency modes](/consul/api-docs/features/consistency), -[agent caching](/consul/api-docs/features/caching), and -[required ACLs](/consul/api-docs/api-structure#authentication). - -| Blocking Queries | Consistency Modes | Agent Caching | ACL Required | -| ---------------- | ----------------- | ------------- | ------------ | -| `NO` | `none` | `none` | `management` | - -### Parameters - -The parameters are the same as the _create_ endpoint, except the `ID` field is -required. - -### Sample Payload - -```json -{ - "ID": "adf4238a-882b-9ddc-4a9d-5b6758e4159e", - "Name": "my-app-token-updated", - "Type": "client", - "Rules": "# New Rules" -} -``` - -### Sample Request - -```shell-session -$ curl \ - --request PUT \ - --data @payload.json \ - http://127.0.0.1:8500/v1/acl/update -``` - -### Sample Response - -```json -{ - "ID": "adf4238a-882b-9ddc-4a9d-5b6758e4159e" -} -``` - -## Delete ACL Token - -This endpoint deletes an ACL token with the given ID. - -| Method | Path | Produces | -| ------ | -------------------- | ------------------ | -| `PUT` | `/acl/destroy/:uuid` | `application/json` | - -Even though the return type is application/json, the value is either true or -false, indicating whether the delete succeeded. - -The table below shows this endpoint's support for -[blocking queries](/consul/api-docs/features/blocking), -[consistency modes](/consul/api-docs/features/consistency), -[agent caching](/consul/api-docs/features/caching), and -[required ACLs](/consul/api-docs/api-structure#authentication). - -| Blocking Queries | Consistency Modes | Agent Caching | ACL Required | -| ---------------- | ----------------- | ------------- | ------------ | -| `NO` | `none` | `none` | `management` | - -### Parameters - -- `uuid` `(string: )` - Specifies the UUID of the ACL token to - destroy. This is required and is specified as part of the URL path. - -### Sample Request - -```shell-session -$ curl \ - --request PUT \ - http://127.0.0.1:8500/v1/acl/destroy/8f246b77-f3e1-ff88-5b48-8ec93abf3e05 -``` - -### Sample Response - -```json -true -``` - -## Read ACL Token - -This endpoint reads an ACL token with the given ID. - -| Method | Path | Produces | -| ------ | ----------------- | ------------------ | -| `GET` | `/acl/info/:uuid` | `application/json` | - -The table below shows this endpoint's support for -[blocking queries](/consul/api-docs/features/blocking), -[consistency modes](/consul/api-docs/features/consistency), -[agent caching](/consul/api-docs/features/caching), and -[required ACLs](/consul/api-docs/api-structure#authentication). - -| Blocking Queries | Consistency Modes | Agent Caching | ACL Required | -| ---------------- | ----------------- | ------------- | ------------ | -| `YES` | `all` | `none` | `none` | - -Note: No ACL is required because the ACL is specified in the URL path. - -### Parameters - -- `uuid` `(string: )` - Specifies the UUID of the ACL token to - read. This is required and is specified as part of the URL path. - -### Sample Request - -```shell-session -$ curl \ - http://127.0.0.1:8500/v1/acl/info/8f246b77-f3e1-ff88-5b48-8ec93abf3e05 -``` - -### Sample Response - -```json -[ - { - "CreateIndex": 3, - "ModifyIndex": 3, - "ID": "8f246b77-f3e1-ff88-5b48-8ec93abf3e05", - "Name": "Client Token", - "Type": "client", - "Rules": "..." - } -] -``` - -## Clone ACL Token - -This endpoint clones an ACL and returns a new token `ID`. This allows a token to -serve as a template for others, making it simple to generate new tokens without -complex rule management. - -| Method | Path | Produces | -| ------ | ------------------ | ------------------ | -| `PUT` | `/acl/clone/:uuid` | `application/json` | - -The table below shows this endpoint's support for -[blocking queries](/consul/api-docs/features/blocking), -[consistency modes](/consul/api-docs/features/consistency), -[agent caching](/consul/api-docs/features/caching), and -[required ACLs](/consul/api-docs/api-structure#authentication). - -| Blocking Queries | Consistency Modes | Agent Caching | ACL Required | -| ---------------- | ----------------- | ------------- | ------------ | -| `NO` | `none` | `none` | `management` | - -### Parameters - -- `uuid` `(string: )` - Specifies the UUID of the ACL token to - be cloned. This is required and is specified as part of the URL path. - -### Sample Request - -```shell-session -$ curl \ - --request PUT \ - http://127.0.0.1:8500/v1/acl/clone/8f246b77-f3e1-ff88-5b48-8ec93abf3e05 -``` - -### Sample Response - -```json -{ - "ID": "adf4238a-882b-9ddc-4a9d-5b6758e4159e" -} -``` - -## List ACLs - -This endpoint lists all the active ACL tokens. - -| Method | Path | Produces | -| ------ | ----------- | ------------------ | -| `GET` | `/acl/list` | `application/json` | - -The table below shows this endpoint's support for -[blocking queries](/consul/api-docs/features/blocking), -[consistency modes](/consul/api-docs/features/consistency), -[agent caching](/consul/api-docs/features/caching), and -[required ACLs](/consul/api-docs/api-structure#authentication). - -| Blocking Queries | Consistency Modes | Agent Caching | ACL Required | -| ---------------- | ----------------- | ------------- | ------------ | -| `YES` | `all` | `none` | `management` | - -### Sample Request - -```shell-session -$ curl \ - http://127.0.0.1:8500/v1/acl/list -``` - -### Sample Response - -```json -[ - { - "CreateIndex": 3, - "ModifyIndex": 3, - "ID": "8f246b77-f3e1-ff88-5b48-8ec93abf3e05", - "Name": "Client Token", - "Type": "client", - "Rules": "..." - } -] -``` - -## Check ACL Replication - -The check ACL replication endpoint has not changed between the legacy system and the new system. Review the [latest documentation](/consul/api-docs/acl#check-acl-replication) to learn more about this endpoint. diff --git a/website/content/api-docs/acl/policies.mdx b/website/content/api-docs/acl/policies.mdx index e4fb09de0..d0c8f6816 100644 --- a/website/content/api-docs/acl/policies.mdx +++ b/website/content/api-docs/acl/policies.mdx @@ -6,8 +6,6 @@ description: The /acl/policy endpoints manage Consul's ACL policies. # ACL Policy HTTP API --> **1.4.0+:** The APIs are available in Consul versions 1.4.0 and later. The documentation for the legacy ACL API is [here](/consul/api-docs/acl/legacy). - The `/acl/policy` endpoints [create](#create-a-policy), [read](#read-a-policy), [update](#update-a-policy), [list](#list-policies) and [delete](#delete-a-policy) ACL policies in Consul. diff --git a/website/content/api-docs/acl/tokens.mdx b/website/content/api-docs/acl/tokens.mdx index 87819fc62..42b254ddf 100644 --- a/website/content/api-docs/acl/tokens.mdx +++ b/website/content/api-docs/acl/tokens.mdx @@ -6,8 +6,6 @@ description: The /acl/token endpoints manage Consul's ACL Tokens. # ACL Token HTTP API --> **1.4.0+:** The APIs are available in Consul versions 1.4.0 and later. The documentation for the legacy ACL API is [here](/consul/api-docs/acl/legacy). - The `/acl/token` endpoints [create](#create-a-token), [read](#read-a-token), [update](#update-a-token), [list](#list-tokens), [clone](#clone-a-token) and [delete](#delete-a-token) ACL tokens in Consul. diff --git a/website/content/commands/acl/index.mdx b/website/content/commands/acl/index.mdx index 31a629fea..57bff03fe 100644 --- a/website/content/commands/acl/index.mdx +++ b/website/content/commands/acl/index.mdx @@ -2,7 +2,7 @@ layout: commands page_title: 'Commands: ACL' description: >- - The `consul acl` command exposes top-level commands for bootstrapping the ACL system, managing tokens and policies, translating legacy rules, and setting the tokens for use by an agent. + The `consul acl` command exposes top-level commands for bootstrapping the ACL system, managing tokens and policies, and setting the tokens for use by an agent. --- # Consul ACLs @@ -11,7 +11,7 @@ Command: `consul acl` The `acl` command is used to interact with Consul's ACLs via the command line. It exposes top-level commands for bootstrapping the ACL system, -managing tokens and policies, translating legacy rules, and setting the +managing tokens and policies, and setting the tokens for use by an agent. ACLs are also accessible via the [HTTP API](/consul/api-docs/acl). @@ -101,8 +101,6 @@ Subcommands: role Manage Consul's ACL roles set-agent-token Assign tokens for the Consul Agent's usage token Manage Consul's ACL tokens - translate-rules Translate the legacy rule syntax into the current syntax - ``` For more information, examples, and usage about a subcommand, click on the name diff --git a/website/content/commands/acl/policy/create.mdx b/website/content/commands/acl/policy/create.mdx index db871f0ca..cbd4b8d87 100644 --- a/website/content/commands/acl/policy/create.mdx +++ b/website/content/commands/acl/policy/create.mdx @@ -11,14 +11,10 @@ Command: `consul acl policy create` Corresponding HTTP API Endpoint: [\[PUT\] /v1/acl/policy](/consul/api-docs/acl/policies#create-a-policy) -The `acl policy create` command creates new policies. The policies rules can either be set explicitly or the -`-from-token` parameter may be used to load the rules from a legacy ACL token. When loading -the rules from an existing legacy ACL token, the rules get translated from the legacy syntax -to the new syntax. +The `acl policy create` command creates new policies. -Both the `-rules` and `-from-token` parameter values allow loading the value -from stdin, a file or the raw value. To use stdin pass `-` as the value. -To load the value from a file prefix the value with an `@`. Any other +The `-rules` parameter value allow loading the value from stdin, a file or the raw value. +To use stdin pass `-` as the value. To load the value from a file prefix the value with an `@`. Any other values will be used directly. The table below shows this command's [required ACLs](/consul/api-docs/api-structure#authentication). Configuration of @@ -29,10 +25,6 @@ are not supported from commands, but may be from the corresponding HTTP endpoint | ------------ | | `acl:write` | --> **Deprecated:** The `-from-token` and `-token-secret` arguments exist only as a convenience -to make legacy ACL migration easier. These will be removed in a future major release when -support for the legacy ACL system is removed. - ## Usage Usage: `consul acl policy create [options] [args]` @@ -41,11 +33,6 @@ Usage: `consul acl policy create [options] [args]` - `-description=` - A description of the policy. -- `-from-token=` - The legacy token to retrieve the rules for when creating this - policy. When this is specified no other rules should be given. - Similar to the -rules option the token to use can be loaded from - stdin or from a file. - - `-meta` - Indicates that policy metadata such as the content hash and raft indices should be shown for each entry. @@ -55,9 +42,6 @@ Usage: `consul acl policy create [options] [args]` value is a file path to load the rules from. '-' may also be given to indicate that the rules are available on stdin. -- `-token-secret` - Indicates the token provided with -from-token is a SecretID and not - an AccessorID. - - `-valid-datacenter=` - Datacenter that the policy should be valid within. This flag may be specified multiple times. @@ -105,20 +89,3 @@ service_prefix "" { } ``` -Create a new policy with rules equivalent to that of a legacy ACL token: - -```shell-session -$ consul acl policy create -name "node-services-read" -from-token 5793a5ce -description "Can read any node and service" -ID: 06acc965-df4b-5a99-58cb-3250930c6324 -Name: node-services-read -Description: Can read any node and service -Datacenters: -Rules: -service_prefix "" { - policy = "read" -} - -node_prefix "" { - policy = "read" -} -``` diff --git a/website/content/commands/acl/token/list.mdx b/website/content/commands/acl/token/list.mdx index d613dba5c..531b4cc68 100644 --- a/website/content/commands/acl/token/list.mdx +++ b/website/content/commands/acl/token/list.mdx @@ -54,7 +54,6 @@ AccessorID: 4d123dff-f460-73c3-02c4-8dd64d136e01 Description: Bootstrap Token (Global Management) Local: false Create Time: 2018-10-22 11:27:04.479026 -0400 EDT -Legacy: false Policies: 00000000-0000-0000-0000-000000000001 - global-management @@ -62,7 +61,6 @@ AccessorID: 00000000-0000-0000-0000-000000000002 Description: Anonymous Token Local: false Create Time: 0001-01-01 00:00:00 +0000 UTC -Legacy: false Policies: 06acc965-df4b-5a99-58cb-3250930c6324 - node-services-read @@ -70,7 +68,6 @@ AccessorID: 986193b5-e2b5-eb26-6264-b524ea60cc6d Description: WonderToken Local: false Create Time: 2018-10-22 15:33:39.01789 -0400 EDT -Legacy: false Policies: 06acc965-df4b-5a99-58cb-3250930c6324 - node-services-read Service Identities: @@ -80,7 +77,6 @@ AccessorID: def4895d-eeb9-f78a-fbb9-2a15a568af31 Description: Node 1 agent token Local: false Create Time: 2020-12-22 04:19:30.552528733 +0000 UTC -Legacy: false Node Identities: node1 (Datacenter: dc1) ``` diff --git a/website/content/commands/acl/token/update.mdx b/website/content/commands/acl/token/update.mdx index 33a5380d5..28158e6db 100644 --- a/website/content/commands/acl/token/update.mdx +++ b/website/content/commands/acl/token/update.mdx @@ -60,16 +60,6 @@ Usage: `consul acl token update [options]` - `-service-identity=` - Name of a service identity to use for this token. May be specified multiple times. Format is the `SERVICENAME` or `SERVICENAME:DATACENTER1,DATACENTER2,...` -- `-upgrade-legacy` - Add new polices to a legacy token replacing all existing - rules. This will cause the legacy token to behave exactly like a new token - but keep the same secret. - -~> When upgrading a legacy token you must ensure that the new policy or policies -specified grant equivalent or appropriate access for the existing clients using -this token. You can find examples on how to use the parameter in the [legacy -token -migration](https://learn.hashicorp.com/consul/day-2-agent-authentication/migrate-acl-tokens) -guide. - `-format={pretty|json}` - Command output format. The default value is `pretty`. diff --git a/website/content/commands/acl/translate-rules.mdx b/website/content/commands/acl/translate-rules.mdx deleted file mode 100644 index a6413f3a8..000000000 --- a/website/content/commands/acl/translate-rules.mdx +++ /dev/null @@ -1,82 +0,0 @@ ---- -layout: commands -page_title: 'Commands: ACL Translate Rules' -description: >- - The `consul acl translate-rules` command translates the legacy ACL rules into the new syntax when migrating from the legacy ACL system. ---- - --> **Deprecated:** This command exists only as a convenience to make legacy ACL migration easier. -It will be removed in a future major release when support for the legacy ACL system is removed. - -# Consul ACL Translate Rules - -Command: `consul acl translate-rules` - -Corresponding HTTP API Endpoint: [\[GET\] /v1/acl/rules/translate/:accessor_id](/consul/api-docs/acl#translate-a-legacy-token-s-rules) - -This command translates the legacy ACL rule syntax into the new syntax. - -The table below shows this command's [required ACLs](/consul/api-docs/api-structure#authentication). Configuration of -[blocking queries](/consul/api-docs/features/blocking) and [agent caching](/consul/api-docs/features/caching) -are not supported from commands, but may be from the corresponding HTTP endpoint. - -| ACL Required | -| ------------ | -| `acl:read` | - -### Usage - -Usage: `consul acl translate-rules [options] TRANSLATE` - -#### Command Options - -- `TRANSLATE` - The rules to translate. If `-` is used, then - the rules will be read from stdin. If `@` is prefixed to - the value then the value is considered to be a file and - the rules will be read from that file. - -- `-token-secret` - Specifies that what the `TRANSLATE` argument - holds is not a rule set but rather the token secret ID of a - legacy ACL token that holds the rule set. - -- `-token-accessor` - Specifies that what the `TRANSLATE` argument - holds is not a rule set but rather the token accessor ID of a - legacy ACL token that holds the rule set. - -#### API Options - -@include 'http_api_options_client.mdx' - -@include 'http_api_options_server.mdx' - -### Examples - -Translate rules within a file: - -```shell-session -$ consul acl translate-rules @rules.hcl -``` - -Translate rules from stdin: - -```shell-session -$ consul acl translate-rules - -``` - -Translate rules from a string argument: - -```shell-session -$ consul acl translate-rules 'key "" { policy = "write"}' -``` - -Translate rules for a legacy ACL token using its SecretID passed from stdin: - -```shell-session -$ consul acl translate-rules --token-secret - -``` - -Translate rules for a legacy ACL token using its AccessorID: - -```shell-session -$ consul acl translate-rules 429cd746-03d5-4bbb-a83a-18b164171c89 -``` diff --git a/website/content/docs/agent/telemetry.mdx b/website/content/docs/agent/telemetry.mdx index 9859a1439..e640a34e8 100644 --- a/website/content/docs/agent/telemetry.mdx +++ b/website/content/docs/agent/telemetry.mdx @@ -409,8 +409,8 @@ These metrics are used to monitor the health of the Consul servers. |-----------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------|---------| | `consul.acl.ResolveToken` | Measures the time it takes to resolve an ACL token. | ms | timer | | `consul.acl.ResolveTokenToIdentity` | Measures the time it takes to resolve an ACL token to an Identity. This metric was removed in Consul 1.12. The time will now be reflected in `consul.acl.ResolveToken`. | ms | timer | -| `consul.acl.token.cache_hit` | Increments if Consul is able to resolve a token's identity, or a legacy token, from the cache. | cache read op | counter | -| `consul.acl.token.cache_miss` | Increments if Consul cannot resolve a token's identity, or a legacy token, from the cache. | cache read op | counter | +| `consul.acl.token.cache_hit` | Increments if Consul is able to resolve a token's identity from the cache. | cache read op | counter | +| `consul.acl.token.cache_miss` | Increments if Consul cannot resolve a token's identity from the cache. | cache read op | counter | | `consul.cache.bypass` | Counts how many times a request bypassed the cache because no cache-key was provided. | counter | counter | | `consul.cache.fetch_success` | Counts the number of successful fetches by the cache. | counter | counter | | `consul.cache.fetch_error` | Counts the number of failed fetches by the cache. | counter | counter | diff --git a/website/content/docs/security/acl/acl-legacy.mdx b/website/content/docs/security/acl/acl-legacy.mdx deleted file mode 100644 index c524f348e..000000000 --- a/website/content/docs/security/acl/acl-legacy.mdx +++ /dev/null @@ -1,1201 +0,0 @@ ---- -layout: docs -page_title: Legacy ACL System -description: >- - Consul's legacy ACL system was deprecated in version 1.4.0 and removed in version 1.11.0. Learn how Consul's legacy ACL system worked and how it differs from the current ACL system. ---- - -# ACL System in Legacy Mode - --> **1.3.0 and earlier:** This document only applies in Consul versions 1.3.0 and before. If you are using version 1.4.0 or later please use the updated documentation [here](/consul/docs/security/acl). - -~> **Alert: Deprecation Notice** -The ACL system described here was Consul's original ACL implementation. -The legacy ACL system was deprecated in Consul 1.4.0 and removed in Consul 1.11.0. -The documentation for the new ACL system can be found [here](/consul/docs/security/acl). For information on how to migrate to the new ACL System, please read the [Migrate Legacy ACL Tokens](https://learn.hashicorp.com/consul/day-2-agent-authentication/migrate-acl-tokens) tutorial. - -The legacy documentation has two sections. - -- The [New ACL System Differences](#new-acl-system-differences) section - details the differences between ACLs in Consul 1.4.0 and older versions. You should read this section before upgrading to Consul 1.4.0 and [migrating](/consul/docs/security/acl/acl-migrate-tokens) tokens. -- The [Legacy ACL System documentation](#legacy-acl-system) section details the - ACL system in Consul 1.3.0 and older. - -# New ACL System Differences - -The [ACL System documentation](/consul/docs/security/acl) and [legacy ACL -documentation](/consul/docs/security/acl/acl-legacy) describes the new and old systems in -detail. Below is a summary of the changes that need to be considered when -migrating legacy tokens to the new system. - -### Token and Policy Separation - -You can use a single policy in the new system for all tokens that share access -rules. For example, all tokens created using the clone endpoint in the legacy -system can be represented with a single policy and a set of tokens that map to -that policy. - -### Rule Syntax Changes - -The most significant change is that rules with selectors _no longer prefix match -by default_. In the legacy system the following rules would grant access to -nodes, services and keys _prefixed_ with foo. - -```hcl -node "foo" { policy = "write" } -service "foo" { policy = "write" } -key "foo" { policy = "write" } -``` - -In the new system the same syntax will only perform _exact_ match on the whole -node name, service name or key. - -In general, exact match is what most operators intended most of the time so the -same policy can be kept, however if you rely on prefix match behavior then using -the same syntax will break behavior. - -Prefix matching can be expressed in the new ACL system explicitly, making the -following rules in the new system exactly the same as the rules above in the -old. - -```hcl -node_prefix "foo" { policy = "write" } -service_prefix "foo" { policy = "write" } -key_prefix "foo" { policy = "write" } -``` - -### API Separation - -The "old" API endpoints below continue to work for backwards compatibility but -will continue to create or show only "legacy" tokens that can't take full -advantage of the new ACL system improvements. They are documented fully under -[Legacy Tokens](/consul/api-docs/acl/legacy). - -- [`PUT /acl/create` - Create Legacy Token](/consul/api-docs/acl/legacy#create-acl-token) -- [`PUT /acl/update` - Update Legacy Token](/consul/api-docs/acl/legacy#update-acl-token) -- [`PUT /acl/destroy/:uuid` - Delete Legacy Token](/consul/api-docs/acl/legacy#delete-acl-token) -- [`GET /acl/info/:uuid` - Read Legacy Token](/consul/api-docs/acl/legacy#read-acl-token) -- [`PUT /acl/clone/:uuid` - Clone Legacy Token](/consul/api-docs/acl/legacy#clone-acl-token) -- [`GET /acl/list` - List Legacy Tokens](/consul/api-docs/acl/legacy#list-acls) - -The new ACL system includes new API endpoints to manage -the [ACL System](/consul/api-docs/acl), [Tokens](/consul/api-docs/acl/tokens) -and [Policies](/consul/api-docs/acl/policies). - -# Legacy ACL System - -~> **Warning**: In this document we use the deprecated -configuration parameter `acl_datacenter`. In Consul 1.4 and newer the -parameter has been updated to [`primary_datacenter`](/consul/docs/agent/config/config-files#primary_datacenter). - -Consul provides an optional Access Control List (ACL) system which can be used to control -access to data and APIs. The ACL is -[Capability-based](https://en.wikipedia.org/wiki/Capability-based_security), relying -on tokens to which fine grained rules can be applied. It is very similar to -[AWS IAM](http://aws.amazon.com/iam/) in many ways. - -## ACL System Overview - -The ACL system is designed to be easy to use, fast to enforce, and flexible to new policies, -all while providing administrative insight. - -#### ACL Tokens - -The ACL system is based on tokens, which are managed by Consul operators via Consul's -[ACL API](/consul/api-docs/acl), or systems like -[HashiCorp's Vault](/vault/docs/secrets/consul). - -Every token has an ID, name, type, and rule set. The ID is a randomly generated -UUID, making it infeasible to guess. The name is opaque to Consul and human readable. -The type is either "client" (meaning the token cannot modify ACL rules) or "management" -(meaning the token is allowed to perform all actions). - -The token ID is passed along with each RPC request to the servers. Consul's -[HTTP endpoints](/consul/api-docs) can accept tokens via the `token` -query string parameter, or the `X-Consul-Token` request header, or Authorization Bearer -token [RFC6750](https://tools.ietf.org/html/rfc6750). Consul's -[CLI commands](/consul/commands) can accept tokens via the -`token` argument, or the `CONSUL_HTTP_TOKEN` environment variable. - -If no token is provided, the rules associated with a special, configurable anonymous -token are automatically applied. The anonymous token is managed using the -[ACL API](/consul/api-docs/acl) like any other ACL token, but using `anonymous` for the ID. - -#### ACL Rules and Scope - -Tokens are bound to a set of rules that control which Consul resources the token -has access to. Policies can be defined in either an allowlist or denylist mode -depending on the configuration of -[`acl_default_policy`](/consul/docs/agent/config/config-files#acl_default_policy). If the default -policy is to "deny" all actions, then token rules can be set to allowlist specific -actions. In the inverse, the "allow" all default behavior is a denylist where rules -are used to prohibit actions. By default, Consul will allow all actions. - -The following table summarizes the ACL policies that are available for constructing -rules: - -| Policy | Scope | -| -------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [`agent`](#agent-rules) | Utility operations in the [Agent API](/consul/api-docs/agent), other than service and check registration | -| [`event`](#event-rules) | Listing and firing events in the [Event API](/consul/api-docs/event) | -| [`key`](#key-value-rules) | Key/value store operations in the [KV Store API](/consul/api-docs/kv) | -| [`keyring`](#keyring-rules) | Keyring operations in the [Keyring API](/consul/api-docs/operator/keyring) | -| [`node`](#node-rules) | Node-level catalog operations in the [Catalog API](/consul/api-docs/catalog), [Health API](/consul/api-docs/health), [Prepared Query API](/consul/api-docs/query), [Network Coordinate API](/consul/api-docs/coordinate), and [Agent API](/consul/api-docs/agent) | -| [`operator`](#operator-rules) | Cluster-level operations in the [Operator API](/consul/api-docs/operator), other than the [Keyring API](/consul/api-docs/operator/keyring) | -| [`query`](#prepared-query-rules) | Prepared query operations in the [Prepared Query API](/consul/api-docs/query) | -| [`service`](#service-rules) | Service-level catalog operations in the [Catalog API](/consul/api-docs/catalog), [Health API](/consul/api-docs/health), [Prepared Query API](/consul/api-docs/query), and [Agent API](/consul/api-docs/agent) | -| [`session`](#session-rules) | Session operations in the [Session API](/consul/api-docs/session) | - -Since Consul snapshots actually contain ACL tokens, the -[Snapshot API](/consul/api-docs/snapshot) requires a management token for snapshot operations -and does not use a special policy. - -The following resources are not covered by ACL policies: - -1. The [Status API](/consul/api-docs/status) is used by servers when bootstrapping and exposes - basic IP and port information about the servers, and does not allow modification - of any state. - -2. The datacenter listing operation of the - [Catalog API](/consul/api-docs/catalog#list-datacenters) similarly exposes the names of known - Consul datacenters, and does not allow modification of any state. - -Constructing rules from these policies is covered in detail in the -[Rule Specification](#rule-specification) section below. - -#### ACL Datacenter - -All nodes (clients and servers) must be configured with a -[`acl_datacenter`](/consul/docs/agent/config/config-files#acl_datacenter) which enables ACL -enforcement but also specifies the authoritative datacenter. Consul relies on -[RPC forwarding](/consul/docs/architecture) to support multi-datacenter -configurations. However, because requests can be made across datacenter boundaries, -ACL tokens must be valid globally. To avoid consistency issues, a single datacenter -is considered authoritative and stores the canonical set of tokens. - -When a request is made to an agent in a non-authoritative datacenter, it must be -resolved into the appropriate policy. This is done by reading the token from the -authoritative server and caching the result for a configurable -[`acl_ttl`](/consul/docs/agent/config/config-files#acl_ttl). The implication of caching is that -the cache TTL is an upper bound on the staleness of policy that is enforced. It is -possible to set a zero TTL, but this has adverse performance impacts, as every -request requires refreshing the policy via an RPC call. - -During an outage of the ACL datacenter, or loss of connectivity, the cache will be -used as long as the TTL is valid, or the cache may be extended if the -[`acl_down_policy`](/consul/docs/agent/config/config-files#acl_down_policy) is set accordingly. -This configuration also allows the ACL system to fail open or closed. -[ACL replication](#replication) is also available to allow for the full set of ACL -tokens to be replicated for use during an outage. - -## Configuring ACLs - -ACLs are configured using several different configuration options. These are marked -as to whether they are set on servers, clients, or both. - -| Configuration Option | Servers | Clients | Purpose | -| --------------------------------------------------------------------- | ---------- | ---------- | ----------------------------------------------------------------------------------------- | -| [`acl_datacenter`](/consul/docs/agent/config/config-files#acl_datacenter) | `REQUIRED` | `REQUIRED` | Master control that enables ACLs by defining the authoritative Consul datacenter for ACLs | -| [`acl_default_policy`](/consul/docs/agent/config/config-files#acl_default_policy_legacy) | `OPTIONAL` | `N/A` | Determines allowlist or denylist mode | -| [`acl_down_policy`](/consul/docs/agent/config/config-files#acl_down_policy_legacy) | `OPTIONAL` | `OPTIONAL` | Determines what to do when the ACL datacenter is offline | -| [`acl_ttl`](/consul/docs/agent/config/config-files#acl_ttl_legacy) | `OPTIONAL` | `OPTIONAL` | Determines time-to-live for cached ACLs | - -There are some additional configuration items related to [ACL replication](#replication) and -[Version 8 ACL support](#version_8_acls). These are discussed in those respective sections -below. - -A number of special tokens can also be configured which allow for bootstrapping the ACL -system, or accessing Consul in special situations: - -| Special Token | Servers | Clients | Purpose | -| ------------------------------------------------------------------------------------------| ---------- | ---------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| [`acl_agent_master_token`](/consul/docs/agent/config/config-files#acl_agent_master_token_legacy) | `OPTIONAL` | `OPTIONAL` | Special token that can be used to access [Agent API](/consul/api-docs/agent) when the ACL datacenter isn't available, or servers are offline (for clients); used for setting up the cluster such as doing initial join operations, see the [ACL Agent Master Token](#acl-agent-master-token) section for more details | -| [`acl_agent_token`](/consul/docs/agent/config/config-files#acl_agent_token_legacy) | `OPTIONAL` | `OPTIONAL` | Special token that is used for an agent's internal operations, see the [ACL Agent Token](#acl-agent-token) section for more details | -| [`acl_master_token`](/consul/docs/agent/config/config-files#acl_master_token_legacy) | `REQUIRED` | `N/A` | Special token used to bootstrap the ACL system, see the [Bootstrapping ACLs](#bootstrapping-acls) section for more details | -| [`acl_token`](/consul/docs/agent/config/config-files#acl_token_legacy) | `OPTIONAL` | `OPTIONAL` | Default token to use for client requests where no token is supplied; this is often configured with read-only access to services to enable DNS service discovery on agents | - -In Consul 0.9.1 and later, the agent ACL tokens can be introduced or updated via the -[/v1/agent/token API](/consul/api-docs/agent#update-acl-tokens). - -#### ACL Agent Master Token - -Since the [`acl_agent_master_token`](/consul/docs/agent/config/config-files#acl_agent_master_token_legacy) is designed to be used when the Consul servers are not available, its policy is managed locally on the agent and does not need to have a token defined on the Consul servers via the ACL API. Once set, it implicitly has the following policy associated with it (the `node` policy was added in Consul 0.9.0): - -```hcl -agent "" { - policy = "write" -} -node "" { - policy = "read" -} -``` - -In Consul 0.9.1 and later, the agent ACL tokens can be introduced or updated via the -[/v1/agent/token API](/consul/api-docs/agent#update-acl-tokens). - -#### ACL Agent Token - -The [`acl_agent_token`](/consul/docs/agent/config/config-files#acl_agent_token) is a special token that is used for an agent's internal operations. It isn't used directly for any user-initiated operations like the [`acl_token`](/consul/docs/agent/config/config-files#acl_token), though if the `acl_agent_token` isn't configured the `acl_token` will be used. The ACL agent token is used for the following operations by the agent: - -1. Updating the agent's node entry using the [Catalog API](/consul/api-docs/catalog), including updating its node metadata, tagged addresses, and network coordinates -2. Performing [anti-entropy](/consul/docs/architecture/anti-entropy) syncing, in particular reading the node metadata and services registered with the catalog -3. Reading and writing the special `_rexec` section of the KV store when executing [`consul exec`](/consul/commands/exec) commands - -Here's an example policy sufficient to accomplish the above for a node called `mynode`: - -```hcl -node "mynode" { - policy = "write" -} -service "" { - policy = "read" -} -key "_rexec" { - policy = "write" -} -``` - -The `service` policy needs `read` access for any services that can be registered on the agent. If [remote exec is disabled](/consul/docs/agent/config/config-files#disable_remote_exec), the default, then the `key` policy can be omitted. - -In Consul 0.9.1 and later, the agent ACL tokens can be introduced or updated via the -[/v1/agent/token API](/consul/api-docs/agent#update-acl-tokens). - -## Bootstrapping ACLs - -Bootstrapping ACLs on a new cluster requires a few steps, outlined in the examples in this -section. - -#### Enable ACLs on the Consul Servers - -The first step for bootstrapping ACLs is to enable ACLs on the Consul servers in the ACL -datacenter. In this example, we are configuring the following: - -1. An ACL datacenter of "dc1", which is where these servers are -2. An ACL master token of "b1gs33cr3t"; see below for an alternative using the [/v1/acl/bootstrap API](/consul/api-docs/acl#bootstrap-acls) -3. A default policy of "deny" which means we are in allowlist mode -4. A down policy of "extend-cache" which means that we will ignore token TTLs - during an outage - -Here's the corresponding JSON configuration file: - -```json -{ - "acl_datacenter": "dc1", - "acl_master_token": "b1gs33cr3t", - "acl_default_policy": "deny", - "acl_down_policy": "extend-cache" -} -``` - -The servers will need to be restarted to load the new configuration. Please take care -to start the servers one at a time, and ensure each server has joined and is operating -correctly before starting another. - -The [`acl_master_token`](/consul/docs/agent/config/config-files#acl_master_token) will be created -as a "management" type token automatically. The -[`acl_master_token`](/consul/docs/agent/config/config-files#acl_master_token) is only installed when -a server acquires cluster leadership. If you would like to install or change the -[`acl_master_token`](/consul/docs/agent/config/config-files#acl_master_token), set the new value for -[`acl_master_token`](/consul/docs/agent/config/config-files#acl_master_token) in the configuration -for all servers. Once this is done, restart the current leader to force a leader election. - -In Consul 0.9.1 and later, you can use the [/v1/acl/bootstrap API](/consul/api-docs/acl#bootstrap-acls) -to make the initial master token, so a token never needs to be placed into a configuration -file. To use this approach, omit `acl_master_token` from the above config and then call the API: - -```shell-session -$ curl \ - --request PUT \ - http://127.0.0.1:8500/v1/acl/bootstrap - -{"ID":"fe3b8d40-0ee0-8783-6cc2-ab1aa9bb16c1"} -``` - -The returned token is the initial management token, which is randomly generated by Consul. -It's only possible to bootstrap one time, and bootstrapping will be disabled if a master -token was configured and created. - -Once the ACL system is bootstrapped, ACL tokens can be managed through the -[ACL API](/consul/api-docs/acl). - -#### Create an Agent Token - -After the servers are restarted above, you will see new errors in the logs of the Consul -servers related to permission denied errors: - -```log -2017/07/08 23:38:24 [WARN] agent: Node info update blocked by ACLs -2017/07/08 23:38:44 [WARN] agent: Coordinate update blocked by ACLs -``` - -These errors are because the agent doesn't yet have a properly configured -[`acl_agent_token`](/consul/docs/agent/config/config-files#acl_agent_token) that it can use for its -own internal operations like updating its node information in the catalog and performing -[anti-entropy](/consul/docs/architecture/anti-entropy) syncing. We can create a token using the -ACL API, and the ACL master token we set in the previous step: - -```shell-session -$ curl \ - --request PUT \ - --header "X-Consul-Token: b1gs33cr3t" \ - --data \ -'{ - "Name": "Agent Token", - "Type": "client", - "Rules": "node \"\" { policy = \"write\" } service \"\" { policy = \"read\" }" -}' http://127.0.0.1:8500/v1/acl/create - -{"ID":"fe3b8d40-0ee0-8783-6cc2-ab1aa9bb16c1"} -``` - -The returned value is the newly-created token. We can now add this to our Consul server -configuration and restart the servers once more to apply it: - -```json -{ - "acl_datacenter": "dc1", - "acl_master_token": "b1gs33cr3t", - "acl_default_policy": "deny", - "acl_down_policy": "extend-cache", - "acl_agent_token": "fe3b8d40-0ee0-8783-6cc2-ab1aa9bb16c1" -} -``` - -In Consul 0.9.1 and later you can also introduce the agent token using an API, -so it doesn't need to be set in the configuration file: - -```shell-session -$ curl \ - --request PUT \ - --header "X-Consul-Token: b1gs33cr3t" \ - --data \ -'{ - "Token": "fe3b8d40-0ee0-8783-6cc2-ab1aa9bb16c1" -}' http://127.0.0.1:8500/v1/agent/token/acl_agent_token -``` - -With that ACL agent token set, the servers will be able to sync themselves with the -catalog: - -```log -2017/07/08 23:42:59 [INFO] agent: Synced node info -``` - -See the [ACL Agent Token](#acl-agent-token) section for more details. - -#### Enable ACLs on the Consul Clients - -Since ACL enforcement also occurs on the Consul clients, we need to also restart them -with a configuration file that enables ACLs: - -```json -{ - "acl_datacenter": "dc1", - "acl_down_policy": "extend-cache", - "acl_agent_token": "fe3b8d40-0ee0-8783-6cc2-ab1aa9bb16c1" -} -``` - -Similar to the previous example, in Consul 0.9.1 and later you can also introduce the -agent token using an API, so it doesn't need to be set in the configuration file: - -```shell-session -$ curl \ - --request PUT \ - --header "X-Consul-Token: b1gs33cr3t" \ - --data \ -'{ - "Token": "fe3b8d40-0ee0-8783-6cc2-ab1aa9bb16c1" -}' http://127.0.0.1:8500/v1/agent/token/acl_agent_token -``` - -We used the same ACL agent token that we created for the servers, which will work since -it was not specific to any node or set of service prefixes. In a more locked-down -environment it is recommended that each client get an ACL agent token with `node` write -privileges for just its own node name prefix, and `service` read privileges for just the -service prefixes expected to be registered on that client. - -[Anti-entropy](/consul/docs/architecture/anti-entropy) syncing requires the ACL agent token -to have `service` read privileges for all services that may be registered with the agent, -so generally an empty `service` prefix can be used, as shown in the example. - -Clients will report similar permission denied errors until they are restarted with an ACL -agent token. - -#### Set an Anonymous Policy (Optional) - -At this point ACLs are bootstrapped with ACL agent tokens configured, but there are no -other policies set up. Even basic operations like `consul members` will be restricted -by the ACL default policy of "deny": - -```shell-session -$ consul members -``` - -We don't get an error since the ACL has filtered what we see, and we aren't allowed to -see any nodes by default. - -If we supply the token we created above we will be able to see a listing of nodes because -it has write privileges to an empty `node` prefix, meaning it has access to all nodes: - -```shell-session -$ CONSUL_HTTP_TOKEN=fe3b8d40-0ee0-8783-6cc2-ab1aa9bb16c1 consul members -Node Address Status Type Build Protocol DC -node-1 127.0.0.1:8301 alive server 0.9.0dev 2 dc1 -node-2 127.0.0.2:8301 alive client 0.9.0dev 2 dc1 -``` - -It's pretty common in many environments to allow listing of all nodes, even without a -token. The policies associated with the special anonymous token can be updated to -configure Consul's behavior when no token is supplied. The anonymous token is managed -like any other ACL token, except that `anonymous` is used for the ID. In this example -we will give the anonymous token read privileges for all nodes: - -```shell-session -$ curl \ - --request PUT \ - --header "X-Consul-Token: b1gs33cr3t" \ - --data \ -'{ - "ID": "anonymous", - "Type": "client", - "Rules": "node \"\" { policy = \"read\" }" -}' http://127.0.0.1:8500/v1/acl/update - -{"ID":"anonymous"} -``` - -The anonymous token is implicitly used if no token is supplied, so now we can run -`consul members` without supplying a token and we will be able to see the nodes: - -```shell-session -$ consul members -Node Address Status Type Build Protocol DC -node-1 127.0.0.1:8301 alive server 0.9.0dev 2 dc1 -node-2 127.0.0.2:8301 alive client 0.9.0dev 2 dc1 -``` - -The anonymous token is also used for DNS lookups since there's no way to pass a -token as part of a DNS request. Here's an example lookup for the "consul" service: - -```shell-session -$ dig @127.0.0.1 -p 8600 consul.service.consul - -; <<>> DiG 9.8.3-P1 <<>> @127.0.0.1 -p 8600 consul.service.consul -; (1 server found) -;; global options: +cmd -;; Got answer: -;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 9648 -;; flags: qr aa rd; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 0 -;; WARNING: recursion requested but not available - -;; QUESTION SECTION: -;consul.service.consul. IN A - -;; AUTHORITY SECTION: -consul. 0 IN SOA ns.consul. postmaster.consul. 1499584110 3600 600 86400 0 - -;; Query time: 2 msec -;; SERVER: 127.0.0.1#8600(127.0.0.1) -;; WHEN: Sun Jul 9 00:08:30 2017 -;; MSG SIZE rcvd: 89 -``` - -Now we get an `NXDOMAIN` error because the anonymous token doesn't have access to the -"consul" service. Let's add that to the anonymous token's policy: - -```shell-session -$ curl \ - --request PUT \ - --header "X-Consul-Token: b1gs33cr3t" \ - --data \ -'{ - "ID": "anonymous", - "Type": "client", - "Rules": "node \"\" { policy = \"read\" } service \"consul\" { policy = \"read\" }" -}' http://127.0.0.1:8500/v1/acl/update - -{"ID":"anonymous"} -``` - -With that new policy in place, the DNS lookup will succeed: - -```shell-session -$ dig @127.0.0.1 -p 8600 consul.service.consul - -; <<>> DiG 9.8.3-P1 <<>> @127.0.0.1 -p 8600 consul.service.consul -; (1 server found) -;; global options: +cmd -;; Got answer: -;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 46006 -;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0 -;; WARNING: recursion requested but not available - -;; QUESTION SECTION: -;consul.service.consul. IN A - -;; ANSWER SECTION: -consul.service.consul. 0 IN A 127.0.0.1 - -;; Query time: 0 msec -;; SERVER: 127.0.0.1#8600(127.0.0.1) -;; WHEN: Sun Jul 9 00:11:14 2017 -;; MSG SIZE rcvd: 55 -``` - -The next section shows an alternative to the anonymous token. - -#### Set Agent-Specific Default Tokens (Optional) - -An alternative to the anonymous token is the [`acl_token`](/consul/docs/agent/config/config-files#acl_token) -configuration item. When a request is made to a particular Consul agent and no token is -supplied, the [`acl_token`](/consul/docs/agent/config/config-files#acl_token) will be used for the token, -instead of being left empty which would normally invoke the anonymous token. - -In Consul 0.9.1 and later, the agent ACL tokens can be introduced or updated via the -[/v1/agent/token API](/consul/api-docs/agent#update-acl-tokens). - -This behaves very similarly to the anonymous token, but can be configured differently on each -agent, if desired. For example, this allows more fine grained control of what DNS requests a -given agent can service, or can give the agent read access to some key-value store prefixes by -default. - -If using [`acl_token`](/consul/docs/agent/config/config-files#acl_token), then it's likely the anonymous -token will have a more restrictive policy than shown in the examples here. - -#### Create Tokens for UI Use (Optional) - -If you utilize the Consul UI with a restrictive ACL policy, as above, the UI will -not function fully using the anonymous ACL token. It is recommended -that a UI-specific ACL token is used, which can be set in the UI during the -web browser session to authenticate the interface. - -```shell-session -$ curl \ - --request PUT \ - --header "X-Consul-Token: b1gs33cr3t" \ - --data \ -'{ - "Name": "UI Token", - "Type": "client", - "Rules": "key \"\" { policy = \"write\" } node \"\" { policy = \"read\" } service \"\" { policy = \"read\" }" -}' http://127.0.0.1:8500/v1/acl/create -{"ID":"d0a9f330-2f9d-0a8c-d2af-1e9ceda354e6"} -``` - -The token can then be set on the "settings" page of the UI. - -#### Next Steps - -The examples above configure a basic ACL environment with the ability to see all nodes -by default, and limited access to just the "consul" service. The [ACL API](/consul/api-docs/acl) -can be used to create tokens for applications specific to their intended use, and to create -more specific ACL agent tokens for each agent's expected role. - -Also see [HashiCorp's Vault](/vault/docs/secrets/consul), which -has an integration with Consul that allows it to generate ACL tokens on the fly and to manage -their lifetimes. - -## Rule Specification - -A core part of the ACL system is the rule language which is used to describe the policy -that must be enforced. Most of the ACL rules are prefix-based, allowing operators to -define different namespaces within Consul's resource areas like the catalog and key/value -store, in order to delegate responsibility for these namespaces. Policies can have several -dispositions: - -- `read`: allow the resource to be read but not modified -- `write`: allow the resource to be read and modified -- `deny`: do not allow the resource to be read or modified - -With prefix-based rules, the most specific prefix match determines the action. This -allows for flexible rules like an empty prefix to allow read-only access to all -resources, along with some specific prefixes that allow write access or that are -denied all access. - -We make use of the -[HashiCorp Configuration Language (HCL)](https://github.com/hashicorp/hcl/) to specify -rules. This language is human readable and interoperable with JSON making it easy to -machine-generate. Rules can make use of one or more policies. - -Specification in the HCL format looks like: - -```hcl -# These control access to the key/value store. -key "" { - policy = "read" -} -key "foo/" { - policy = "write" -} -key "foo/private/" { - policy = "deny" -} - -# This controls access to cluster-wide Consul operator information. -operator = "read" -``` - -This is equivalent to the following JSON input: - -```json -{ - "key": { - "": { - "policy": "read" - }, - "foo/": { - "policy": "write" - }, - "foo/private/": { - "policy": "deny" - } - }, - "operator": "read" -} -``` - -The [ACL API](/consul/api-docs/acl) allows either HCL or JSON to be used to define the content -of the rules section. - -Here's a sample request using the HCL form: - -```shell-session -$ curl \ - --request PUT \ - --header "X-Consul-Token: " \ - --data \ -'{ - "Name": "my-app-token", - "Type": "client", - "Rules": "key \"\" { policy = \"read\" } key \"foo/\" { policy = \"write\" } key \"foo/private/\" { policy = \"deny\" } operator = \"read\"" -}' http://127.0.0.1:8500/v1/acl/create -``` - -Here's an equivalent request using the JSON form: - -```shell-session -$ curl \ - --request PUT \ - --header "X-Consul-Token: " \ - --data \ -'{ - "Name": "my-app-token", - "Type": "client", - "Rules": "{\"key\":{\"\":{\"policy\":\"read\"},\"foo/\":{\"policy\":\"write\"},\"foo/private\":{\"policy\":\"deny\"}},\"operator\":\"read\"}" -}' http://127.0.0.1:8500/v1/acl/create -``` - -On success, the token ID is returned: - -```json -{ - "ID": "adf4238a-882b-9ddc-4a9d-5b6758e4159e" -} -``` - -This token ID can then be passed into Consul's HTTP APIs via the `token` -query string parameter, or the `X-Consul-Token` request header, or Authorization -Bearer token header, or Consul's CLI commands via the `token` argument, -or the `CONSUL_HTTP_TOKEN` environment variable. - -#### Agent Rules - -The `agent` policy controls access to the utility operations in the [Agent API](/consul/api-docs/agent), -such as join and leave. All of the catalog-related operations are covered by the [`node`](#node-rules) -and [`service`](#service-rules) policies instead. - -Agent rules look like this: - -```hcl -agent "" { - policy = "read" -} -agent "foo" { - policy = "write" -} -agent "bar" { - policy = "deny" -} -``` - -Agent rules are keyed by the node name prefix they apply to, using the longest prefix match rule. In -the example above, the rules allow read-only access to any node name with the empty prefix, allow -read-write access to any node name that starts with "foo", and deny all access to any node name that -starts with "bar". - -Since [Agent API](/consul/api-docs/agent) utility operations may be required before an agent is joined to -a cluster, or during an outage of the Consul servers or ACL datacenter, a special token may be -configured with [`acl_agent_master_token`](/consul/docs/agent/config/config-files#acl_agent_master_token) to allow -write access to these operations even if no ACL resolution capability is available. - -#### Event Rules - -The `event` policy controls access to event operations in the [Event API](/consul/api-docs/event), such as -firing events and listing events. - -Event rules look like this: - -```hcl -event "" { - policy = "read" -} -event "deploy" { - policy = "write" -} -``` - -Event rules are keyed by the event name prefix they apply to, using the longest prefix match rule. -In the example above, the rules allow read-only access to any event, and firing of any event that -starts with "deploy". - -The [`consul exec`](/consul/commands/exec) command uses events with the "\_rexec" prefix during -operation, so to enable this feature in a Consul environment with ACLs enabled, you will need to -give agents a token with access to this event prefix, in addition to configuring -[`disable_remote_exec`](/consul/docs/agent/config/config-files#disable_remote_exec) to `false`. - -#### Key/Value Rules - -The `key` policy controls access to key/value store operations in the [KV API](/consul/api-docs/kv). Key -rules look like this: - -```hcl -key "" { - policy = "read" -} -key "foo" { - policy = "write" -} -key "bar" { - policy = "deny" -} -``` - -Key rules are keyed by the key name prefix they apply to, using the longest prefix match rule. In -the example above, the rules allow read-only access to any key name with the empty prefix, allow -read-write access to any key name that starts with "foo", and deny all access to any key name that -starts with "bar". - -#### List Policy for Keys - -Consul 1.0 introduces a new `list` policy for keys that is only enforced when opted in via the boolean config param "acl_enable_key_list_policy". -`list` controls access to recursively list entries and keys, and enables more fine grained policies. With "acl_enable_key_list_policy", -recursive reads via [the KV API](/consul/api-docs/kv#recurse) with an invalid token result in a 403. Example: - -```hcl -key "" { - policy = "deny" -} - -key "bar" { - policy = "list" -} - -key "baz" { - policy = "read" -} -``` - -In the example above, the rules allow reading the key "baz", and only allow recursive reads on the prefix "bar". - -A token with `write` access on a prefix also has `list` access. A token with `list` access on a prefix also has `read` access on all its suffixes. - -#### Sentinel Integration - -Consul Enterprise supports additional optional fields for key write policies for -[Sentinel](https://docs.hashicorp.com/sentinel/consul) integration. An example key rule with a -Sentinel code policy looks like this: - -```hcl -key "foo" { - policy = "write" - sentinel { - code = < 0.6.3 | -| ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| Create static query without `Name` | The ACL Token used to create the prepared query is checked to make sure it can access the service being queried. This token is captured as the `Token` to use when executing the prepared query. | No ACL policies are used as long as no `Name` is defined. No `Token` is captured by default unless specifically supplied by the client when creating the query. | -| Create static query with `Name` | The ACL Token used to create the prepared query is checked to make sure it can access the service being queried. This token is captured as the `Token` to use when executing the prepared query. | The client token's `query` ACL policy is used to determine if the client is allowed to register a query for the given `Name`. No `Token` is captured by default unless specifically supplied by the client when creating the query. | -| Manage static query without `Name` | The ACL Token used to create the query, or a management token must be supplied in order to perform these operations. | Any client with the ID of the query can perform these operations. | -| Manage static query with a `Name` | The ACL token used to create the query, or a management token must be supplied in order to perform these operations. | Similar to create, the client token's `query` ACL policy is used to determine if these operations are allowed. | -| List queries | A management token is required to list any queries. | The client token's `query` ACL policy is used to determine which queries they can see. Only management tokens can see prepared queries without `Name`. | -| Execute query | Since a `Token` is always captured when a query is created, that is used to check access to the service being queried. Any token supplied by the client is ignored. | The captured token, client's token, or anonymous token is used to filter the results, as described above. | - -#### Service Rules - -The `service` policy controls service-level registration and read access to the [Catalog API](/consul/api-docs/catalog) -and service discovery with the [Health API](/consul/api-docs/health). - -Service rules look like this: - -```hcl -service "" { - policy = "read" -} -service "app" { - policy = "write" -} -service "admin" { - policy = "deny" -} -``` - -Service rules are keyed by the service name prefix they apply to, using the longest prefix match rule. In -the example above, the rules allow read-only access to any service name with the empty prefix, allow -read-write access to any service name that starts with "app", and deny all access to any service name that -starts with "admin". - -Consul's DNS interface is affected by restrictions on service rules. If the -[`acl_token`](/consul/docs/agent/config/config-files#acl_token) used by the agent does not have "read" access to a -given service, then the DNS interface will return no records when queried for it. - -When reading from the catalog or retrieving information from the health endpoints, service rules are -used to filter the results of the query. - -Service rules come into play when using the [Agent API](/consul/api-docs/agent) to register services or -checks. The agent will check tokens locally as a service or check is registered, and Consul also -performs periodic [anti-entropy](/consul/docs/architecture/anti-entropy) syncs, which may require an -ACL token to complete. To accommodate this, Consul provides two methods of configuring ACL tokens -to use for registration events: - -1. Using the [acl_token](/consul/docs/agent/config/config-files#acl_token) configuration - directive. This allows a single token to be configured globally and used - during all service and check registration operations. -2. Providing an ACL token with service and check definitions at registration - time. This allows for greater flexibility and enables the use of multiple - tokens on the same agent. Examples of what this looks like are available for - both [services](/consul/docs/discovery/services) and - [checks](/consul/docs/discovery/checks). Tokens may also be passed to the [HTTP - API](/consul/api-docs) for operations that require them. **Note:** all tokens - passed to an agent are persisted on local disk to allow recovery from - restarts. See [`-data-dir` flag - documentation](/consul/docs/agent/config/config-files#acl_token) for notes on securing - access. - -In addition to ACLs, in Consul 0.9.0 and later, the agent must be configured with -[`enable_script_checks`](/consul/docs/agent/config/config-files#enable_script_checks) or -[`enable_local_script_checks`](/consul/docs/agent/config/config-files#enable_local_script_checks) -set to `true` in order to enable script checks. - -#### Session Rules - -The `session` policy controls access to [Session API](/consul/api-docs/session) operations. - -Session rules look like this: - -```hcl -session "" { - policy = "read" -} -session "app" { - policy = "write" -} -session "admin" { - policy = "deny" -} -``` - -Session rules are keyed by the node name prefix they apply to, using the longest prefix match rule. In -the example above, the rules allow read-only access to sessions on node name with the empty prefix, allow -creating sessions on any node name that starts with "app", and deny all access to any sessions on a node -name that starts with "admin". - -## Advanced Topics - -#### Outages and ACL Replication ((#replication)) - -The Consul ACL system is designed with flexible rules to accommodate for an outage -of the [`acl_datacenter`](/consul/docs/agent/config/config-files#acl_datacenter) or networking -issues preventing access to it. In this case, it may be impossible for -agents in non-authoritative datacenters to resolve tokens. Consul provides -a number of configurable [`acl_down_policy`](/consul/docs/agent/config/config-files#acl_down_policy) -choices to tune behavior. It is possible to deny or permit all actions or to ignore -cache TTLs and enter a fail-safe mode. The default is to ignore cache TTLs -for any previously resolved tokens and to deny any uncached tokens. - -Consul 0.7 added an ACL Replication capability that can allow non-authoritative -datacenter agents to resolve even uncached tokens. This is enabled by setting an -[`acl_replication_token`](/consul/docs/agent/config/config-files#acl_replication_token) in the -configuration on the servers in the non-authoritative datacenters. In Consul -0.9.1 and later you can enable ACL replication using -[`enable_acl_replication`](/consul/docs/agent/config/config-files#enable_acl_replication) and -then set the token later using the -[agent token API](/consul/api-docs/agent#update-acl-tokens) on each server. This can -also be used to rotate the token without restarting the Consul servers. - -With replication enabled, the servers will maintain a replica of the authoritative -datacenter's full set of ACLs on the non-authoritative servers. The ACL replication -token needs to be a valid ACL token with management privileges, it can also be the -same as the master ACL token. - -Replication occurs with a background process that looks for new ACLs approximately -every 30 seconds. Replicated changes are written at a rate that's throttled to -100 updates/second, so it may take several minutes to perform the initial sync of -a large set of ACLs. - -If there's a partition or other outage affecting the authoritative datacenter, -and the [`acl_down_policy`](/consul/docs/agent/config/config-files#acl_down_policy) -is set to "extend-cache", tokens will be resolved during the outage using the -replicated set of ACLs. An [ACL replication status](/consul/api-docs/acl#check-acl-replication) -endpoint is available to monitor the health of the replication process. -Also note that in recent versions of Consul (greater than 1.2.0), using -`acl_down_policy = "async-cache"` refreshes token asynchronously when an ACL is -already cached and is expired while similar semantics than "extend-cache". -It allows to avoid having issues when connectivity with the authoritative is not completely -broken, but very slow. - -Locally-resolved ACLs will be cached using the [`acl_ttl`](/consul/docs/agent/config/config-files#acl_ttl) -setting of the non-authoritative datacenter, so these entries may persist in the -cache for up to the TTL, even after the authoritative datacenter comes back online. - -ACL replication can also be used to migrate ACLs from one datacenter to another -using a process like this: - -1. Enable ACL replication in all datacenters to allow continuation of service - during the migration, and to populate the target datacenter. Verify replication - is healthy and caught up to the current ACL index in the target datacenter - using the [ACL replication status](/consul/api-docs/acl#check-acl-replication) - endpoint. -2. Turn down the old authoritative datacenter servers. -3. Rolling restart the agents in the target datacenter and change the - `acl_datacenter` servers to itself. This will automatically turn off - replication and will enable the datacenter to start acting as the authoritative - datacenter, using its replicated ACLs from before. -4. Rolling restart the agents in other datacenters and change their `acl_datacenter` - configuration to the target datacenter. - -#### Complete ACL Coverage in Consul 0.8 ((#version_8_acls)) - -Consul 0.8 added many more ACL policy types and brought ACL enforcement to Consul -agents for the first time. To ease the transition to Consul 0.8 for existing ACL -users, there's a configuration option to disable these new features. To disable -support for these new ACLs, set the -[`acl_enforce_version_8`](/consul/docs/agent/config/config-files#acl_enforce_version_8) configuration -option to `false` on Consul clients and servers. - -Here's a summary of the new features: - -- Agents now check [`node`](#node-rules) and [`service`](#service-rules) ACL policies - for catalog-related operations in `/v1/agent` endpoints, such as service and check - registration and health check updates. -- Agents enforce a new [`agent`](#agent-rules) ACL policy for utility operations in - `/v1/agent` endpoints, such as joins and leaves. -- A new [`node`](#node-rules) ACL policy is enforced throughout Consul, providing a - mechanism to restrict registration and discovery of nodes by name. This also applies - to service discovery, so provides an additional dimension for controlling access to - services. -- A new [`session`](#session-rules) ACL policy controls the ability to create session - objects by node name. -- Anonymous prepared queries (non-templates without a `Name`) now require a valid - session, which ties their creation to the new [`session`](#session-rules) ACL policy. -- The existing [`event`](#event-rules) ACL policy has been applied to the - `/v1/event/list` endpoint. - -Two new configuration options are used once version 8 ACLs are enabled: - -- [`acl_agent_master_token`](/consul/docs/agent/config/config-files#acl_agent_master_token) is used as - a special access token that has `agent` ACL policy `write` privileges on each agent where - it is configured, as well as `node` ACL policy `read` privileges for all nodes. This token - should only be used by operators during outages when Consul servers aren't available to - resolve ACL tokens. Applications should use regular ACL tokens during normal operation. -- [`acl_agent_token`](/consul/docs/agent/config/config-files#acl_agent_token) is used internally by - Consul agents to perform operations to the service catalog when registering themselves - or sending network coordinates to the servers. This token must at least have `node` ACL - policy `write` access to the node name it will register as in order to register any - node-level information like metadata or tagged addresses. - -Since clients now resolve ACLs locally, the [`acl_down_policy`](/consul/docs/agent/config/config-files#acl_down_policy) -now applies to Consul clients as well as Consul servers. This will determine what the -client will do in the event that the servers are down. - -Consul clients must have [`acl_datacenter`](/consul/docs/agent/config/config-files#acl_datacenter) configured -in order to enable agent-level ACL features. If this is set, the agents will contact the Consul -servers to determine if ACLs are enabled at the cluster level. If they detect that ACLs are not -enabled, they will check at most every 2 minutes to see if they have become enabled, and will -start enforcing ACLs automatically. If an agent has an `acl_datacenter` defined, operators will -need to use the [`acl_agent_master_token`](/consul/docs/agent/config/config-files#acl_agent_master_token) to -perform agent-level operations if the Consul servers aren't present (such as for a manual join -to the cluster), unless the [`acl_down_policy`](/consul/docs/agent/config/config-files#acl_down_policy) on the -agent is set to "allow". - -Non-server agents do not need to have the -[`acl_master_token`](/consul/docs/agent/config/config-files#acl_master_token) configured; it is not -used by agents in any way. diff --git a/website/content/docs/security/acl/acl-migrate-tokens.mdx b/website/content/docs/security/acl/acl-migrate-tokens.mdx deleted file mode 100644 index 33baf4eff..000000000 --- a/website/content/docs/security/acl/acl-migrate-tokens.mdx +++ /dev/null @@ -1,393 +0,0 @@ ---- -layout: docs -page_title: Legacy ACL Token Migration -description: >- - Migrate legacy tokens when updating to Consul 1.4.0+ from earlier versions to use the current ACL system. Learn about the migration process, how to update tokens, and examples for creating policies. ---- - -# ACL Token Migration - -Consul 1.4.0 introduces a new ACL system with improvements for the security and -management of ACL tokens and policies. This guide documents how to upgrade -existing (now called "legacy") tokens after upgrading to 1.4.0. - -Since the policy syntax changed to be more precise and flexible to manage, it's -necessary to manually translate old tokens into new ones to take advantage of -the new ACL system features. Tooling is provided to help automate this and this -guide describes the overall process. - -~> **Note**: Before starting the token migration process all Consul agents, servers -and clients, must be running at least version 1.4.0. Additionally, you -must ensure the cluster is in a healthy state including a functioning leader. Once -the leader has determined that all servers in the cluster are capable of using the -new ACL system, the leader will transition itself. Then, the other servers will -transition themselves to the new system, followed by the client agents. You can -use `consul info` to investigate the cluster health. - -Consul 1.4.0 retains full support for "legacy" ACL tokens so upgrades -from Consul 1.3.0 are safe. Existing tokens will continue to work in the same -way for at least two "major" releases (1.5.x, 1.6.x, etc; note HashiCorp does -not use SemVer for our products). - -This document will briefly describes the [high-level migration process](#migration-process) and provides some [specific examples](#migration-examples) of migration strategies. - -## Migration Process - -While "legacy" tokens will continue to work for several major releases, it's -advisable to plan on migrating existing tokens as soon as is convenient. -Migrating also enables using the new policy management improvements, stricter -policy syntax rules and other features of the new system without -re-issuing all the secrets in use. - -The high-level process for migrating a legacy token is as follows: - -1. Create a new policy or policies that grant the required access -2. Update the existing token to use those policies - -### Prerequisites - -This process assumes that the 1.4.0 upgrade is complete including all legacy -ACLs having their accessor IDs populated. This might take up to several minutes -after the servers upgrade in the primary datacenter. You can tell if this is the -case by using `consul acl token list` and checking that no tokens exist with a -blank `AccessorID`. - -In addition, it is assumed that all clients that might _create_ ACL tokens (e.g. -Vault's Consul secrets engine) have been updated to use the [new ACL -APIs](/consul/api-docs/acl/tokens). - -Specifically if you are using Vault's Consul secrets engine you need to be -running Vault 1.0.0 or higher, _and_ you must update all roles defined in Vault -to specify a list of policy names rather than an inline policy (which causes -Vault to use the legacy API). - -~> **Note:** if you have systems still creating "legacy" tokens with the old -APIs, the migration steps below will still work, however you'll have to keep -re-running them until nothing is creating legacy tokens to ensure all tokens are -migrated. - -### Creating Policies - -There are a range of different strategies for creating new policies from existing -tokens. Two high-level strategies are described here although others or a -mixture of these may be most appropriate depending on the ACL tokens you already -have. - -#### Strategy 1: Simple Policy Mapping - -The simplest and most automatic strategy is to create one new policy for every -existing token. This is easy to automate, but may result in a lot of policies -with exactly the same rules and with non-human-readable names which will make -managing policies harder. This approach can be accomplished using the [`consul acl policy create`](/consul/commands/acl/policy/create) command with -`-from-token` option. - -| Pros | Cons | -| ------------------------ | ------------------------------------------- | -| ✅ Simple | ❌ May leave many duplicated policies | -| ✅ Easy to automate | ❌ Policy names not human-readable | - -A detailed example of using this approach is [given -below](#simple-policy-mapping). - -#### Strategy 2: Combining Policies - -This strategy takes a more manual approach to create a more manageable set of -policies. There are a spectrum of options for how to do this which tradeoff -increasing human involvement for increasing clarity and re-usability of the -resulting policies. - -For example you could use hashes of the policy rules to de-duplicate identical -token policies automatically, however naming them something meaningful for -humans would likely still need manual intervention. - -Toward the other end of the spectrum it might be beneficial for security to -translate prefix matches into exact matches. This however requires the operator -knowing that clients using the token really doesn't rely on the prefix matching -semantics of the old ACL system. - -To assist with this approach, there is a CLI tool and corresponding API that can -translate a legacy ACL token's rules into a new ACL policy that is exactly -equivalent. See [`consul acl translate-rules`](/consul/commands/acl/translate-rules). - -| Pros | Cons | -| ------------------------------------------------- | ------------------------------------------------------------------ | -| ✅ Clearer, more manageable policies | ❌ Requires more manual effort | -| ✅ Policies can be re-used by new ACL tokens | ❌ May take longer for large or complex existing policy sets | - -A detailed example of using this approach is [given below](#combining-policies). - -### Updating Existing Tokens - -Once you have created one or more policies that adequately express the rules -needed for a legacy token, you can update the token via the CLI or API to use -those policies. - -After updating, the token is no longer considered "legacy" and will have all the -properties of a new token, however it keeps its `SecretID` (the secret part of -the token used in API calls) so clients already using that token will continue -to work. It is assumed that the policies you attach continue to grant the -necessary access for existing clients; this is up to the operator to ensure. - -#### Update via API - -Use the [`PUT /v1/acl/token/:AccessorID`](/consul/api-docs/acl/tokens#update-a-token) -endpoint. Specifically, ensure that the `Rules` field is omitted or empty. Empty -`Rules` indicates that this is now treated as a new token. - -#### Update via CLI - -Use the [`consul acl token update`](/consul/commands/acl/token/update) -command to update the token. Specifically you need to use `-upgrade-legacy` -which will ensure that legacy rules are removed as well as the new policies -added. - -## Migration Examples - -Below are two detailed examples of the two high-level strategies for creating -policies discussed above. It should be noted these are intended to clarify the -concrete steps you might take. **We don't recommend you perform production -migrations with ad-hoc terminal commands**. Combining these or something similar -into a script might be appropriate. - -### Simple Policy Mapping - -This strategy uses the CLI to create a new policy for every existing legacy -token with exactly equivalent rules. It's easy to automate and clients will see -no change in behavior for their tokens, but it does leave you with a lot of -potentially identical policies to manage or clean up later. - -#### Create Policies - -You can get the AccessorID of every legacy token from the API. For example, -using `curl` and `jq` in bash: - -```shell-session -$ LEGACY_IDS=$(curl --silent --header "X-Consul-Token: $CONSUL_HTTP_TOKEN" \ - 'localhost:8500/v1/acl/tokens' | jq --raw-output '.[] | select (.Legacy) | .AccessorID') -$ echo "$LEGACY_IDS" -621cbd12-dde7-de06-9be0-e28d067b5b7f -65cecc86-eb5b-ced5-92dc-f861cf7636fe -ba464aa8-d857-3d26-472c-4d49c3bdae72 -``` - -To create a policy for each one we can use something like: - -```shell -for id in $LEGACY_IDS; do \ - consul acl policy create -name "migrated-$id" -from-token $id \ - -description "Migrated from legacy ACL token"; \ -done -``` - -Each policy now has an identical set of rules to the original token. You can -inspect these: - -```shell-session -$ consul acl policy read -name migrated-621cbd12-dde7-de06-9be0-e28d067b5b7f -ID: 573d84bd-8b08-3061-e391-d2602e1b4947 -Name: migrated-621cbd12-dde7-de06-9be0-e28d067b5b7f -Description: Migrated from legacy ACL token -Datacenters: -Rules: -service_prefix "" { - policy = "write" -} -``` - -Notice how the policy here is `service_prefix` and not `service` since the old -ACL syntax was an implicit prefix match. This ensures any clients relying on -prefix matching behavior will still work. - -#### Update Tokens - -With the policies created as above, we can automatically upgrade all legacy -tokens. - -```shell -for id in $LEGACY_IDS; do \ - consul acl token update -id $id -policy-name "migrated-$id" -upgrade-legacy; \ -done -``` - -The update is now complete, all legacy tokens are now new tokens with identical -secrets and enforcement rules. - -### Combining Policies - -This strategy has more manual elements but results in a cleaner and more -manageable set of policies than the fully automatic solutions. Note that this is -**just an example** to illustrate a few ways you may choose to merge or -manipulate policies. - -#### Find All Unique Policies - -You can get the AccessorID of every legacy token from the API. For example, -using `curl` and `jq` in bash: - -```shell-session -$ LEGACY_IDS=$(curl --silent --header "X-Consul-Token: $CONSUL_HTTP_TOKEN" \ - 'localhost:8500/v1/acl/tokens' | jq --raw-output '.[] | select (.Legacy) | .AccessorID') -$ echo "$LEGACY_IDS" -8b65fdf9-303e-0894-9f87-e71b3273600c -d9deb39b-1b30-e100-b9c5-04aba3f593a1 -f2bce42e-cdcc-848d-28ca-cfd0556a22e3 -``` - -Now we want to read the actual policy for each legacy token and de-duplicate -them. We can use the `translate-rules` helper sub-command which will read the -token's policy and return a new ACL policy that is exactly equivalent. - -```shell-session -$ for id in $LEGACY_IDS; do \ - echo "Policy for $id:" - consul acl translate-rules -token-accessor "$id"; \ -done -Policy for 8b65fdf9-303e-0894-9f87-e71b3273600c: -service_prefix "bar" { - policy = "write" -} -Policy for d9deb39b-1b30-e100-b9c5-04aba3f593a1: -service_prefix "foo" { - policy = "write" -} -Policy for f2bce42e-cdcc-848d-28ca-cfd0556a22e3: -service_prefix "bar" { - policy = "write" -} -``` - -Notice that two policies are the same and one different. - -We can change the loop above to take a hash of this policy definition to -de-duplicate the policies into a set of files locally. This example uses command -available on macOS but equivalents for other platforms should be easy to find. - -```shell-session -$ mkdir policies -$ for id in $LEGACY_IDS; do \ - # Fetch the equivalent new policy rules based on the legacy token rules - NEW_POLICY=$(consul acl translate-rules -token-accessor "$id"); \ - # Sha1 hash the rules - HASH=$(echo -n "$NEW_POLICY" | shasum | awk '{ print $1 }'); \ - # Write rules to a policy file named with the hash to de-duplicated - echo "$NEW_POLICY" > policies/$HASH.hcl; \ -done -$ tree policies -policies -├── 024ce11f26f59436c518fb31f0999d1400485c17.hcl -└── 501b787c9444fbd62f346ab257eeb27197be2444.hcl -``` - -#### Cleaning Up Policies - -You can now manually inspect and potentially edit these policies. For example we -could rename them according to their intended use. In this case we maintain the -hash as it will allow us to match tokens to policies later. - -```shell-session -$ cat policies/024ce11f26f59436c518fb31f0999d1400485c17.hcl -service_prefix "bar" { - policy = "write" -} -$ # Add human-readable suffix to the file name so policies end up clearly named -$ mv policies/024ce11f26f59436c518fb31f0999d1400485c17.hcl \ - policies/024ce11f26f59436c518fb31f0999d1400485c17-bar-service.hcl -``` - -You might also choose to tighten up the rules, for example if you know you never -rely on prefix-matching the service name `foo` you might choose to modify the -policy to use exact match. - -```shell-session -$ cat policies/501b787c9444fbd62f346ab257eeb27197be2444.hcl -service_prefix "foo" { - policy = "write" -} -$ echo 'service "foo" { policy = "write" }' > policies/501b787c9444fbd62f346ab257eeb27197be2444.hcl -$ # Add human-readable suffix to the file name so policies end up clearly named -$ mv policies/501b787c9444fbd62f346ab257eeb27197be2444.hcl \ - policies/501b787c9444fbd62f346ab257eeb27197be2444-foo-service.hcl -``` - -#### Creating Policies - -We now have a minimal set of policies to create, with human-readable names. We -can create each one with something like the following. - -```shell-session -$ for p in $(ls policies | grep ".hcl"); do \ - # Extract the hash part of the file name - HASH=$(echo "$p" | cut -d - -f 1); \ - # Extract the name suffix without .hcl - NAME=$(echo "$p" | cut -d - -f 2- | cut -d . -f 1); \ - # Create new policy based on the rules in the file and the name we gave - consul acl policy create -name $NAME \ - -rules "@policies/$p" \ - -description "Migrated from legacy token"; \ -done -ID: da2a9f9b-4e44-13f8-e308-76ce7a8dcb21 -Name: bar-service -Description: Migrated from legacy token -Datacenters: -Rules: -service_prefix "bar" { - policy = "write" -} - -ID: 9fbded86-9140-efe4-b661-c8bd07b6c584 -Name: foo-service -Description: Migrated from legacy token -Datacenters: -Rules: -service "foo" { policy = "write" } - -``` - -#### Upgrading Tokens - -Finally we can map our existing tokens to those policies using the hash in the -policy file names. The `-upgrade-legacy` flag removes the token's legacy -embedded rules at the same time as associating them with the new policies -created from those rules. - -```shell-session -$ for id in $LEGACY_IDS; do \ - NEW_POLICY=$(consul acl translate-rules -token-accessor "$id"); \ - HASH=$(echo -n "$NEW_POLICY" | shasum | awk '{ print $1 }'); \ - # Lookup the hash->new policy mapping from the policy file names - POLICY_FILE=$(ls policies | grep "^$HASH"); \ - POLICY_NAME=$(echo "$POLICY_FILE" | cut -d - -f 2- | cut -d . -f 1); \ - echo "==> Mapping token $id to policy $POLICY_NAME"; \ - consul acl token update -id $id -policy-name $POLICY_NAME -upgrade-legacy; \ -done -==> Mapping token 8b65fdf9-303e-0894-9f87-e71b3273600c to policy bar-service -Token updated successfully. -AccessorID: 8b65fdf9-303e-0894-9f87-e71b3273600c -SecretID: 3dbb3981-7654-733a-3475-5ce20fc5a7b9 -Description: -Local: false -Create Time: 0001-01-01 00:00:00 +0000 UTC -Policies: - da2a9f9b-4e44-13f8-e308-76ce7a8dcb21 - bar-service -==> Mapping token d9deb39b-1b30-e100-b9c5-04aba3f593a1 to policy foo-service -Token updated successfully. -AccessorID: d9deb39b-1b30-e100-b9c5-04aba3f593a1 -SecretID: 5f54733b-4c76-eb74-8781-3550c20f4969 -Description: -Local: false -Create Time: 0001-01-01 00:00:00 +0000 UTC -Policies: - 9fbded86-9140-efe4-b661-c8bd07b6c584 - foo-service -==> Mapping token f2bce42e-cdcc-848d-28ca-cfd0556a22e3 to policy bar-service -Token updated successfully. -AccessorID: f2bce42e-cdcc-848d-28ca-cfd0556a22e3 -SecretID: f3aaa3e2-2c6f-cf3c-1e86-454de728e8ab -Description: -Local: false -Create Time: 0001-01-01 00:00:00 +0000 UTC -Policies: - da2a9f9b-4e44-13f8-e308-76ce7a8dcb21 - bar-service -``` - -At this point all tokens are upgraded and can use new ACL features while -retaining the same secret clients are already using. diff --git a/website/content/docs/upgrading/instructions/upgrade-to-1-6-x.mdx b/website/content/docs/upgrading/instructions/upgrade-to-1-6-x.mdx index 8a12ca811..c39aed602 100644 --- a/website/content/docs/upgrading/instructions/upgrade-to-1-6-x.mdx +++ b/website/content/docs/upgrading/instructions/upgrade-to-1-6-x.mdx @@ -189,7 +189,7 @@ You should receive output similar to this: } ``` -**6.** Migrate your legacy ACL tokens to the new ACL system by following the instructions in our [ACL Token Migration guide](/consul/docs/security/acl/acl-migrate-tokens). +**6.** Migrate your legacy ACL tokens to the new ACL system. ~> This step _must_ be completed before upgrading to a version higher than 1.6.x. diff --git a/website/content/docs/upgrading/upgrade-specific.mdx b/website/content/docs/upgrading/upgrade-specific.mdx index f723664ce..83e5ebd9a 100644 --- a/website/content/docs/upgrading/upgrade-specific.mdx +++ b/website/content/docs/upgrading/upgrade-specific.mdx @@ -31,7 +31,7 @@ Check whether you are using a `token` query parameter by searching your Consul a $ This request used the token query parameter which is deprecated and will be removed in Consul 1.17 ``` -Deprecated authentication using the `token` query parameter: +Deprecated authentication using the `token` query parameter: ```shell-session $ curl \ @@ -410,20 +410,10 @@ The `consul acl set-agent-token master` subcommand has been replaced with ### Legacy ACL System Removal -The legacy ACL system that was deprecated in Consul 1.4.0 has been removed. +The legacy ACL system that was deprecated in Consul 1.4.0 was removed in 1.11.0. Before upgrading you should verify that nothing is still using the legacy ACL system. Complete the [Migrate Legacy ACL Tokens](https://learn.hashicorp.com/consul/day-2-agent-authentication/migrate-acl-tokens) tutorial to learn more. -Due to this removal the following endpoints no longer function: - - - [`PUT /v1/acl/create`](/consul/api-docs/acl/legacy#create-acl-token) - - [`PUT /v1/acl/update`](/consul/api-docs/acl/legacy#update-acl-token) - - [`PUT /v1/acl/destroy/`](/consul/api-docs/acl/legacy#delete-acl-token) - - [`GET /v1/acl/info/`](/consul/api-docs/acl/legacy#read-acl-token) - - [`PUT /v1/acl/clone/`](/consul/api-docs/acl/legacy#clone-acl-token) - - [`GET /v1/acl/list`](/consul/api-docs/acl/legacy#list-acls) - - [`GET,POST /v1/acl/rules/translate`](/consul/api-docs/acl#translate-rules) - ### Raft Storage Changes The underlying library used for persisting the Raft log to persistent storage @@ -786,8 +776,6 @@ as soon as possible after upgrade, as well as updating any integrations to work with the the new ACL [Token](/consul/api-docs/acl/tokens) and [Policy](/consul/api-docs/acl/policies) APIs. -More complete details on how to upgrade "legacy" tokens is available [here](/consul/docs/security/acl/acl-migrate-tokens). - ### Connect Multi-datacenter This only applies to users upgrading from an older version of Consul Enterprise to Consul Enterprise 1.4.0 (all license types). diff --git a/website/data/api-docs-nav-data.json b/website/data/api-docs-nav-data.json index 5ac07414e..fb1dd8742 100644 --- a/website/data/api-docs-nav-data.json +++ b/website/data/api-docs-nav-data.json @@ -43,10 +43,6 @@ "title": "Tokens", "path": "acl/tokens" }, - { - "title": "Legacy Tokens", - "path": "acl/legacy" - }, { "title": "Policies", "path": "acl/policies" diff --git a/website/data/commands-nav-data.json b/website/data/commands-nav-data.json index 3a3bb0609..62ed01a40 100644 --- a/website/data/commands-nav-data.json +++ b/website/data/commands-nav-data.json @@ -166,10 +166,6 @@ "path": "acl/token/update" } ] - }, - { - "title": "translate-rules", - "path": "acl/translate-rules" } ] }, diff --git a/website/data/docs-nav-data.json b/website/data/docs-nav-data.json index abf735dd8..16bf17d84 100644 --- a/website/data/docs-nav-data.json +++ b/website/data/docs-nav-data.json @@ -656,14 +656,6 @@ "title": "Rules Reference", "path": "security/acl/acl-rules" }, - { - "title": "Legacy Mode", - "path": "security/acl/acl-legacy" - }, - { - "title": "Token Migration", - "path": "security/acl/acl-migrate-tokens" - }, { "title": "ACLs in Federated Datacenters", "path": "security/acl/acl-federated-datacenters"