1package consul 2 3import ( 4 "fmt" 5 6 "github.com/hashicorp/consul/agent/consul/authmethod" 7 "github.com/hashicorp/consul/agent/structs" 8 "github.com/hashicorp/go-bexpr" 9 10 // register these as a builtin auth method 11 _ "github.com/hashicorp/consul/agent/consul/authmethod/kubeauth" 12 _ "github.com/hashicorp/consul/agent/consul/authmethod/ssoauth" 13) 14 15type authMethodValidatorEntry struct { 16 Validator authmethod.Validator 17 ModifyIndex uint64 // the raft index when this last changed 18} 19 20// loadAuthMethodValidator returns an authmethod.Validator for the given auth 21// method configuration. If the cache is up to date as-of the provided index 22// then the cached version is returned, otherwise a new validator is created 23// and cached. 24func (s *Server) loadAuthMethodValidator(idx uint64, method *structs.ACLAuthMethod) (authmethod.Validator, error) { 25 if prevIdx, v, ok := s.aclAuthMethodValidators.GetValidator(method); ok && idx <= prevIdx { 26 return v, nil 27 } 28 29 v, err := authmethod.NewValidator(s.logger, method) 30 if err != nil { 31 return nil, fmt.Errorf("auth method validator for %q could not be initialized: %v", method.Name, err) 32 } 33 34 v = s.aclAuthMethodValidators.PutValidatorIfNewer(method, v, idx) 35 36 return v, nil 37} 38 39type aclBindings struct { 40 roles []structs.ACLTokenRoleLink 41 serviceIdentities []*structs.ACLServiceIdentity 42 nodeIdentities []*structs.ACLNodeIdentity 43} 44 45// evaluateRoleBindings evaluates all current binding rules associated with the 46// given auth method against the verified data returned from the authentication 47// process. 48// 49// A list of role links and service identities are returned. 50func (s *Server) evaluateRoleBindings( 51 validator authmethod.Validator, 52 verifiedIdentity *authmethod.Identity, 53 methodMeta *structs.EnterpriseMeta, 54 targetMeta *structs.EnterpriseMeta, 55) (*aclBindings, error) { 56 // Only fetch rules that are relevant for this method. 57 _, rules, err := s.fsm.State().ACLBindingRuleList(nil, validator.Name(), methodMeta) 58 if err != nil { 59 return nil, err 60 } else if len(rules) == 0 { 61 return nil, nil 62 } 63 64 // Find all binding rules that match the provided fields. 65 var matchingRules []*structs.ACLBindingRule 66 for _, rule := range rules { 67 if doesSelectorMatch(rule.Selector, verifiedIdentity.SelectableFields) { 68 matchingRules = append(matchingRules, rule) 69 } 70 } 71 if len(matchingRules) == 0 { 72 return nil, nil 73 } 74 75 // For all matching rules compute the attributes of a token. 76 var bindings aclBindings 77 for _, rule := range matchingRules { 78 bindName, valid, err := computeBindingRuleBindName(rule.BindType, rule.BindName, verifiedIdentity.ProjectedVars) 79 if err != nil { 80 return nil, fmt.Errorf("cannot compute %q bind name for bind target: %v", rule.BindType, err) 81 } else if !valid { 82 return nil, fmt.Errorf("computed %q bind name for bind target is invalid: %q", rule.BindType, bindName) 83 } 84 85 switch rule.BindType { 86 case structs.BindingRuleBindTypeService: 87 bindings.serviceIdentities = append(bindings.serviceIdentities, &structs.ACLServiceIdentity{ 88 ServiceName: bindName, 89 }) 90 91 case structs.BindingRuleBindTypeNode: 92 bindings.nodeIdentities = append(bindings.nodeIdentities, &structs.ACLNodeIdentity{ 93 NodeName: bindName, 94 Datacenter: s.config.Datacenter, 95 }) 96 97 case structs.BindingRuleBindTypeRole: 98 _, role, err := s.fsm.State().ACLRoleGetByName(nil, bindName, targetMeta) 99 if err != nil { 100 return nil, err 101 } 102 103 if role != nil { 104 bindings.roles = append(bindings.roles, structs.ACLTokenRoleLink{ 105 ID: role.ID, 106 }) 107 } 108 109 default: 110 // skip unknown bind type; don't grant privileges 111 } 112 } 113 114 return &bindings, nil 115} 116 117// doesSelectorMatch checks that a single selector matches the provided vars. 118func doesSelectorMatch(selector string, selectableVars interface{}) bool { 119 if selector == "" { 120 return true // catch-all 121 } 122 123 eval, err := bexpr.CreateEvaluatorForType(selector, nil, selectableVars) 124 if err != nil { 125 return false // fails to match if selector is invalid 126 } 127 128 result, err := eval.Evaluate(selectableVars) 129 if err != nil { 130 return false // fails to match if evaluation fails 131 } 132 133 return result 134} 135