diff --git a/gatekeeper.go b/gatekeeper.go index ecf00af..c9f001a 100644 --- a/gatekeeper.go +++ b/gatekeeper.go @@ -592,7 +592,7 @@ func (g *Gatekeeper) RenewalWorker(controlChan chan struct{}) { if err := g.RenewToken(); err == nil { log.Infof("Renewed Vault Token (original ttl: %v)", ttl) } else { - log.Warn("Failed to renew Vault token. Is the policy set correctly? Gatekeeper will now be sealed: %v", err) + log.Warnf("Failed to renew Vault token. Is the policy set correctly? Gatekeeper will now be sealed: %v", err) g.Seal() return } diff --git a/policy/policy.go b/policy/policy.go index ff4c800..03b3b1e 100644 --- a/policy/policy.go +++ b/policy/policy.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/json" "errors" + "regexp" "strings" log "github.com/sirupsen/logrus" @@ -13,9 +14,10 @@ import ( type Policy struct { Roles []string `json:"roles"` + Regexp string `json:"regexp,omitempty"` NumUses int `json:"num_uses"` strictestPath []byte - wildcard bool + regexp *regexp.Regexp } func (p *Policy) merge(path []byte, other Policy) { @@ -54,18 +56,26 @@ func LoadPoliciesFromJson(data []byte) (*Policies, error) { tree := iradix.New() txn := tree.Txn() for k, v := range pol { - if strings.HasSuffix(k, "*") { - v.wildcard = true - } if strings.HasSuffix(k, ":") { return nil, errors.New("Invalid key name '" + k + "'. Keys must not end with a ':'") } if v.NumUses < 1 { return nil, errors.New("Invalid num_uses for key '" + k + "'.") } + wildcard := false if k != "*" { + wildcard = strings.HasSuffix(k, "*") k = strings.TrimSuffix(k, "*") } + if wildcard { + v.Regexp = k + v.Regexp + } + if v.Regexp != "" { + v.regexp, err = regexp.Compile(v.Regexp) + if err != nil { + return nil, errors.New("Invalid regexp for key '" + k + "'.") + } + } txn.Insert([]byte(k), v) } tree = txn.Commit() @@ -85,12 +95,14 @@ func (p *Policies) Get(path string) (*Policy, bool) { walkFn := func(k []byte, _v interface{}) bool { v := _v.(Policy) - if v.wildcard && bytes.HasPrefix([]byte(path), k) { - ret.merge(k, v) - foundPolicy = true - } else if bytes.Equal(k, []byte(path)) { + if bytes.Equal(k, []byte(path)) { ret.merge(k, v) foundPolicy = true + } else if v.regexp != nil { + if v.regexp.MatchString(path) { + ret.merge(k, v) + foundPolicy = true + } } return false diff --git a/policy/policy_test.go b/policy/policy_test.go index 81fa5d8..ab2d28b 100644 --- a/policy/policy_test.go +++ b/policy/policy_test.go @@ -40,6 +40,11 @@ const samplePolicy = `{ "mesos:framework:service/*": { "roles":["mesos_framework_service"], "num_uses":1 + }, + "mesos:marathone:*":{ + "roles":["mesos_marathone_taskA"], + "regexp":"\\d{4}\\w{2}\\.taskA", + "num_uses":1 } }` @@ -91,6 +96,10 @@ func TestSamplePolicy(t *testing.T) { t.Fatalf("Test of '%s' failed. 'task2' should not conatain permission of 'task'. Had: %v", "mesos:framework:task", actual) } + if pass, _, actual := shouldContainAll(mustGet(pols.Get("mesos:marathone:6668wz.taskA")), "mesos_child", "mesos_marathone_taskA"); pass { + t.Fatalf("Test of '%s' failed. 'task2' should not conatain permission of 'task'. Had: %v", "mesos:framework:task", actual) + } + if policy, ok := pols.Get("mesos:framework:task"); ok { if policy.Roles[0] != "mesos_framework_task" { t.Fatalf("Expected most specific role of '%s'. Had: %v", "mesos:framework:task", policy.Roles[0])