mirror of https://github.com/status-im/consul.git
[NET-6103] Enable query tokens by service name using templated policy (#19666)
This commit is contained in:
parent
d9432f9032
commit
ea0caa3e0f
|
@ -0,0 +1,3 @@
|
||||||
|
```release-note:improvement
|
||||||
|
api: Add support for listing ACL tokens by service name when using templated policies.
|
||||||
|
```
|
|
@ -1361,6 +1361,39 @@ func TestACL_HTTP(t *testing.T) {
|
||||||
require.Len(t, token.ServiceIdentities, 1)
|
require.Len(t, token.ServiceIdentities, 1)
|
||||||
require.Equal(t, "sn1", token.ServiceIdentities[0].ServiceName)
|
require.Equal(t, "sn1", token.ServiceIdentities[0].ServiceName)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("List by ServiceName based on templated policies", func(t *testing.T) {
|
||||||
|
tokenInput := &structs.ACLToken{
|
||||||
|
Description: "token for templated policies service",
|
||||||
|
TemplatedPolicies: []*structs.ACLTemplatedPolicy{
|
||||||
|
{
|
||||||
|
TemplateName: "builtin/service",
|
||||||
|
TemplateVariables: &structs.ACLTemplatedPolicyVariables{
|
||||||
|
Name: "service1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
req, _ := http.NewRequest("PUT", "/v1/acl/token", jsonBody(tokenInput))
|
||||||
|
req.Header.Add("X-Consul-Token", "root")
|
||||||
|
resp := httptest.NewRecorder()
|
||||||
|
_, err := a.srv.ACLTokenCreate(resp, req)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
req, _ = http.NewRequest("GET", "/v1/acl/tokens?servicename=service1", nil)
|
||||||
|
req.Header.Add("X-Consul-Token", "root")
|
||||||
|
resp = httptest.NewRecorder()
|
||||||
|
raw, err := a.srv.ACLTokenList(resp, req)
|
||||||
|
require.NoError(t, err)
|
||||||
|
tokens, ok := raw.(structs.ACLTokenListStubs)
|
||||||
|
require.True(t, ok)
|
||||||
|
require.Len(t, tokens, 1)
|
||||||
|
token := tokens[0]
|
||||||
|
require.Equal(t, "token for templated policies service", token.Description)
|
||||||
|
require.Len(t, token.TemplatedPolicies, 1)
|
||||||
|
require.Equal(t, "service1", token.TemplatedPolicies[0].TemplateVariables.Name)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("ACLTemplatedPolicy", func(t *testing.T) {
|
t.Run("ACLTemplatedPolicy", func(t *testing.T) {
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"github.com/hashicorp/go-memdb"
|
"github.com/hashicorp/go-memdb"
|
||||||
|
|
||||||
"github.com/hashicorp/consul/agent/structs"
|
"github.com/hashicorp/consul/agent/structs"
|
||||||
|
"github.com/hashicorp/consul/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -409,7 +410,7 @@ func indexExpiresFromACLToken(t *structs.ACLToken, local bool) ([]byte, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func indexServiceNameFromACLToken(token *structs.ACLToken) ([][]byte, error) {
|
func indexServiceNameFromACLToken(token *structs.ACLToken) ([][]byte, error) {
|
||||||
vals := make([][]byte, 0, len(token.ServiceIdentities))
|
vals := make([][]byte, 0, len(token.ServiceIdentities)+len(token.TemplatedPolicies))
|
||||||
for _, id := range token.ServiceIdentities {
|
for _, id := range token.ServiceIdentities {
|
||||||
if id != nil && id.ServiceName != "" {
|
if id != nil && id.ServiceName != "" {
|
||||||
var b indexBuilder
|
var b indexBuilder
|
||||||
|
@ -417,6 +418,15 @@ func indexServiceNameFromACLToken(token *structs.ACLToken) ([][]byte, error) {
|
||||||
vals = append(vals, b.Bytes())
|
vals = append(vals, b.Bytes())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for _, tp := range token.TemplatedPolicies {
|
||||||
|
if tp != nil && tp.TemplateName == api.ACLTemplatedPolicyServiceName && tp.TemplateVariables != nil && tp.TemplateVariables.Name != "" {
|
||||||
|
var b indexBuilder
|
||||||
|
b.String(strings.ToLower(tp.TemplateVariables.Name))
|
||||||
|
vals = append(vals, b.Bytes())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if len(vals) == 0 {
|
if len(vals) == 0 {
|
||||||
return nil, errMissingValueForIndex
|
return nil, errMissingValueForIndex
|
||||||
}
|
}
|
||||||
|
|
|
@ -868,6 +868,33 @@ func TestStateStore_ACLToken_List(t *testing.T) {
|
||||||
},
|
},
|
||||||
Local: true,
|
Local: true,
|
||||||
},
|
},
|
||||||
|
// templated policy: the serviceName specific token
|
||||||
|
&structs.ACLToken{
|
||||||
|
AccessorID: "2f89e357-dedb-8d8f-7f30-1f465a41508a",
|
||||||
|
SecretID: "21ab62c9-5372-038c-b6ba-424961cb38c7",
|
||||||
|
TemplatedPolicies: []*structs.ACLTemplatedPolicy{
|
||||||
|
{
|
||||||
|
TemplateName: "builtin/service",
|
||||||
|
TemplateVariables: &structs.ACLTemplatedPolicyVariables{
|
||||||
|
Name: "service-1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
// templated policy: the serviceName specific token and local
|
||||||
|
&structs.ACLToken{
|
||||||
|
AccessorID: "5e5d6269-f933-3af2-fe30-259b050223f9",
|
||||||
|
SecretID: "89a456eb-5d55-9a65-92e1-96935dc5b358",
|
||||||
|
TemplatedPolicies: []*structs.ACLTemplatedPolicy{
|
||||||
|
{
|
||||||
|
TemplateName: "builtin/service",
|
||||||
|
TemplateVariables: &structs.ACLTemplatedPolicyVariables{
|
||||||
|
Name: "service-1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Local: true,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
require.NoError(t, s.ACLTokenBatchSet(2, tokens, ACLTokenSetOptions{}))
|
require.NoError(t, s.ACLTokenBatchSet(2, tokens, ACLTokenSetOptions{}))
|
||||||
|
@ -893,6 +920,7 @@ func TestStateStore_ACLToken_List(t *testing.T) {
|
||||||
methodName: "",
|
methodName: "",
|
||||||
accessors: []string{
|
accessors: []string{
|
||||||
acl.AnonymousTokenID,
|
acl.AnonymousTokenID,
|
||||||
|
"2f89e357-dedb-8d8f-7f30-1f465a41508a", // templated policy: serviceName + global
|
||||||
"47eea4da-bda1-48a6-901c-3e36d2d9262f", // policy + global
|
"47eea4da-bda1-48a6-901c-3e36d2d9262f", // policy + global
|
||||||
"54866514-3cf2-4fec-8a8a-710583831834", // mgmt + global
|
"54866514-3cf2-4fec-8a8a-710583831834", // mgmt + global
|
||||||
"74277ae1-6a9b-4035-b444-2370fe6a2cb5", // authMethod + global
|
"74277ae1-6a9b-4035-b444-2370fe6a2cb5", // authMethod + global
|
||||||
|
@ -910,6 +938,7 @@ func TestStateStore_ACLToken_List(t *testing.T) {
|
||||||
accessors: []string{
|
accessors: []string{
|
||||||
"211f0360-ef53-41d3-9d4d-db84396eb6c0", // authMethod + local
|
"211f0360-ef53-41d3-9d4d-db84396eb6c0", // authMethod + local
|
||||||
"4915fc9d-3726-4171-b588-6c271f45eecd", // policy + local
|
"4915fc9d-3726-4171-b588-6c271f45eecd", // policy + local
|
||||||
|
"5e5d6269-f933-3af2-fe30-259b050223f9", // templated policies: serviceName + local
|
||||||
"a14fa45e-0afe-4b44-961d-a430030ccfe2", // serviceName + local
|
"a14fa45e-0afe-4b44-961d-a430030ccfe2", // serviceName + local
|
||||||
"cadb4f13-f62a-49ab-ab3f-5a7e01b925d9", // role + local
|
"cadb4f13-f62a-49ab-ab3f-5a7e01b925d9", // role + local
|
||||||
"f1093997-b6c7-496d-bfb8-6b1b1895641b", // mgmt + local
|
"f1093997-b6c7-496d-bfb8-6b1b1895641b", // mgmt + local
|
||||||
|
@ -1030,18 +1059,58 @@ func TestStateStore_ACLToken_List(t *testing.T) {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "All",
|
name: "templated policy: ServiceName - Global",
|
||||||
local: true,
|
local: false,
|
||||||
global: true,
|
global: true,
|
||||||
policy: "",
|
policy: "",
|
||||||
role: "",
|
role: "",
|
||||||
methodName: "",
|
methodName: "",
|
||||||
|
serviceName: "service-1",
|
||||||
|
accessors: []string{
|
||||||
|
"2f89e357-dedb-8d8f-7f30-1f465a41508a", // serviceName + global
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "templated policy: ServiceName - Local",
|
||||||
|
local: true,
|
||||||
|
global: false,
|
||||||
|
policy: "",
|
||||||
|
role: "",
|
||||||
|
methodName: "",
|
||||||
|
serviceName: "service-1",
|
||||||
|
accessors: []string{
|
||||||
|
"5e5d6269-f933-3af2-fe30-259b050223f9", // serviceName + local
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "templated policy: ServiceName - All",
|
||||||
|
local: true,
|
||||||
|
global: true,
|
||||||
|
policy: "",
|
||||||
|
role: "",
|
||||||
|
methodName: "",
|
||||||
|
serviceName: "service-1",
|
||||||
|
accessors: []string{
|
||||||
|
"2f89e357-dedb-8d8f-7f30-1f465a41508a", // serviceName + global
|
||||||
|
"5e5d6269-f933-3af2-fe30-259b050223f9", // serviceName + local
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "All",
|
||||||
|
local: true,
|
||||||
|
global: true,
|
||||||
|
policy: "",
|
||||||
|
role: "",
|
||||||
|
methodName: "",
|
||||||
|
serviceName: "",
|
||||||
accessors: []string{
|
accessors: []string{
|
||||||
acl.AnonymousTokenID,
|
acl.AnonymousTokenID,
|
||||||
"211f0360-ef53-41d3-9d4d-db84396eb6c0", // authMethod + local
|
"211f0360-ef53-41d3-9d4d-db84396eb6c0", // authMethod + local
|
||||||
|
"2f89e357-dedb-8d8f-7f30-1f465a41508a", // templated policy: serviceName + global
|
||||||
"47eea4da-bda1-48a6-901c-3e36d2d9262f", // policy + global
|
"47eea4da-bda1-48a6-901c-3e36d2d9262f", // policy + global
|
||||||
"4915fc9d-3726-4171-b588-6c271f45eecd", // policy + local
|
"4915fc9d-3726-4171-b588-6c271f45eecd", // policy + local
|
||||||
"54866514-3cf2-4fec-8a8a-710583831834", // mgmt + global
|
"54866514-3cf2-4fec-8a8a-710583831834", // mgmt + global
|
||||||
|
"5e5d6269-f933-3af2-fe30-259b050223f9", // templated policy: serviceName + local
|
||||||
"74277ae1-6a9b-4035-b444-2370fe6a2cb5", // authMethod + global
|
"74277ae1-6a9b-4035-b444-2370fe6a2cb5", // authMethod + global
|
||||||
"80c900e1-2fc5-4685-ae29-1b2d17fc30e4", // serviceName + global
|
"80c900e1-2fc5-4685-ae29-1b2d17fc30e4", // serviceName + global
|
||||||
"a14fa45e-0afe-4b44-961d-a430030ccfe2", // serviceName + local
|
"a14fa45e-0afe-4b44-961d-a430030ccfe2", // serviceName + local
|
||||||
|
|
|
@ -160,6 +160,17 @@ func (tp *ACLTemplatedPolicy) ValidateTemplatedPolicy(schema string) error {
|
||||||
return fmt.Errorf("failed to load json schema for validation %w", err)
|
return fmt.Errorf("failed to load json schema for validation %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// validate service and node identity names
|
||||||
|
if tp.TemplateVariables != nil {
|
||||||
|
if tp.TemplateName == api.ACLTemplatedPolicyServiceName && !acl.IsValidServiceIdentityName(tp.TemplateVariables.Name) {
|
||||||
|
return fmt.Errorf("service identity %q has an invalid name. Only lowercase alphanumeric characters, '-' and '_' are allowed", tp.TemplateVariables.Name)
|
||||||
|
}
|
||||||
|
|
||||||
|
if tp.TemplateName == api.ACLTemplatedPolicyNodeName && !acl.IsValidNodeIdentityName(tp.TemplateVariables.Name) {
|
||||||
|
return fmt.Errorf("node identity %q has an invalid name. Only lowercase alphanumeric characters, '-' and '_' are allowed", tp.TemplateVariables.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if res.Valid() {
|
if res.Valid() {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue