mirror of
https://github.com/status-im/consul.git
synced 2025-02-19 17:14:37 +00:00
[CC-5719] Add support for builtin global-read-only policy (#18319)
* [CC-5719] Add support for builtin global-read-only policy * Add changelog * Add read-only to docs * Fix some minor issues. * Change from ReplaceAll to Sprintf * Change IsValidPolicy name to return an error instead of bool * Fix PolicyList test * Fix other tests * Apply suggestions from code review Co-authored-by: Paul Glass <pglass@hashicorp.com> * Fix state store test for policy list. * Fix naming issues * Update acl/validation.go Co-authored-by: Chris Thain <32781396+cthain@users.noreply.github.com> * Update agent/consul/acl_endpoint.go --------- Co-authored-by: Paul Glass <pglass@hashicorp.com> Co-authored-by: Chris Thain <32781396+cthain@users.noreply.github.com>
This commit is contained in:
parent
bb6fc63823
commit
6424ef6a56
6
.changelog/18319.txt
Normal file
6
.changelog/18319.txt
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
```release-note:improvement
|
||||||
|
acl: added builtin ACL policy that provides global read-only access (builtin/global-read-only)
|
||||||
|
```
|
||||||
|
```release-note:improvement
|
||||||
|
acl: allow for a single slash character in policy names
|
||||||
|
```
|
@ -12,6 +12,8 @@ const (
|
|||||||
AnonymousTokenID = "00000000-0000-0000-0000-000000000002"
|
AnonymousTokenID = "00000000-0000-0000-0000-000000000002"
|
||||||
AnonymousTokenAlias = "anonymous token"
|
AnonymousTokenAlias = "anonymous token"
|
||||||
AnonymousTokenSecret = "anonymous"
|
AnonymousTokenSecret = "anonymous"
|
||||||
|
|
||||||
|
ReservedBuiltinPrefix = "builtin/"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Config encapsulates all of the generic configuration parameters used for
|
// Config encapsulates all of the generic configuration parameters used for
|
||||||
|
@ -3,17 +3,22 @@
|
|||||||
|
|
||||||
package acl
|
package acl
|
||||||
|
|
||||||
import "regexp"
|
import (
|
||||||
|
"fmt"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ServiceIdentityNameMaxLength = 256
|
ServiceIdentityNameMaxLength = 256
|
||||||
NodeIdentityNameMaxLength = 256
|
NodeIdentityNameMaxLength = 256
|
||||||
|
PolicyNameMaxLength = 128
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
validServiceIdentityName = regexp.MustCompile(`^[a-z0-9]([a-z0-9\-_]*[a-z0-9])?$`)
|
validServiceIdentityName = regexp.MustCompile(`^[a-z0-9]([a-z0-9\-_]*[a-z0-9])?$`)
|
||||||
validNodeIdentityName = regexp.MustCompile(`^[a-z0-9]([a-z0-9\-_]*[a-z0-9])?$`)
|
validNodeIdentityName = regexp.MustCompile(`^[a-z0-9]([a-z0-9\-_]*[a-z0-9])?$`)
|
||||||
validPolicyName = regexp.MustCompile(`^[A-Za-z0-9\-_]{1,128}$`)
|
validPolicyName = regexp.MustCompile(`^[A-Za-z0-9\-_]+\/?[A-Za-z0-9\-_]*$`)
|
||||||
validRoleName = regexp.MustCompile(`^[A-Za-z0-9\-_]{1,256}$`)
|
validRoleName = regexp.MustCompile(`^[A-Za-z0-9\-_]{1,256}$`)
|
||||||
validAuthMethodName = regexp.MustCompile(`^[A-Za-z0-9\-_]{1,128}$`)
|
validAuthMethodName = regexp.MustCompile(`^[A-Za-z0-9\-_]{1,128}$`)
|
||||||
)
|
)
|
||||||
@ -40,10 +45,21 @@ func IsValidNodeIdentityName(name string) bool {
|
|||||||
return validNodeIdentityName.MatchString(name)
|
return validNodeIdentityName.MatchString(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsValidPolicyName returns true if the provided name can be used as an
|
// ValidatePolicyName returns nil if the provided name can be used as an
|
||||||
// ACLPolicy Name.
|
// ACLPolicy Name otherwise a useful error is returned.
|
||||||
func IsValidPolicyName(name string) bool {
|
func ValidatePolicyName(name string) error {
|
||||||
return validPolicyName.MatchString(name)
|
if len(name) < 1 || len(name) > PolicyNameMaxLength {
|
||||||
|
return fmt.Errorf("Invalid Policy: invalid Name. Length must be greater than 0 and less than %d", PolicyNameMaxLength)
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.HasPrefix(name, "/") || strings.HasPrefix(name, ReservedBuiltinPrefix) {
|
||||||
|
return fmt.Errorf("Invalid Policy: invalid Name. Names cannot be prefixed with '/' or '%s'", ReservedBuiltinPrefix)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !validPolicyName.MatchString(name) {
|
||||||
|
return fmt.Errorf("Invalid Policy: invalid Name. Only alphanumeric characters, a single '/', '-' and '_' are allowed")
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsValidRoleName returns true if the provided name can be used as an
|
// IsValidRoleName returns true if the provided name can be used as an
|
||||||
|
78
acl/validation_test.go
Normal file
78
acl/validation_test.go
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
// Copyright (c) HashiCorp, Inc.
|
||||||
|
// SPDX-License-Identifier: MPL-2.0
|
||||||
|
|
||||||
|
package acl
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Test_ValidatePolicyName(t *testing.T) {
|
||||||
|
for _, tc := range []struct {
|
||||||
|
description string
|
||||||
|
name string
|
||||||
|
valid bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
description: "valid policy",
|
||||||
|
name: "this-is-valid",
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "empty policy",
|
||||||
|
name: "",
|
||||||
|
valid: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "with slash",
|
||||||
|
name: "policy/with-slash",
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "leading slash",
|
||||||
|
name: "/no-leading-slash",
|
||||||
|
valid: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "too many slashes",
|
||||||
|
name: "too/many/slashes",
|
||||||
|
valid: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "no double-slash",
|
||||||
|
name: "no//double-slash",
|
||||||
|
valid: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "builtin prefix",
|
||||||
|
name: "builtin/prefix-cannot-be-used",
|
||||||
|
valid: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "long",
|
||||||
|
name: "this-policy-name-is-very-very-long-but-it-is-okay-because-it-is-the-max-length-that-we-allow-here-in-a-policy-name-which-is-good",
|
||||||
|
valid: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "too long",
|
||||||
|
name: "this-is-a-policy-that-has-one-character-too-many-it-is-way-too-long-for-a-policy-we-do-not-want-a-policy-of-this-length-because-1",
|
||||||
|
valid: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "invalid start character",
|
||||||
|
name: "!foo",
|
||||||
|
valid: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
description: "invalid character",
|
||||||
|
name: "this%is%bad",
|
||||||
|
valid: false,
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
t.Run(tc.description, func(t *testing.T) {
|
||||||
|
require.Equal(t, tc.valid, ValidatePolicyName(tc.name) == nil)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -438,8 +438,8 @@ func TestACL_HTTP(t *testing.T) {
|
|||||||
policies, ok := raw.(structs.ACLPolicyListStubs)
|
policies, ok := raw.(structs.ACLPolicyListStubs)
|
||||||
require.True(t, ok)
|
require.True(t, ok)
|
||||||
|
|
||||||
// 2 we just created + global management
|
// 2 we just created + builtin policies
|
||||||
require.Len(t, policies, 3)
|
require.Len(t, policies, 2+len(structs.ACLBuiltinPolicies))
|
||||||
|
|
||||||
for policyID, expected := range policyMap {
|
for policyID, expected := range policyMap {
|
||||||
found := false
|
found := false
|
||||||
|
@ -869,8 +869,8 @@ func (a *ACL) PolicySet(args *structs.ACLPolicySetRequest, reply *structs.ACLPol
|
|||||||
return fmt.Errorf("Invalid Policy: no Name is set")
|
return fmt.Errorf("Invalid Policy: no Name is set")
|
||||||
}
|
}
|
||||||
|
|
||||||
if !acl.IsValidPolicyName(policy.Name) {
|
if err := acl.ValidatePolicyName(policy.Name); err != nil {
|
||||||
return fmt.Errorf("Invalid Policy: invalid Name. Only alphanumeric characters, '-' and '_' are allowed")
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
var idMatch *structs.ACLPolicy
|
var idMatch *structs.ACLPolicy
|
||||||
@ -915,13 +915,13 @@ func (a *ACL) PolicySet(args *structs.ACLPolicySetRequest, reply *structs.ACLPol
|
|||||||
return fmt.Errorf("Invalid Policy: A policy with name %q already exists", policy.Name)
|
return fmt.Errorf("Invalid Policy: A policy with name %q already exists", policy.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
if policy.ID == structs.ACLPolicyGlobalManagementID {
|
if builtinPolicy, ok := structs.ACLBuiltinPolicies[policy.ID]; ok {
|
||||||
if policy.Datacenters != nil || len(policy.Datacenters) > 0 {
|
if policy.Datacenters != nil || len(policy.Datacenters) > 0 {
|
||||||
return fmt.Errorf("Changing the Datacenters of the builtin global-management policy is not permitted")
|
return fmt.Errorf("Changing the Datacenters of the %s policy is not permitted", builtinPolicy.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
if policy.Rules != idMatch.Rules {
|
if policy.Rules != idMatch.Rules {
|
||||||
return fmt.Errorf("Changing the Rules for the builtin global-management policy is not permitted")
|
return fmt.Errorf("Changing the Rules for the builtin %s policy is not permitted", builtinPolicy.Name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -999,8 +999,8 @@ func (a *ACL) PolicyDelete(args *structs.ACLPolicyDeleteRequest, reply *string)
|
|||||||
return fmt.Errorf("policy does not exist: %w", acl.ErrNotFound)
|
return fmt.Errorf("policy does not exist: %w", acl.ErrNotFound)
|
||||||
}
|
}
|
||||||
|
|
||||||
if policy.ID == structs.ACLPolicyGlobalManagementID {
|
if builtinPolicy, ok := structs.ACLBuiltinPolicies[policy.ID]; ok {
|
||||||
return fmt.Errorf("Delete operation not permitted on the builtin global-management policy")
|
return fmt.Errorf("Delete operation not permitted on the builtin %s policy", builtinPolicy.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
req := structs.ACLPolicyBatchDeleteRequest{
|
req := structs.ACLPolicyBatchDeleteRequest{
|
||||||
|
@ -2183,7 +2183,7 @@ func TestACLEndpoint_PolicySet_CustomID(t *testing.T) {
|
|||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestACLEndpoint_PolicySet_globalManagement(t *testing.T) {
|
func TestACLEndpoint_PolicySet_builtins(t *testing.T) {
|
||||||
if testing.Short() {
|
if testing.Short() {
|
||||||
t.Skip("too slow for testing.Short")
|
t.Skip("too slow for testing.Short")
|
||||||
}
|
}
|
||||||
@ -2195,13 +2195,16 @@ func TestACLEndpoint_PolicySet_globalManagement(t *testing.T) {
|
|||||||
|
|
||||||
aclEp := ACL{srv: srv}
|
aclEp := ACL{srv: srv}
|
||||||
|
|
||||||
|
for _, builtinPolicy := range structs.ACLBuiltinPolicies {
|
||||||
|
name := fmt.Sprintf("foobar-%s", builtinPolicy.Name) // This is required to get past validation
|
||||||
|
|
||||||
// Can't change the rules
|
// Can't change the rules
|
||||||
{
|
{
|
||||||
req := structs.ACLPolicySetRequest{
|
req := structs.ACLPolicySetRequest{
|
||||||
Datacenter: "dc1",
|
Datacenter: "dc1",
|
||||||
Policy: structs.ACLPolicy{
|
Policy: structs.ACLPolicy{
|
||||||
ID: structs.ACLPolicyGlobalManagementID,
|
ID: builtinPolicy.ID,
|
||||||
Name: "foobar", // This is required to get past validation
|
Name: name,
|
||||||
Rules: "service \"\" { policy = \"write\" }",
|
Rules: "service \"\" { policy = \"write\" }",
|
||||||
},
|
},
|
||||||
WriteRequest: structs.WriteRequest{Token: TestDefaultInitialManagementToken},
|
WriteRequest: structs.WriteRequest{Token: TestDefaultInitialManagementToken},
|
||||||
@ -2209,7 +2212,7 @@ func TestACLEndpoint_PolicySet_globalManagement(t *testing.T) {
|
|||||||
resp := structs.ACLPolicy{}
|
resp := structs.ACLPolicy{}
|
||||||
|
|
||||||
err := aclEp.PolicySet(&req, &resp)
|
err := aclEp.PolicySet(&req, &resp)
|
||||||
require.EqualError(t, err, "Changing the Rules for the builtin global-management policy is not permitted")
|
require.EqualError(t, err, fmt.Sprintf("Changing the Rules for the builtin %s policy is not permitted", builtinPolicy.Name))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Can rename it
|
// Can rename it
|
||||||
@ -2217,9 +2220,9 @@ func TestACLEndpoint_PolicySet_globalManagement(t *testing.T) {
|
|||||||
req := structs.ACLPolicySetRequest{
|
req := structs.ACLPolicySetRequest{
|
||||||
Datacenter: "dc1",
|
Datacenter: "dc1",
|
||||||
Policy: structs.ACLPolicy{
|
Policy: structs.ACLPolicy{
|
||||||
ID: structs.ACLPolicyGlobalManagementID,
|
ID: builtinPolicy.ID,
|
||||||
Name: "foobar",
|
Name: name,
|
||||||
Rules: structs.ACLPolicyGlobalManagement,
|
Rules: builtinPolicy.Rules,
|
||||||
},
|
},
|
||||||
WriteRequest: structs.WriteRequest{Token: TestDefaultInitialManagementToken},
|
WriteRequest: structs.WriteRequest{Token: TestDefaultInitialManagementToken},
|
||||||
}
|
}
|
||||||
@ -2229,13 +2232,13 @@ func TestACLEndpoint_PolicySet_globalManagement(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Get the policy again
|
// Get the policy again
|
||||||
policyResp, err := retrieveTestPolicy(codec, TestDefaultInitialManagementToken, "dc1", structs.ACLPolicyGlobalManagementID)
|
policyResp, err := retrieveTestPolicy(codec, TestDefaultInitialManagementToken, "dc1", builtinPolicy.ID)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
policy := policyResp.Policy
|
policy := policyResp.Policy
|
||||||
|
|
||||||
require.Equal(t, policy.ID, structs.ACLPolicyGlobalManagementID)
|
require.Equal(t, policy.ID, builtinPolicy.ID)
|
||||||
require.Equal(t, policy.Name, "foobar")
|
require.Equal(t, policy.Name, name)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2271,7 +2274,7 @@ func TestACLEndpoint_PolicyDelete(t *testing.T) {
|
|||||||
require.Nil(t, tokenResp.Policy)
|
require.Nil(t, tokenResp.Policy)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestACLEndpoint_PolicyDelete_globalManagement(t *testing.T) {
|
func TestACLEndpoint_PolicyDelete_builtins(t *testing.T) {
|
||||||
if testing.Short() {
|
if testing.Short() {
|
||||||
t.Skip("too slow for testing.Short")
|
t.Skip("too slow for testing.Short")
|
||||||
}
|
}
|
||||||
@ -2282,16 +2285,17 @@ func TestACLEndpoint_PolicyDelete_globalManagement(t *testing.T) {
|
|||||||
waitForLeaderEstablishment(t, srv)
|
waitForLeaderEstablishment(t, srv)
|
||||||
aclEp := ACL{srv: srv}
|
aclEp := ACL{srv: srv}
|
||||||
|
|
||||||
|
for _, builtinPolicy := range structs.ACLBuiltinPolicies {
|
||||||
req := structs.ACLPolicyDeleteRequest{
|
req := structs.ACLPolicyDeleteRequest{
|
||||||
Datacenter: "dc1",
|
Datacenter: "dc1",
|
||||||
PolicyID: structs.ACLPolicyGlobalManagementID,
|
PolicyID: builtinPolicy.ID,
|
||||||
WriteRequest: structs.WriteRequest{Token: TestDefaultInitialManagementToken},
|
WriteRequest: structs.WriteRequest{Token: TestDefaultInitialManagementToken},
|
||||||
}
|
}
|
||||||
var resp string
|
var resp string
|
||||||
|
|
||||||
err := aclEp.PolicyDelete(&req, &resp)
|
err := aclEp.PolicyDelete(&req, &resp)
|
||||||
|
require.EqualError(t, err, fmt.Sprintf("Delete operation not permitted on the builtin %s policy", builtinPolicy.Name))
|
||||||
require.EqualError(t, err, "Delete operation not permitted on the builtin global-management policy")
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestACLEndpoint_PolicyList(t *testing.T) {
|
func TestACLEndpoint_PolicyList(t *testing.T) {
|
||||||
@ -2324,6 +2328,7 @@ func TestACLEndpoint_PolicyList(t *testing.T) {
|
|||||||
|
|
||||||
policies := []string{
|
policies := []string{
|
||||||
structs.ACLPolicyGlobalManagementID,
|
structs.ACLPolicyGlobalManagementID,
|
||||||
|
structs.ACLPolicyGlobalReadOnlyID,
|
||||||
p1.ID,
|
p1.ID,
|
||||||
p2.ID,
|
p2.ID,
|
||||||
}
|
}
|
||||||
|
@ -244,7 +244,7 @@ func (w *TokenWriter) Delete(secretID string, fromLogout bool) error {
|
|||||||
|
|
||||||
func validateTokenID(id string) error {
|
func validateTokenID(id string) error {
|
||||||
if structs.ACLIDReserved(id) {
|
if structs.ACLIDReserved(id) {
|
||||||
return fmt.Errorf("UUIDs with the prefix %q are reserved", structs.ACLReservedPrefix)
|
return fmt.Errorf("UUIDs with the prefix %q are reserved", structs.ACLReservedIDPrefix)
|
||||||
}
|
}
|
||||||
if _, err := uuid.ParseUUID(id); err != nil {
|
if _, err := uuid.ParseUUID(id); err != nil {
|
||||||
return errors.New("not a valid UUID")
|
return errors.New("not a valid UUID")
|
||||||
|
@ -41,7 +41,7 @@ func TestTokenWriter_Create_Validation(t *testing.T) {
|
|||||||
errorContains: "not a valid UUID",
|
errorContains: "not a valid UUID",
|
||||||
},
|
},
|
||||||
"AccessorID is reserved": {
|
"AccessorID is reserved": {
|
||||||
token: structs.ACLToken{AccessorID: structs.ACLReservedPrefix + generateID(t)},
|
token: structs.ACLToken{AccessorID: structs.ACLReservedIDPrefix + generateID(t)},
|
||||||
errorContains: "reserved",
|
errorContains: "reserved",
|
||||||
},
|
},
|
||||||
"AccessorID already in use (as AccessorID)": {
|
"AccessorID already in use (as AccessorID)": {
|
||||||
@ -57,7 +57,7 @@ func TestTokenWriter_Create_Validation(t *testing.T) {
|
|||||||
errorContains: "not a valid UUID",
|
errorContains: "not a valid UUID",
|
||||||
},
|
},
|
||||||
"SecretID is reserved": {
|
"SecretID is reserved": {
|
||||||
token: structs.ACLToken{SecretID: structs.ACLReservedPrefix + generateID(t)},
|
token: structs.ACLToken{SecretID: structs.ACLReservedIDPrefix + generateID(t)},
|
||||||
errorContains: "reserved",
|
errorContains: "reserved",
|
||||||
},
|
},
|
||||||
"SecretID already in use (as AccessorID)": {
|
"SecretID already in use (as AccessorID)": {
|
||||||
|
@ -108,7 +108,7 @@ func TestFSM_SnapshotRestore_OSS(t *testing.T) {
|
|||||||
ID: structs.ACLPolicyGlobalManagementID,
|
ID: structs.ACLPolicyGlobalManagementID,
|
||||||
Name: "global-management",
|
Name: "global-management",
|
||||||
Description: "Builtin Policy that grants unlimited access",
|
Description: "Builtin Policy that grants unlimited access",
|
||||||
Rules: structs.ACLPolicyGlobalManagement,
|
Rules: structs.ACLPolicyGlobalManagementRules,
|
||||||
}
|
}
|
||||||
policy.SetHash(true)
|
policy.SetHash(true)
|
||||||
require.NoError(t, fsm.state.ACLPolicySet(1, policy))
|
require.NoError(t, fsm.state.ACLPolicySet(1, policy))
|
||||||
|
@ -420,34 +420,11 @@ func (s *Server) initializeACLs(ctx context.Context) error {
|
|||||||
if s.InPrimaryDatacenter() {
|
if s.InPrimaryDatacenter() {
|
||||||
s.logger.Info("initializing acls")
|
s.logger.Info("initializing acls")
|
||||||
|
|
||||||
// Create/Upgrade the builtin global-management policy
|
// Create/Upgrade the builtin policies
|
||||||
_, policy, err := s.fsm.State().ACLPolicyGetByID(nil, structs.ACLPolicyGlobalManagementID, structs.DefaultEnterpriseMetaInDefaultPartition())
|
for _, policy := range structs.ACLBuiltinPolicies {
|
||||||
if err != nil {
|
if err := s.writeBuiltinACLPolicy(policy); err != nil {
|
||||||
return fmt.Errorf("failed to get the builtin global-management policy")
|
return err
|
||||||
}
|
}
|
||||||
if policy == nil || policy.Rules != structs.ACLPolicyGlobalManagement {
|
|
||||||
newPolicy := structs.ACLPolicy{
|
|
||||||
ID: structs.ACLPolicyGlobalManagementID,
|
|
||||||
Name: "global-management",
|
|
||||||
Description: "Builtin Policy that grants unlimited access",
|
|
||||||
Rules: structs.ACLPolicyGlobalManagement,
|
|
||||||
EnterpriseMeta: *structs.DefaultEnterpriseMetaInDefaultPartition(),
|
|
||||||
}
|
|
||||||
if policy != nil {
|
|
||||||
newPolicy.Name = policy.Name
|
|
||||||
newPolicy.Description = policy.Description
|
|
||||||
}
|
|
||||||
|
|
||||||
newPolicy.SetHash(true)
|
|
||||||
|
|
||||||
req := structs.ACLPolicyBatchSetRequest{
|
|
||||||
Policies: structs.ACLPolicies{&newPolicy},
|
|
||||||
}
|
|
||||||
_, err := s.raftApply(structs.ACLPolicySetRequestType, &req)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed to create global-management policy: %v", err)
|
|
||||||
}
|
|
||||||
s.logger.Info("Created ACL 'global-management' policy")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for configured initial management token.
|
// Check for configured initial management token.
|
||||||
@ -492,6 +469,36 @@ func (s *Server) initializeACLs(ctx context.Context) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// writeBuiltinACLPolicy writes the given built-in policy to Raft if the policy
|
||||||
|
// is not found or if the policy rules have been changed. The name and
|
||||||
|
// description of a built-in policy are user-editable and must be preserved
|
||||||
|
// during updates. This function must only be called in a primary datacenter.
|
||||||
|
func (s *Server) writeBuiltinACLPolicy(newPolicy structs.ACLPolicy) error {
|
||||||
|
_, policy, err := s.fsm.State().ACLPolicyGetByID(nil, newPolicy.ID, structs.DefaultEnterpriseMetaInDefaultPartition())
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to get the builtin %s policy", newPolicy.Name)
|
||||||
|
}
|
||||||
|
if policy == nil || policy.Rules != newPolicy.Rules {
|
||||||
|
if policy != nil {
|
||||||
|
newPolicy.Name = policy.Name
|
||||||
|
newPolicy.Description = policy.Description
|
||||||
|
}
|
||||||
|
|
||||||
|
newPolicy.EnterpriseMeta = *structs.DefaultEnterpriseMetaInDefaultPartition()
|
||||||
|
newPolicy.SetHash(true)
|
||||||
|
|
||||||
|
req := structs.ACLPolicyBatchSetRequest{
|
||||||
|
Policies: structs.ACLPolicies{&newPolicy},
|
||||||
|
}
|
||||||
|
_, err := s.raftApply(structs.ACLPolicySetRequestType, &req)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to create %s policy: %v", newPolicy.Name, err)
|
||||||
|
}
|
||||||
|
s.logger.Info(fmt.Sprintf("Created ACL '%s' policy", newPolicy.Name))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s *Server) initializeManagementToken(name, secretID string) error {
|
func (s *Server) initializeManagementToken(name, secretID string) error {
|
||||||
state := s.fsm.State()
|
state := s.fsm.State()
|
||||||
if _, err := uuid.ParseUUID(secretID); err != nil {
|
if _, err := uuid.ParseUUID(secretID); err != nil {
|
||||||
|
@ -1307,9 +1307,12 @@ func TestLeader_ACL_Initialization(t *testing.T) {
|
|||||||
_, s1 := testServerWithConfig(t, conf)
|
_, s1 := testServerWithConfig(t, conf)
|
||||||
testrpc.WaitForTestAgent(t, s1.RPC, "dc1")
|
testrpc.WaitForTestAgent(t, s1.RPC, "dc1")
|
||||||
|
|
||||||
_, policy, err := s1.fsm.State().ACLPolicyGetByID(nil, structs.ACLPolicyGlobalManagementID, nil)
|
// check that the builtin policies were created
|
||||||
|
for _, builtinPolicy := range structs.ACLBuiltinPolicies {
|
||||||
|
_, policy, err := s1.fsm.State().ACLPolicyGetByID(nil, builtinPolicy.ID, nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NotNil(t, policy)
|
require.NotNil(t, policy)
|
||||||
|
}
|
||||||
|
|
||||||
if tt.initialManagement != "" {
|
if tt.initialManagement != "" {
|
||||||
_, initialManagement, err := s1.fsm.State().ACLTokenGetBySecret(nil, tt.initialManagement, nil)
|
_, initialManagement, err := s1.fsm.State().ACLTokenGetBySecret(nil, tt.initialManagement, nil)
|
||||||
@ -1439,15 +1442,17 @@ func TestLeader_ACLUpgrade_IsStickyEvenIfSerfTagsRegress(t *testing.T) {
|
|||||||
waitForLeaderEstablishment(t, s2)
|
waitForLeaderEstablishment(t, s2)
|
||||||
waitForNewACLReplication(t, s2, structs.ACLReplicatePolicies, 1, 0, 0)
|
waitForNewACLReplication(t, s2, structs.ACLReplicatePolicies, 1, 0, 0)
|
||||||
|
|
||||||
// Everybody has the management policy.
|
// Everybody has the builtin policies.
|
||||||
retry.Run(t, func(r *retry.R) {
|
retry.Run(t, func(r *retry.R) {
|
||||||
_, policy1, err := s1.fsm.State().ACLPolicyGetByID(nil, structs.ACLPolicyGlobalManagementID, structs.DefaultEnterpriseMetaInDefaultPartition())
|
for _, builtinPolicy := range structs.ACLBuiltinPolicies {
|
||||||
|
_, policy1, err := s1.fsm.State().ACLPolicyGetByID(nil, builtinPolicy.ID, structs.DefaultEnterpriseMetaInDefaultPartition())
|
||||||
require.NoError(r, err)
|
require.NoError(r, err)
|
||||||
require.NotNil(r, policy1)
|
require.NotNil(r, policy1)
|
||||||
|
|
||||||
_, policy2, err := s2.fsm.State().ACLPolicyGetByID(nil, structs.ACLPolicyGlobalManagementID, structs.DefaultEnterpriseMetaInDefaultPartition())
|
_, policy2, err := s2.fsm.State().ACLPolicyGetByID(nil, builtinPolicy.ID, structs.DefaultEnterpriseMetaInDefaultPartition())
|
||||||
require.NoError(r, err)
|
require.NoError(r, err)
|
||||||
require.NotNil(r, policy2)
|
require.NotNil(r, policy2)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// Shutdown s1 and s2.
|
// Shutdown s1 and s2.
|
||||||
|
@ -884,18 +884,18 @@ func aclPolicySetTxn(tx WriteTxn, idx uint64, policy *structs.ACLPolicy) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if existing != nil {
|
if existing != nil {
|
||||||
if policy.ID == structs.ACLPolicyGlobalManagementID {
|
if builtinPolicy, ok := structs.ACLBuiltinPolicies[policy.ID]; ok {
|
||||||
// Only the name and description are modifiable
|
// Only the name and description are modifiable
|
||||||
// Here we specifically check that the rules on the global management policy
|
// Here we specifically check that the rules on the builtin policy
|
||||||
// are identical to the correct policy rules within the binary. This is opposed
|
// are identical to the correct policy rules within the binary. This is opposed
|
||||||
// to checking against the current rules to allow us to update the rules during
|
// to checking against the current rules to allow us to update the rules during
|
||||||
// upgrades.
|
// upgrades.
|
||||||
if policy.Rules != structs.ACLPolicyGlobalManagement {
|
if policy.Rules != builtinPolicy.Rules {
|
||||||
return fmt.Errorf("Changing the Rules for the builtin global-management policy is not permitted")
|
return fmt.Errorf("Changing the Rules for the builtin %s policy is not permitted", builtinPolicy.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
if policy.Datacenters != nil && len(policy.Datacenters) != 0 {
|
if policy.Datacenters != nil && len(policy.Datacenters) != 0 {
|
||||||
return fmt.Errorf("Changing the Datacenters of the builtin global-management policy is not permitted")
|
return fmt.Errorf("Changing the Datacenters of the builtin %s policy is not permitted", builtinPolicy.Name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1062,8 +1062,8 @@ func aclPolicyDeleteTxn(tx WriteTxn, idx uint64, value string, fn aclPolicyGetFn
|
|||||||
|
|
||||||
policy := rawPolicy.(*structs.ACLPolicy)
|
policy := rawPolicy.(*structs.ACLPolicy)
|
||||||
|
|
||||||
if policy.ID == structs.ACLPolicyGlobalManagementID {
|
if builtinPolicy, ok := structs.ACLBuiltinPolicies[policy.ID]; ok {
|
||||||
return fmt.Errorf("Deletion of the builtin global-management policy is not permitted")
|
return fmt.Errorf("Deletion of the builtin %s policy is not permitted", builtinPolicy.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
return aclPolicyDeleteWithPolicy(tx, policy, idx)
|
return aclPolicyDeleteWithPolicy(tx, policy, idx)
|
||||||
|
@ -30,16 +30,17 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func setupGlobalManagement(t *testing.T, s *Store) {
|
func setupGlobalManagement(t *testing.T, s *Store) {
|
||||||
policy := structs.ACLPolicy{
|
policy := structs.ACLBuiltinPolicies[structs.ACLPolicyGlobalManagementID]
|
||||||
ID: structs.ACLPolicyGlobalManagementID,
|
|
||||||
Name: "global-management",
|
|
||||||
Description: "Builtin Policy that grants unlimited access",
|
|
||||||
Rules: structs.ACLPolicyGlobalManagement,
|
|
||||||
}
|
|
||||||
policy.SetHash(true)
|
policy.SetHash(true)
|
||||||
require.NoError(t, s.ACLPolicySet(1, &policy))
|
require.NoError(t, s.ACLPolicySet(1, &policy))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func setupBuiltinGlobalReadOnly(t *testing.T, s *Store) {
|
||||||
|
policy := structs.ACLBuiltinPolicies[structs.ACLPolicyGlobalReadOnlyID]
|
||||||
|
policy.SetHash(true)
|
||||||
|
require.NoError(t, s.ACLPolicySet(2, &policy))
|
||||||
|
}
|
||||||
|
|
||||||
func setupAnonymous(t *testing.T, s *Store) {
|
func setupAnonymous(t *testing.T, s *Store) {
|
||||||
token := structs.ACLToken{
|
token := structs.ACLToken{
|
||||||
AccessorID: acl.AnonymousTokenID,
|
AccessorID: acl.AnonymousTokenID,
|
||||||
@ -53,6 +54,7 @@ func setupAnonymous(t *testing.T, s *Store) {
|
|||||||
func testACLStateStore(t *testing.T) *Store {
|
func testACLStateStore(t *testing.T) *Store {
|
||||||
s := testStateStore(t)
|
s := testStateStore(t)
|
||||||
setupGlobalManagement(t, s)
|
setupGlobalManagement(t, s)
|
||||||
|
setupBuiltinGlobalReadOnly(t, s)
|
||||||
setupAnonymous(t, s)
|
setupAnonymous(t, s)
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
@ -184,6 +186,7 @@ func TestStateStore_ACLBootstrap(t *testing.T) {
|
|||||||
|
|
||||||
s := testStateStore(t)
|
s := testStateStore(t)
|
||||||
setupGlobalManagement(t, s)
|
setupGlobalManagement(t, s)
|
||||||
|
setupBuiltinGlobalReadOnly(t, s)
|
||||||
|
|
||||||
canBootstrap, index, err := s.CanBootstrapACLToken()
|
canBootstrap, index, err := s.CanBootstrapACLToken()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@ -1430,7 +1433,7 @@ func TestStateStore_ACLPolicy_SetGet(t *testing.T) {
|
|||||||
ID: structs.ACLPolicyGlobalManagementID,
|
ID: structs.ACLPolicyGlobalManagementID,
|
||||||
Name: "global-management",
|
Name: "global-management",
|
||||||
Description: "Global Management",
|
Description: "Global Management",
|
||||||
Rules: structs.ACLPolicyGlobalManagement,
|
Rules: structs.ACLPolicyGlobalManagementRules,
|
||||||
Datacenters: []string{"dc1"},
|
Datacenters: []string{"dc1"},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1444,7 +1447,7 @@ func TestStateStore_ACLPolicy_SetGet(t *testing.T) {
|
|||||||
ID: structs.ACLPolicyGlobalManagementID,
|
ID: structs.ACLPolicyGlobalManagementID,
|
||||||
Name: "management",
|
Name: "management",
|
||||||
Description: "Modified",
|
Description: "Modified",
|
||||||
Rules: structs.ACLPolicyGlobalManagement,
|
Rules: structs.ACLPolicyGlobalManagementRules,
|
||||||
}
|
}
|
||||||
|
|
||||||
require.NoError(t, s.ACLPolicySet(3, &policy))
|
require.NoError(t, s.ACLPolicySet(3, &policy))
|
||||||
@ -1494,7 +1497,7 @@ func TestStateStore_ACLPolicy_SetGet(t *testing.T) {
|
|||||||
require.NotNil(t, rpolicy)
|
require.NotNil(t, rpolicy)
|
||||||
require.Equal(t, "global-management", rpolicy.Name)
|
require.Equal(t, "global-management", rpolicy.Name)
|
||||||
require.Equal(t, "Builtin Policy that grants unlimited access", rpolicy.Description)
|
require.Equal(t, "Builtin Policy that grants unlimited access", rpolicy.Description)
|
||||||
require.Equal(t, structs.ACLPolicyGlobalManagement, rpolicy.Rules)
|
require.Equal(t, structs.ACLPolicyGlobalManagementRules, rpolicy.Rules)
|
||||||
require.Len(t, rpolicy.Datacenters, 0)
|
require.Len(t, rpolicy.Datacenters, 0)
|
||||||
require.Equal(t, uint64(1), rpolicy.CreateIndex)
|
require.Equal(t, uint64(1), rpolicy.CreateIndex)
|
||||||
require.Equal(t, uint64(1), rpolicy.ModifyIndex)
|
require.Equal(t, uint64(1), rpolicy.ModifyIndex)
|
||||||
@ -1664,31 +1667,39 @@ func TestStateStore_ACLPolicy_List(t *testing.T) {
|
|||||||
|
|
||||||
_, policies, err := s.ACLPolicyList(nil, nil)
|
_, policies, err := s.ACLPolicyList(nil, nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Len(t, policies, 3)
|
require.Len(t, policies, 4)
|
||||||
policies.Sort()
|
policies.Sort()
|
||||||
require.Equal(t, structs.ACLPolicyGlobalManagementID, policies[0].ID)
|
require.Equal(t, structs.ACLPolicyGlobalManagementID, policies[0].ID)
|
||||||
require.Equal(t, "global-management", policies[0].Name)
|
require.Equal(t, structs.ACLPolicyGlobalManagementName, policies[0].Name)
|
||||||
require.Equal(t, "Builtin Policy that grants unlimited access", policies[0].Description)
|
require.Equal(t, structs.ACLPolicyGlobalManagementDesc, policies[0].Description)
|
||||||
require.Empty(t, policies[0].Datacenters)
|
require.Empty(t, policies[0].Datacenters)
|
||||||
require.NotEqual(t, []byte{}, policies[0].Hash)
|
require.NotEqual(t, []byte{}, policies[0].Hash)
|
||||||
require.Equal(t, uint64(1), policies[0].CreateIndex)
|
require.Equal(t, uint64(1), policies[0].CreateIndex)
|
||||||
require.Equal(t, uint64(1), policies[0].ModifyIndex)
|
require.Equal(t, uint64(1), policies[0].ModifyIndex)
|
||||||
|
|
||||||
require.Equal(t, "a2719052-40b3-4a4b-baeb-f3df1831a217", policies[1].ID)
|
require.Equal(t, structs.ACLPolicyGlobalReadOnlyID, policies[1].ID)
|
||||||
require.Equal(t, "acl-write-dc3", policies[1].Name)
|
require.Equal(t, structs.ACLPolicyGlobalReadOnlyName, policies[1].Name)
|
||||||
require.Equal(t, "Can manage ACLs in dc3", policies[1].Description)
|
require.Equal(t, structs.ACLPolicyGlobalReadOnlyDesc, policies[1].Description)
|
||||||
require.ElementsMatch(t, []string{"dc3"}, policies[1].Datacenters)
|
require.Empty(t, policies[1].Datacenters)
|
||||||
require.Nil(t, policies[1].Hash)
|
require.NotEqual(t, []byte{}, policies[1].Hash)
|
||||||
require.Equal(t, uint64(2), policies[1].CreateIndex)
|
require.Equal(t, uint64(2), policies[1].CreateIndex)
|
||||||
require.Equal(t, uint64(2), policies[1].ModifyIndex)
|
require.Equal(t, uint64(2), policies[1].ModifyIndex)
|
||||||
|
|
||||||
require.Equal(t, "a4f68bd6-3af5-4f56-b764-3c6f20247879", policies[2].ID)
|
require.Equal(t, "a2719052-40b3-4a4b-baeb-f3df1831a217", policies[2].ID)
|
||||||
require.Equal(t, "service-read", policies[2].Name)
|
require.Equal(t, "acl-write-dc3", policies[2].Name)
|
||||||
require.Equal(t, "", policies[2].Description)
|
require.Equal(t, "Can manage ACLs in dc3", policies[2].Description)
|
||||||
require.Empty(t, policies[2].Datacenters)
|
require.ElementsMatch(t, []string{"dc3"}, policies[2].Datacenters)
|
||||||
require.Nil(t, policies[2].Hash)
|
require.Nil(t, policies[2].Hash)
|
||||||
require.Equal(t, uint64(2), policies[2].CreateIndex)
|
require.Equal(t, uint64(2), policies[2].CreateIndex)
|
||||||
require.Equal(t, uint64(2), policies[2].ModifyIndex)
|
require.Equal(t, uint64(2), policies[2].ModifyIndex)
|
||||||
|
|
||||||
|
require.Equal(t, "a4f68bd6-3af5-4f56-b764-3c6f20247879", policies[3].ID)
|
||||||
|
require.Equal(t, "service-read", policies[3].Name)
|
||||||
|
require.Equal(t, "", policies[3].Description)
|
||||||
|
require.Empty(t, policies[3].Datacenters)
|
||||||
|
require.Nil(t, policies[3].Hash)
|
||||||
|
require.Equal(t, uint64(2), policies[3].CreateIndex)
|
||||||
|
require.Equal(t, uint64(2), policies[3].ModifyIndex)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestStateStore_ACLPolicy_Delete(t *testing.T) {
|
func TestStateStore_ACLPolicy_Delete(t *testing.T) {
|
||||||
|
@ -46,40 +46,67 @@ const (
|
|||||||
// This policy gives unlimited access to everything. Users
|
// This policy gives unlimited access to everything. Users
|
||||||
// may rename if desired but cannot delete or modify the rules.
|
// may rename if desired but cannot delete or modify the rules.
|
||||||
ACLPolicyGlobalManagementID = "00000000-0000-0000-0000-000000000001"
|
ACLPolicyGlobalManagementID = "00000000-0000-0000-0000-000000000001"
|
||||||
ACLPolicyGlobalManagement = `
|
ACLPolicyGlobalManagementName = "global-management"
|
||||||
acl = "write"
|
ACLPolicyGlobalManagementDesc = "Builtin Policy that grants unlimited access"
|
||||||
|
|
||||||
|
ACLPolicyGlobalReadOnlyID = "00000000-0000-0000-0000-000000000002"
|
||||||
|
ACLPolicyGlobalReadOnlyName = "builtin/global-read-only"
|
||||||
|
ACLPolicyGlobalReadOnlyDesc = "Builtin Policy that grants unlimited read-only access to all components"
|
||||||
|
|
||||||
|
ACLReservedIDPrefix = "00000000-0000-0000-0000-0000000000"
|
||||||
|
|
||||||
|
aclPolicyGlobalRulesTemplate = `
|
||||||
|
acl = "%[1]s"
|
||||||
agent_prefix "" {
|
agent_prefix "" {
|
||||||
policy = "write"
|
policy = "%[1]s"
|
||||||
}
|
}
|
||||||
event_prefix "" {
|
event_prefix "" {
|
||||||
policy = "write"
|
policy = "%[1]s"
|
||||||
}
|
}
|
||||||
key_prefix "" {
|
key_prefix "" {
|
||||||
policy = "write"
|
policy = "%[1]s"
|
||||||
}
|
}
|
||||||
keyring = "write"
|
keyring = "%[1]s"
|
||||||
node_prefix "" {
|
node_prefix "" {
|
||||||
policy = "write"
|
policy = "%[1]s"
|
||||||
}
|
}
|
||||||
operator = "write"
|
operator = "%[1]s"
|
||||||
mesh = "write"
|
mesh = "%[1]s"
|
||||||
peering = "write"
|
peering = "%[1]s"
|
||||||
query_prefix "" {
|
query_prefix "" {
|
||||||
policy = "write"
|
policy = "%[1]s"
|
||||||
}
|
}
|
||||||
service_prefix "" {
|
service_prefix "" {
|
||||||
policy = "write"
|
policy = "%[1]s"
|
||||||
intentions = "write"
|
intentions = "%[1]s"
|
||||||
}
|
}
|
||||||
session_prefix "" {
|
session_prefix "" {
|
||||||
policy = "write"
|
policy = "%[1]s"
|
||||||
}` + EnterpriseACLPolicyGlobalManagement
|
}`
|
||||||
|
)
|
||||||
|
|
||||||
ACLReservedPrefix = "00000000-0000-0000-0000-0000000000"
|
var (
|
||||||
|
ACLPolicyGlobalReadOnlyRules = fmt.Sprintf(aclPolicyGlobalRulesTemplate, "read") + EnterpriseACLPolicyGlobalReadOnly
|
||||||
|
ACLPolicyGlobalManagementRules = fmt.Sprintf(aclPolicyGlobalRulesTemplate, "write") + EnterpriseACLPolicyGlobalManagement
|
||||||
|
|
||||||
|
ACLBuiltinPolicies = map[string]ACLPolicy{
|
||||||
|
ACLPolicyGlobalManagementID: {
|
||||||
|
ID: ACLPolicyGlobalManagementID,
|
||||||
|
Name: ACLPolicyGlobalManagementName,
|
||||||
|
Description: ACLPolicyGlobalManagementDesc,
|
||||||
|
Rules: ACLPolicyGlobalManagementRules,
|
||||||
|
},
|
||||||
|
ACLPolicyGlobalReadOnlyID: {
|
||||||
|
ID: ACLPolicyGlobalReadOnlyID,
|
||||||
|
Name: ACLPolicyGlobalReadOnlyName,
|
||||||
|
Description: ACLPolicyGlobalReadOnlyDesc,
|
||||||
|
Rules: ACLPolicyGlobalReadOnlyRules,
|
||||||
|
},
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func ACLIDReserved(id string) bool {
|
func ACLIDReserved(id string) bool {
|
||||||
return strings.HasPrefix(id, ACLReservedPrefix)
|
return strings.HasPrefix(id, ACLReservedIDPrefix)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ACLBootstrapNotAllowedErr is returned once we know that a bootstrap can no
|
// ACLBootstrapNotAllowedErr is returned once we know that a bootstrap can no
|
||||||
|
@ -14,6 +14,7 @@ import (
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
EnterpriseACLPolicyGlobalManagement = ""
|
EnterpriseACLPolicyGlobalManagement = ""
|
||||||
|
EnterpriseACLPolicyGlobalReadOnly = ""
|
||||||
|
|
||||||
// aclPolicyTemplateServiceIdentity is the template used for synthesizing
|
// aclPolicyTemplateServiceIdentity is the template used for synthesizing
|
||||||
// policies for service identities.
|
// policies for service identities.
|
||||||
|
@ -190,7 +190,7 @@ func TestAPI_ACLPolicy_List(t *testing.T) {
|
|||||||
|
|
||||||
policies, qm, err := acl.PolicyList(nil)
|
policies, qm, err := acl.PolicyList(nil)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Len(t, policies, 4)
|
require.Len(t, policies, 5)
|
||||||
require.NotEqual(t, 0, qm.LastIndex)
|
require.NotEqual(t, 0, qm.LastIndex)
|
||||||
require.True(t, qm.KnownLeader)
|
require.True(t, qm.KnownLeader)
|
||||||
|
|
||||||
@ -233,6 +233,11 @@ func TestAPI_ACLPolicy_List(t *testing.T) {
|
|||||||
policy4, ok := policyMap["00000000-0000-0000-0000-000000000001"]
|
policy4, ok := policyMap["00000000-0000-0000-0000-000000000001"]
|
||||||
require.True(t, ok)
|
require.True(t, ok)
|
||||||
require.NotNil(t, policy4)
|
require.NotNil(t, policy4)
|
||||||
|
|
||||||
|
// make sure the 5th policy is the global read-only
|
||||||
|
policy5, ok := policyMap["00000000-0000-0000-0000-000000000002"]
|
||||||
|
require.True(t, ok)
|
||||||
|
require.NotNil(t, policy5)
|
||||||
}
|
}
|
||||||
|
|
||||||
func prepTokenPolicies(t *testing.T, acl *ACL) (policies []*ACLPolicy) {
|
func prepTokenPolicies(t *testing.T, acl *ACL) (policies []*ACLPolicy) {
|
||||||
|
@ -391,7 +391,11 @@ New installations of Consul ship with the following built-in policies.
|
|||||||
|
|
||||||
### Global Management
|
### Global Management
|
||||||
|
|
||||||
The `global-management` policy grants unrestricted privileges to any token linked to it. The policy is assigned the reserved ID of `00000000-0000-0000-0000-000000000001`. You can rename the global management policy, but Consul will prevent you from modifying any other attributes, including the rule set and datacenter scope.
|
The `global-management` policy grants unrestricted privileges to any token linked to it. The policy is assigned the reserved ID of `00000000-0000-0000-0000-000000000001`. You can rename the global management policy, but Consul prevents you from modifying any other attributes, including the rule set and datacenter scope.
|
||||||
|
|
||||||
|
### Global Read-Only
|
||||||
|
|
||||||
|
The `builtin/global-read-only` policy grants unrestricted _read-only_ privileges to any token linked to it. The policy is assigned the reserved ID of `00000000-0000-0000-0000-000000000002`. You can rename the global read-only policy, but Consul prevents you from modifying any other attributes, including the rule set and datacenter scope.
|
||||||
|
|
||||||
### Namespace Management <EnterpriseAlert inline />
|
### Namespace Management <EnterpriseAlert inline />
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user