diff --git a/.changelog/12807.txt b/.changelog/12807.txt new file mode 100644 index 000000000..9d2005a03 --- /dev/null +++ b/.changelog/12807.txt @@ -0,0 +1,3 @@ +```release-note:improvement +acl: Clarify node/service identities must be lowercase +``` diff --git a/agent/acl_endpoint_test.go b/agent/acl_endpoint_test.go index 2c6aad450..01a3f0b5e 100644 --- a/agent/acl_endpoint_test.go +++ b/agent/acl_endpoint_test.go @@ -1142,6 +1142,41 @@ func TestACL_HTTP(t *testing.T) { _, err := a.srv.ACLTokenCreate(resp, req) require.Error(t, err) }) + + t.Run("Create with uppercase node identity", func(t *testing.T) { + tokenInput := &structs.ACLToken{ + Description: "agent token for foo node", + NodeIdentities: []*structs.ACLNodeIdentity{ + { + NodeName: "FOO", + Datacenter: "bar", + }, + }, + } + + req, _ := http.NewRequest("PUT", "/v1/acl/token?token=root", jsonBody(tokenInput)) + resp := httptest.NewRecorder() + _, err := a.srv.ACLTokenCreate(resp, req) + require.Error(t, err) + testutil.RequireErrorContains(t, err, "Only lowercase alphanumeric") + }) + + t.Run("Create with uppercase service identity", func(t *testing.T) { + tokenInput := &structs.ACLToken{ + Description: "token for service identity foo", + ServiceIdentities: []*structs.ACLServiceIdentity{ + { + ServiceName: "FOO", + }, + }, + } + + req, _ := http.NewRequest("PUT", "/v1/acl/token?token=root", jsonBody(tokenInput)) + resp := httptest.NewRecorder() + _, err := a.srv.ACLTokenCreate(resp, req) + require.Error(t, err) + testutil.RequireErrorContains(t, err, "Only lowercase alphanumeric") + }) }) } diff --git a/agent/consul/acl_endpoint.go b/agent/consul/acl_endpoint.go index 658f72a42..3b9b00cf8 100644 --- a/agent/consul/acl_endpoint.go +++ b/agent/consul/acl_endpoint.go @@ -770,7 +770,7 @@ func (a *ACL) tokenSetInternal(args *structs.ACLTokenSetRequest, reply *structs. return fmt.Errorf("Service identity %q cannot specify a list of datacenters on a local token", svcid.ServiceName) } if !isValidServiceIdentityName(svcid.ServiceName) { - return fmt.Errorf("Service identity %q has an invalid name. Only alphanumeric characters, '-' and '_' are allowed", svcid.ServiceName) + return fmt.Errorf("Service identity %q has an invalid name. Only lowercase alphanumeric characters, '-' and '_' are allowed", svcid.ServiceName) } } token.ServiceIdentities = dedupeServiceIdentities(token.ServiceIdentities) @@ -783,7 +783,7 @@ func (a *ACL) tokenSetInternal(args *structs.ACLTokenSetRequest, reply *structs. return fmt.Errorf("Node identity is missing the datacenter field on this token") } if !isValidNodeIdentityName(nodeid.NodeName) { - return fmt.Errorf("Node identity has an invalid name. Only alphanumeric characters, '-' and '_' are allowed") + return fmt.Errorf("Node identity has an invalid name. Only lowercase alphanumeric characters, '-' and '_' are allowed") } } token.NodeIdentities = dedupeNodeIdentities(token.NodeIdentities) @@ -1682,7 +1682,7 @@ func (a *ACL) RoleSet(args *structs.ACLRoleSetRequest, reply *structs.ACLRole) e return fmt.Errorf("Service identity is missing the service name field on this role") } if !isValidServiceIdentityName(svcid.ServiceName) { - return fmt.Errorf("Service identity %q has an invalid name. Only alphanumeric characters, '-' and '_' are allowed", svcid.ServiceName) + return fmt.Errorf("Service identity %q has an invalid name. Only lowercase alphanumeric characters, '-' and '_' are allowed", svcid.ServiceName) } } role.ServiceIdentities = dedupeServiceIdentities(role.ServiceIdentities) @@ -1695,7 +1695,7 @@ func (a *ACL) RoleSet(args *structs.ACLRoleSetRequest, reply *structs.ACLRole) e return fmt.Errorf("Node identity is missing the datacenter field on this role") } if !isValidNodeIdentityName(nodeid.NodeName) { - return fmt.Errorf("Node identity has an invalid name. Only alphanumeric characters, '-' and '_' are allowed") + return fmt.Errorf("Node identity has an invalid name. Only lowercase alphanumeric characters, '-' and '_' are allowed") } } role.NodeIdentities = dedupeNodeIdentities(role.NodeIdentities)