mirror of https://github.com/status-im/consul.git
[NET-6640] Adds "Policy" BindType to BindingRule (#19499)
feat: add bind type of policy Co-authored-by: Ronald Ekambi <ronekambi@gmail.com>
This commit is contained in:
parent
0058045969
commit
302f994410
|
@ -0,0 +1,3 @@
|
||||||
|
```release-note:feature
|
||||||
|
acl: add policy bindtype to binding rules.
|
||||||
|
```
|
|
@ -68,6 +68,10 @@ func IsValidRoleName(name string) bool {
|
||||||
return validRoleName.MatchString(name)
|
return validRoleName.MatchString(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func IsValidPolicyName(name string) bool {
|
||||||
|
return ValidatePolicyName(name) == 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
|
||||||
// ACLAuthMethod Name.
|
// ACLAuthMethod Name.
|
||||||
func IsValidAuthMethodName(name string) bool {
|
func IsValidAuthMethodName(name string) bool {
|
||||||
|
|
|
@ -3663,6 +3663,37 @@ func TestACLEndpoint_BindingRuleSet(t *testing.T) {
|
||||||
require.Equal(t, "test-node", rule.BindName)
|
require.Equal(t, "test-node", rule.BindName)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("Bind Policy", func(t *testing.T) {
|
||||||
|
req := structs.ACLBindingRuleSetRequest{
|
||||||
|
Datacenter: "dc1",
|
||||||
|
BindingRule: structs.ACLBindingRule{
|
||||||
|
Description: "foobar policy",
|
||||||
|
AuthMethod: testAuthMethod.Name,
|
||||||
|
Selector: "serviceaccount.name==abc",
|
||||||
|
BindType: structs.BindingRuleBindTypePolicy,
|
||||||
|
BindName: "test-policy",
|
||||||
|
},
|
||||||
|
WriteRequest: structs.WriteRequest{Token: TestDefaultInitialManagementToken},
|
||||||
|
}
|
||||||
|
var resp structs.ACLBindingRule
|
||||||
|
|
||||||
|
err := aclEp.BindingRuleSet(&req, &resp)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, resp.ID)
|
||||||
|
|
||||||
|
// Get the rule directly to validate that it exists
|
||||||
|
ruleResp, err := retrieveTestBindingRule(codec, TestDefaultInitialManagementToken, "dc1", resp.ID)
|
||||||
|
require.NoError(t, err)
|
||||||
|
rule := ruleResp.BindingRule
|
||||||
|
|
||||||
|
require.NotEmpty(t, rule.ID)
|
||||||
|
require.Equal(t, rule.Description, "foobar policy")
|
||||||
|
require.Equal(t, rule.AuthMethod, testAuthMethod.Name)
|
||||||
|
require.Equal(t, "serviceaccount.name==abc", rule.Selector)
|
||||||
|
require.Equal(t, structs.BindingRuleBindTypePolicy, rule.BindType)
|
||||||
|
require.Equal(t, "test-policy", rule.BindName)
|
||||||
|
})
|
||||||
|
|
||||||
t.Run("templated policy", func(t *testing.T) {
|
t.Run("templated policy", func(t *testing.T) {
|
||||||
req := structs.ACLBindingRuleSetRequest{
|
req := structs.ACLBindingRuleSetRequest{
|
||||||
Datacenter: "dc1",
|
Datacenter: "dc1",
|
||||||
|
@ -3841,7 +3872,7 @@ func TestACLEndpoint_BindingRuleSet(t *testing.T) {
|
||||||
t.Run("Create fails; invalid bind type", func(t *testing.T) {
|
t.Run("Create fails; invalid bind type", func(t *testing.T) {
|
||||||
reqRule := newRule()
|
reqRule := newRule()
|
||||||
reqRule.BindType = "invalid"
|
reqRule.BindType = "invalid"
|
||||||
requireSetErrors(t, reqRule, "Invalid Binding Rule: unknown BindType")
|
requireSetErrors(t, reqRule, "invalid Binding Rule: unknown BindType")
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Create fails; bind name with unknown vars", func(t *testing.T) {
|
t.Run("Create fails; bind name with unknown vars", func(t *testing.T) {
|
||||||
|
@ -4540,6 +4571,11 @@ func TestACLEndpoint_Login(t *testing.T) {
|
||||||
"fake-node",
|
"fake-node",
|
||||||
"default", "mynode", "jkl101",
|
"default", "mynode", "jkl101",
|
||||||
)
|
)
|
||||||
|
testauth.InstallSessionToken(
|
||||||
|
testSessionID,
|
||||||
|
"fake-policy", // 1 rule (policy)
|
||||||
|
"default", "mypolicy", "jkl012",
|
||||||
|
)
|
||||||
|
|
||||||
method, err := upsertTestAuthMethod(codec, TestDefaultInitialManagementToken, "dc1", testSessionID)
|
method, err := upsertTestAuthMethod(codec, TestDefaultInitialManagementToken, "dc1", testSessionID)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
@ -4587,6 +4623,15 @@ func TestACLEndpoint_Login(t *testing.T) {
|
||||||
)
|
)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// policy rule
|
||||||
|
_, err = upsertTestBindingRule(
|
||||||
|
codec, TestDefaultInitialManagementToken, "dc1", method.Name,
|
||||||
|
"serviceaccount.namespace==default and serviceaccount.name==mypolicy",
|
||||||
|
structs.BindingRuleBindTypePolicy,
|
||||||
|
"method-${serviceaccount.name}",
|
||||||
|
)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
t.Run("do not provide a token", func(t *testing.T) {
|
t.Run("do not provide a token", func(t *testing.T) {
|
||||||
req := structs.ACLLoginRequest{
|
req := structs.ACLLoginRequest{
|
||||||
Auth: &structs.ACLLoginParams{
|
Auth: &structs.ACLLoginParams{
|
||||||
|
|
|
@ -36,14 +36,16 @@ func NewBinder(store BinderStateStore, datacenter string) *Binder {
|
||||||
type BinderStateStore interface {
|
type BinderStateStore interface {
|
||||||
ACLBindingRuleList(ws memdb.WatchSet, methodName string, entMeta *acl.EnterpriseMeta) (uint64, structs.ACLBindingRules, error)
|
ACLBindingRuleList(ws memdb.WatchSet, methodName string, entMeta *acl.EnterpriseMeta) (uint64, structs.ACLBindingRules, error)
|
||||||
ACLRoleGetByName(ws memdb.WatchSet, roleName string, entMeta *acl.EnterpriseMeta) (uint64, *structs.ACLRole, error)
|
ACLRoleGetByName(ws memdb.WatchSet, roleName string, entMeta *acl.EnterpriseMeta) (uint64, *structs.ACLRole, error)
|
||||||
|
ACLPolicyGetByName(ws memdb.WatchSet, policyName string, entMeta *acl.EnterpriseMeta) (uint64, *structs.ACLPolicy, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bindings contains the ACL roles, service identities, node identities,
|
// Bindings contains the ACL roles, service identities, node identities, policies,
|
||||||
// templated policies, and enterprise meta to be assigned to the created token.
|
// templated policies, and enterprise meta to be assigned to the created token.
|
||||||
type Bindings struct {
|
type Bindings struct {
|
||||||
Roles []structs.ACLTokenRoleLink
|
Roles []structs.ACLTokenRoleLink
|
||||||
ServiceIdentities []*structs.ACLServiceIdentity
|
ServiceIdentities []*structs.ACLServiceIdentity
|
||||||
NodeIdentities []*structs.ACLNodeIdentity
|
NodeIdentities []*structs.ACLNodeIdentity
|
||||||
|
Policies []structs.ACLTokenPolicyLink
|
||||||
TemplatedPolicies structs.ACLTemplatedPolicies
|
TemplatedPolicies structs.ACLTemplatedPolicies
|
||||||
EnterpriseMeta acl.EnterpriseMeta
|
EnterpriseMeta acl.EnterpriseMeta
|
||||||
}
|
}
|
||||||
|
@ -58,7 +60,8 @@ func (b *Bindings) None() bool {
|
||||||
return len(b.ServiceIdentities) == 0 &&
|
return len(b.ServiceIdentities) == 0 &&
|
||||||
len(b.NodeIdentities) == 0 &&
|
len(b.NodeIdentities) == 0 &&
|
||||||
len(b.TemplatedPolicies) == 0 &&
|
len(b.TemplatedPolicies) == 0 &&
|
||||||
len(b.Roles) == 0
|
len(b.Roles) == 0 &&
|
||||||
|
len(b.Policies) == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bind collects the ACL roles, service identities, etc. to be assigned to the
|
// Bind collects the ACL roles, service identities, etc. to be assigned to the
|
||||||
|
@ -119,6 +122,24 @@ func (b *Binder) Bind(authMethod *structs.ACLAuthMethod, verifiedIdentity *authm
|
||||||
}
|
}
|
||||||
bindings.TemplatedPolicies = append(bindings.TemplatedPolicies, templatedPolicy)
|
bindings.TemplatedPolicies = append(bindings.TemplatedPolicies, templatedPolicy)
|
||||||
|
|
||||||
|
case structs.BindingRuleBindTypePolicy:
|
||||||
|
bindName, err := computeBindName(rule.BindName, verifiedIdentity.ProjectedVars, acl.IsValidRoleName)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
_, policy, err := b.store.ACLPolicyGetByName(nil, bindName, &bindings.EnterpriseMeta)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if policy != nil {
|
||||||
|
bindings.Policies = append(bindings.Policies, structs.ACLTokenPolicyLink{
|
||||||
|
ID: policy.ID,
|
||||||
|
Name: policy.Name,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
case structs.BindingRuleBindTypeRole:
|
case structs.BindingRuleBindTypeRole:
|
||||||
bindName, err := computeBindName(rule.BindName, verifiedIdentity.ProjectedVars, acl.IsValidRoleName)
|
bindName, err := computeBindName(rule.BindName, verifiedIdentity.ProjectedVars, acl.IsValidRoleName)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -177,8 +198,13 @@ func IsValidBindingRule(bindType, bindName string, bindVars *structs.ACLTemplate
|
||||||
if _, err := computeBindName(bindName, fakeVarMap, acl.IsValidRoleName); err != nil {
|
if _, err := computeBindName(bindName, fakeVarMap, acl.IsValidRoleName); err != nil {
|
||||||
return fmt.Errorf("failed to validate bindType %q: %w", bindType, err)
|
return fmt.Errorf("failed to validate bindType %q: %w", bindType, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case structs.BindingRuleBindTypePolicy:
|
||||||
|
if _, err := computeBindName(bindName, fakeVarMap, acl.IsValidPolicyName); err != nil {
|
||||||
|
return fmt.Errorf("failed to validate bindType %q: %w", bindType, err)
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
return fmt.Errorf("Invalid Binding Rule: unknown BindType %q", bindType)
|
return fmt.Errorf("invalid Binding Rule: unknown BindType %q", bindType)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -15,6 +15,7 @@ import (
|
||||||
"github.com/hashicorp/consul/agent/consul/authmethod"
|
"github.com/hashicorp/consul/agent/consul/authmethod"
|
||||||
"github.com/hashicorp/consul/agent/consul/state"
|
"github.com/hashicorp/consul/agent/consul/state"
|
||||||
"github.com/hashicorp/consul/agent/structs"
|
"github.com/hashicorp/consul/agent/structs"
|
||||||
|
"github.com/hashicorp/consul/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestBindings_None(t *testing.T) {
|
func TestBindings_None(t *testing.T) {
|
||||||
|
@ -27,11 +28,79 @@ func TestBindings_None(t *testing.T) {
|
||||||
b = &Bindings{Roles: []structs.ACLTokenRoleLink{{ID: generateID(t)}}}
|
b = &Bindings{Roles: []structs.ACLTokenRoleLink{{ID: generateID(t)}}}
|
||||||
require.False(t, b.None())
|
require.False(t, b.None())
|
||||||
|
|
||||||
|
b = &Bindings{Policies: []structs.ACLTokenPolicyLink{{ID: generateID(t)}}}
|
||||||
|
require.False(t, b.None())
|
||||||
|
|
||||||
b = &Bindings{ServiceIdentities: []*structs.ACLServiceIdentity{{ServiceName: "web"}}}
|
b = &Bindings{ServiceIdentities: []*structs.ACLServiceIdentity{{ServiceName: "web"}}}
|
||||||
require.False(t, b.None())
|
require.False(t, b.None())
|
||||||
|
|
||||||
b = &Bindings{NodeIdentities: []*structs.ACLNodeIdentity{{NodeName: "node-123"}}}
|
b = &Bindings{NodeIdentities: []*structs.ACLNodeIdentity{{NodeName: "node-123"}}}
|
||||||
require.False(t, b.None())
|
require.False(t, b.None())
|
||||||
|
|
||||||
|
b = &Bindings{TemplatedPolicies: []*structs.ACLTemplatedPolicy{{TemplateName: api.ACLTemplatedPolicyDNSName}}}
|
||||||
|
require.False(t, b.None())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBinder_Policy_Success(t *testing.T) {
|
||||||
|
store := testStateStore(t)
|
||||||
|
binder := &Binder{store: store}
|
||||||
|
|
||||||
|
authMethod := &structs.ACLAuthMethod{
|
||||||
|
Name: "test-auth-method",
|
||||||
|
Type: "testing",
|
||||||
|
}
|
||||||
|
require.NoError(t, store.ACLAuthMethodSet(0, authMethod))
|
||||||
|
|
||||||
|
targetPolicy := &structs.ACLPolicy{
|
||||||
|
ID: generateID(t),
|
||||||
|
Name: "foo-policy",
|
||||||
|
}
|
||||||
|
require.NoError(t, store.ACLPolicySet(0, targetPolicy))
|
||||||
|
|
||||||
|
otherPolicy := &structs.ACLPolicy{
|
||||||
|
ID: generateID(t),
|
||||||
|
Name: "not-my-policy",
|
||||||
|
}
|
||||||
|
require.NoError(t, store.ACLPolicySet(0, otherPolicy))
|
||||||
|
|
||||||
|
bindingRules := structs.ACLBindingRules{
|
||||||
|
{
|
||||||
|
ID: generateID(t),
|
||||||
|
Selector: "role==engineer",
|
||||||
|
BindType: structs.BindingRuleBindTypePolicy,
|
||||||
|
BindName: "${editor}-policy",
|
||||||
|
AuthMethod: authMethod.Name,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: generateID(t),
|
||||||
|
Selector: "role==engineer",
|
||||||
|
BindType: structs.BindingRuleBindTypePolicy,
|
||||||
|
BindName: "this-policy-does-not-exist",
|
||||||
|
AuthMethod: authMethod.Name,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
ID: generateID(t),
|
||||||
|
Selector: "language==js",
|
||||||
|
BindType: structs.BindingRuleBindTypePolicy,
|
||||||
|
BindName: otherPolicy.Name,
|
||||||
|
AuthMethod: authMethod.Name,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
require.NoError(t, store.ACLBindingRuleBatchSet(0, bindingRules))
|
||||||
|
|
||||||
|
result, err := binder.Bind(&structs.ACLAuthMethod{}, &authmethod.Identity{
|
||||||
|
SelectableFields: map[string]string{
|
||||||
|
"role": "engineer",
|
||||||
|
"language": "go",
|
||||||
|
},
|
||||||
|
ProjectedVars: map[string]string{
|
||||||
|
"editor": "foo",
|
||||||
|
},
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, []structs.ACLTokenPolicyLink{
|
||||||
|
{ID: targetPolicy.ID, Name: targetPolicy.Name},
|
||||||
|
}, result.Policies)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestBinder_Roles_Success(t *testing.T) {
|
func TestBinder_Roles_Success(t *testing.T) {
|
||||||
|
@ -122,6 +191,32 @@ func TestBinder_Roles_NameValidation(t *testing.T) {
|
||||||
require.Contains(t, err.Error(), "invalid bind name")
|
require.Contains(t, err.Error(), "invalid bind name")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestBinder_Policy_NameValidation(t *testing.T) {
|
||||||
|
store := testStateStore(t)
|
||||||
|
binder := &Binder{store: store}
|
||||||
|
|
||||||
|
authMethod := &structs.ACLAuthMethod{
|
||||||
|
Name: "test-auth-method",
|
||||||
|
Type: "testing",
|
||||||
|
}
|
||||||
|
require.NoError(t, store.ACLAuthMethodSet(0, authMethod))
|
||||||
|
|
||||||
|
bindingRules := structs.ACLBindingRules{
|
||||||
|
{
|
||||||
|
ID: generateID(t),
|
||||||
|
Selector: "",
|
||||||
|
BindType: structs.BindingRuleBindTypePolicy,
|
||||||
|
BindName: "INVALID!",
|
||||||
|
AuthMethod: authMethod.Name,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
require.NoError(t, store.ACLBindingRuleBatchSet(0, bindingRules))
|
||||||
|
|
||||||
|
_, err := binder.Bind(&structs.ACLAuthMethod{}, &authmethod.Identity{})
|
||||||
|
require.Error(t, err)
|
||||||
|
require.Contains(t, err.Error(), "invalid bind name")
|
||||||
|
}
|
||||||
|
|
||||||
func TestBinder_ServiceIdentities_Success(t *testing.T) {
|
func TestBinder_ServiceIdentities_Success(t *testing.T) {
|
||||||
store := testStateStore(t)
|
store := testStateStore(t)
|
||||||
binder := &Binder{store: store}
|
binder := &Binder{store: store}
|
||||||
|
@ -275,54 +370,60 @@ func Test_IsValidBindingRule(t *testing.T) {
|
||||||
"invalid", "blah", nil, "", true},
|
"invalid", "blah", nil, "", true},
|
||||||
// valid HIL, invalid name
|
// valid HIL, invalid name
|
||||||
{"empty",
|
{"empty",
|
||||||
"both", "", nil, "", true},
|
"all", "", nil, "", true},
|
||||||
{"just end",
|
{"just end",
|
||||||
"both", "}", nil, "", true},
|
"all", "}", nil, "", true},
|
||||||
{"var without start",
|
{"var without start",
|
||||||
"both", " item }", nil, "item", true},
|
"all", " item }", nil, "item", true},
|
||||||
{"two vars missing second start",
|
{"two vars missing second start",
|
||||||
"both", "before-${ item }after--more }", nil, "item,more", true},
|
"all", "before-${ item }after--more }", nil, "item,more", true},
|
||||||
// names for the two types are validated differently
|
// names for the two types are validated differently
|
||||||
{"@ is disallowed",
|
{"@ is disallowed",
|
||||||
"both", "bad@name", nil, "", true},
|
"all", "bad@name", nil, "", true},
|
||||||
{"leading dash",
|
{"leading dash",
|
||||||
"role", "-name", nil, "", false},
|
"role", "-name", nil, "", false},
|
||||||
|
{"leading dash",
|
||||||
|
"policy", "-name", nil, "", false},
|
||||||
{"leading dash",
|
{"leading dash",
|
||||||
"service", "-name", nil, "", true},
|
"service", "-name", nil, "", true},
|
||||||
{"trailing dash",
|
{"trailing dash",
|
||||||
"role", "name-", nil, "", false},
|
"role", "name-", nil, "", false},
|
||||||
|
{"trailing dash",
|
||||||
|
"policy", "name-", nil, "", false},
|
||||||
{"trailing dash",
|
{"trailing dash",
|
||||||
"service", "name-", nil, "", true},
|
"service", "name-", nil, "", true},
|
||||||
{"inner dash",
|
{"inner dash",
|
||||||
"both", "name-end", nil, "", false},
|
"all", "name-end", nil, "", false},
|
||||||
{"upper case",
|
{"upper case",
|
||||||
"role", "NAME", nil, "", false},
|
"role", "NAME", nil, "", false},
|
||||||
|
{"upper case",
|
||||||
|
"policy", "NAME", nil, "", false},
|
||||||
{"upper case",
|
{"upper case",
|
||||||
"service", "NAME", nil, "", true},
|
"service", "NAME", nil, "", true},
|
||||||
// valid HIL, valid name
|
// valid HIL, valid name
|
||||||
{"no vars",
|
{"no vars",
|
||||||
"both", "nothing", nil, "", false},
|
"all", "nothing", nil, "", false},
|
||||||
{"just var",
|
{"just var",
|
||||||
"both", "${item}", nil, "item", false},
|
"all", "${item}", nil, "item", false},
|
||||||
{"var in middle",
|
{"var in middle",
|
||||||
"both", "before-${item}after", nil, "item", false},
|
"all", "before-${item}after", nil, "item", false},
|
||||||
{"two vars",
|
{"two vars",
|
||||||
"both", "before-${item}after-${more}", nil, "item,more", false},
|
"all", "before-${item}after-${more}", nil, "item,more", false},
|
||||||
// bad
|
// bad
|
||||||
{"no bind name",
|
{"no bind name",
|
||||||
"both", "", nil, "", true},
|
"all", "", nil, "", true},
|
||||||
{"just start",
|
{"just start",
|
||||||
"both", "${", nil, "", true},
|
"all", "${", nil, "", true},
|
||||||
{"backwards",
|
{"backwards",
|
||||||
"both", "}${", nil, "", true},
|
"all", "}${", nil, "", true},
|
||||||
{"no varname",
|
{"no varname",
|
||||||
"both", "${}", nil, "", true},
|
"all", "${}", nil, "", true},
|
||||||
{"missing map key",
|
{"missing map key",
|
||||||
"both", "${item}", nil, "", true},
|
"all", "${item}", nil, "", true},
|
||||||
{"var without end",
|
{"var without end",
|
||||||
"both", "${ item ", nil, "item", true},
|
"all", "${ item ", nil, "item", true},
|
||||||
{"two vars missing first end",
|
{"two vars missing first end",
|
||||||
"both", "before-${ item after-${ more }", nil, "item,more", true},
|
"all", "before-${ item after-${ more }", nil, "item,more", true},
|
||||||
|
|
||||||
// bind type: templated policy - bad input
|
// bind type: templated policy - bad input
|
||||||
{"templated-policy missing bindvars", "templated-policy", "builtin/service", nil, "", true},
|
{"templated-policy missing bindvars", "templated-policy", "builtin/service", nil, "", true},
|
||||||
|
@ -338,12 +439,16 @@ func Test_IsValidBindingRule(t *testing.T) {
|
||||||
"templated-policy", "builtin/service", &structs.ACLTemplatedPolicyVariables{Name: "before-${item}after-${more}"}, "item,more", false},
|
"templated-policy", "builtin/service", &structs.ACLTemplatedPolicyVariables{Name: "before-${item}after-${more}"}, "item,more", false},
|
||||||
} {
|
} {
|
||||||
var cases []testcase
|
var cases []testcase
|
||||||
if test.bindType == "both" {
|
if test.bindType == "all" {
|
||||||
test1 := test
|
test1 := test
|
||||||
test1.bindType = "role"
|
test1.bindType = "role"
|
||||||
test2 := test
|
test2 := test
|
||||||
test2.bindType = "service"
|
test2.bindType = "service"
|
||||||
cases = []testcase{test1, test2}
|
test3 := test
|
||||||
|
test3.bindType = "policy"
|
||||||
|
test4 := test
|
||||||
|
test4.bindType = "node"
|
||||||
|
cases = []testcase{test1, test2, test3, test4}
|
||||||
} else {
|
} else {
|
||||||
cases = []testcase{test}
|
cases = []testcase{test}
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,6 +48,7 @@ func (l *Login) TokenForVerifiedIdentity(identity *authmethod.Identity, authMeth
|
||||||
NodeIdentities: bindings.NodeIdentities,
|
NodeIdentities: bindings.NodeIdentities,
|
||||||
TemplatedPolicies: bindings.TemplatedPolicies,
|
TemplatedPolicies: bindings.TemplatedPolicies,
|
||||||
Roles: bindings.Roles,
|
Roles: bindings.Roles,
|
||||||
|
Policies: bindings.Policies,
|
||||||
EnterpriseMeta: bindings.EnterpriseMeta,
|
EnterpriseMeta: bindings.EnterpriseMeta,
|
||||||
}
|
}
|
||||||
token.ACLAuthMethodEnterpriseMeta.FillWithEnterpriseMeta(&authMethod.EnterpriseMeta)
|
token.ACLAuthMethodEnterpriseMeta.FillWithEnterpriseMeta(&authMethod.EnterpriseMeta)
|
||||||
|
|
|
@ -1084,6 +1084,21 @@ const (
|
||||||
// },
|
// },
|
||||||
// }
|
// }
|
||||||
BindingRuleBindTypeTemplatedPolicy = "templated-policy"
|
BindingRuleBindTypeTemplatedPolicy = "templated-policy"
|
||||||
|
|
||||||
|
// BindingRuleBindTypePolicy is the binding rule bind type that only allows
|
||||||
|
// the binding rule to function if a policy with the given name (BindName)
|
||||||
|
// exists at login-time. If it does the token that is created is directly
|
||||||
|
// linked to that policy like:
|
||||||
|
//
|
||||||
|
// &ACLToken{
|
||||||
|
// ...other fields...
|
||||||
|
// Policies: *ACLTokenPolicyLink{
|
||||||
|
// { Name: "<computed BindName>" },
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// If it does not exist at login-time the rule is ignored.
|
||||||
|
BindingRuleBindTypePolicy = "policy"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ACLBindingRule struct {
|
type ACLBindingRule struct {
|
||||||
|
@ -1106,6 +1121,7 @@ type ACLBindingRule struct {
|
||||||
// - BindingRuleBindTypeService = "service"
|
// - BindingRuleBindTypeService = "service"
|
||||||
// - BindingRuleBindTypeNode = "node"
|
// - BindingRuleBindTypeNode = "node"
|
||||||
// - BindingRuleBindTypeRole = "role"
|
// - BindingRuleBindTypeRole = "role"
|
||||||
|
// - BindingRuleBindTypePolicy = "policy"
|
||||||
// - BindingRuleBindTypeTemplatedPolicy = "templated-policy"
|
// - BindingRuleBindTypeTemplatedPolicy = "templated-policy"
|
||||||
BindType string
|
BindType string
|
||||||
|
|
||||||
|
|
|
@ -253,6 +253,9 @@ const (
|
||||||
// BindingRuleBindTypeNode binds to a node identity with given name.
|
// BindingRuleBindTypeNode binds to a node identity with given name.
|
||||||
BindingRuleBindTypeNode BindingRuleBindType = "node"
|
BindingRuleBindTypeNode BindingRuleBindType = "node"
|
||||||
|
|
||||||
|
// BindingRuleBindTypePolicy binds to a specific policy with given name.
|
||||||
|
BindingRuleBindTypePolicy BindingRuleBindType = "policy"
|
||||||
|
|
||||||
// BindingRuleBindTypeTemplatedPolicy binds to a templated policy with given template name and variables.
|
// BindingRuleBindTypeTemplatedPolicy binds to a templated policy with given template name and variables.
|
||||||
BindingRuleBindTypeTemplatedPolicy BindingRuleBindType = "templated-policy"
|
BindingRuleBindTypeTemplatedPolicy BindingRuleBindType = "templated-policy"
|
||||||
)
|
)
|
||||||
|
|
|
@ -73,7 +73,7 @@ func (c *cmd) init() {
|
||||||
&c.bindType,
|
&c.bindType,
|
||||||
"bind-type",
|
"bind-type",
|
||||||
string(api.BindingRuleBindTypeService),
|
string(api.BindingRuleBindTypeService),
|
||||||
"Type of binding to perform (\"service\", \"role\", \"node\" or \"templated-policy\").",
|
"Type of binding to perform (\"service\", \"role\", \"node\", \"policy\", or \"templated-policy\").",
|
||||||
)
|
)
|
||||||
c.flags.Var(
|
c.flags.Var(
|
||||||
(*flags.FlagMapValue)(&c.bindVars),
|
(*flags.FlagMapValue)(&c.bindVars),
|
||||||
|
|
|
@ -77,7 +77,7 @@ func (c *cmd) init() {
|
||||||
&c.bindType,
|
&c.bindType,
|
||||||
"bind-type",
|
"bind-type",
|
||||||
string(api.BindingRuleBindTypeService),
|
string(api.BindingRuleBindTypeService),
|
||||||
"Type of binding to perform (\"service\" or \"role\").",
|
"Type of binding to perform (\"service\", \"policy\", or \"role\").",
|
||||||
)
|
)
|
||||||
c.flags.StringVar(
|
c.flags.StringVar(
|
||||||
&c.bindName,
|
&c.bindName,
|
||||||
|
|
|
@ -242,6 +242,39 @@ func TestBindingRuleUpdateCommand(t *testing.T) {
|
||||||
require.Equal(t, "serviceaccount.namespace==alt and serviceaccount.name==demo", rule.Selector)
|
require.Equal(t, "serviceaccount.namespace==alt and serviceaccount.name==demo", rule.Selector)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("update all fields with policy", func(t *testing.T) {
|
||||||
|
id := createRule(t, false)
|
||||||
|
|
||||||
|
ui := cli.NewMockUi()
|
||||||
|
cmd := New(ui)
|
||||||
|
|
||||||
|
args := []string{
|
||||||
|
"-http-addr=" + a.HTTPAddr(),
|
||||||
|
"-token=root",
|
||||||
|
"-id", id,
|
||||||
|
"-description=test rule edited",
|
||||||
|
"-bind-type", "policy",
|
||||||
|
"-bind-name=policy-updated",
|
||||||
|
"-selector=serviceaccount.namespace==alt and serviceaccount.name==demo",
|
||||||
|
}
|
||||||
|
|
||||||
|
code := cmd.Run(args)
|
||||||
|
require.Equal(t, code, 0, "err: %s", ui.ErrorWriter.String())
|
||||||
|
require.Empty(t, ui.ErrorWriter.String())
|
||||||
|
|
||||||
|
rule, _, err := client.ACL().BindingRuleRead(
|
||||||
|
id,
|
||||||
|
&api.QueryOptions{Token: "root"},
|
||||||
|
)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotNil(t, rule)
|
||||||
|
|
||||||
|
require.Equal(t, "test rule edited", rule.Description)
|
||||||
|
require.Equal(t, "policy-updated", rule.BindName)
|
||||||
|
require.Equal(t, api.BindingRuleBindTypePolicy, rule.BindType)
|
||||||
|
require.Equal(t, "serviceaccount.namespace==alt and serviceaccount.name==demo", rule.Selector)
|
||||||
|
})
|
||||||
|
|
||||||
t.Run("update all fields with templated policy", func(t *testing.T) {
|
t.Run("update all fields with templated policy", func(t *testing.T) {
|
||||||
id := createRule(t, false)
|
id := createRule(t, false)
|
||||||
|
|
||||||
|
|
|
@ -89,4 +89,4 @@ Description: just vault role
|
||||||
BindType: role
|
BindType: role
|
||||||
BindName: vault
|
BindName: vault
|
||||||
Selector: serviceaccount.namespace==default and serviceaccount.name==vault
|
Selector: serviceaccount.namespace==default and serviceaccount.name==vault
|
||||||
```
|
```
|
Loading…
Reference in New Issue