mirror of https://github.com/k3s-io/k3s
move authorizers over to new interface
parent
ee4d2d0a94
commit
12125455d8
|
@ -221,13 +221,13 @@ func resourceMatches(p abac.Policy, a authorizer.Attributes) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Authorizer implements authorizer.Authorize
|
// Authorizer implements authorizer.Authorize
|
||||||
func (pl policyList) Authorize(a authorizer.Attributes) (bool, string, error) {
|
func (pl policyList) Authorize(a authorizer.Attributes) (authorizer.Decision, string, error) {
|
||||||
for _, p := range pl {
|
for _, p := range pl {
|
||||||
if matches(*p, a) {
|
if matches(*p, a) {
|
||||||
return true, "", nil
|
return authorizer.DecisionAllow, "", nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false, "No policy matched.", nil
|
return authorizer.DecisionNoOpinion, "No policy matched.", nil
|
||||||
// TODO: Benchmark how much time policy matching takes with a medium size
|
// TODO: Benchmark how much time policy matching takes with a medium size
|
||||||
// policy file, compared to other steps such as encoding/decoding.
|
// policy file, compared to other steps such as encoding/decoding.
|
||||||
// Then, add Caching only if needed.
|
// Then, add Caching only if needed.
|
||||||
|
|
|
@ -81,46 +81,46 @@ func TestAuthorizeV0(t *testing.T) {
|
||||||
uChuck := user.DefaultInfo{Name: "chuck", UID: "uid5", Groups: authenticatedGroup}
|
uChuck := user.DefaultInfo{Name: "chuck", UID: "uid5", Groups: authenticatedGroup}
|
||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
User user.DefaultInfo
|
User user.DefaultInfo
|
||||||
Verb string
|
Verb string
|
||||||
Resource string
|
Resource string
|
||||||
NS string
|
NS string
|
||||||
APIGroup string
|
APIGroup string
|
||||||
Path string
|
Path string
|
||||||
ExpectAllow bool
|
ExpectDecision authorizer.Decision
|
||||||
}{
|
}{
|
||||||
// Scheduler can read pods
|
// Scheduler can read pods
|
||||||
{User: uScheduler, Verb: "list", Resource: "pods", NS: "ns1", ExpectAllow: true},
|
{User: uScheduler, Verb: "list", Resource: "pods", NS: "ns1", ExpectDecision: authorizer.DecisionAllow},
|
||||||
{User: uScheduler, Verb: "list", Resource: "pods", NS: "", ExpectAllow: true},
|
{User: uScheduler, Verb: "list", Resource: "pods", NS: "", ExpectDecision: authorizer.DecisionAllow},
|
||||||
// Scheduler cannot write pods
|
// Scheduler cannot write pods
|
||||||
{User: uScheduler, Verb: "create", Resource: "pods", NS: "ns1", ExpectAllow: false},
|
{User: uScheduler, Verb: "create", Resource: "pods", NS: "ns1", ExpectDecision: authorizer.DecisionNoOpinion},
|
||||||
{User: uScheduler, Verb: "create", Resource: "pods", NS: "", ExpectAllow: false},
|
{User: uScheduler, Verb: "create", Resource: "pods", NS: "", ExpectDecision: authorizer.DecisionNoOpinion},
|
||||||
// Scheduler can write bindings
|
// Scheduler can write bindings
|
||||||
{User: uScheduler, Verb: "get", Resource: "bindings", NS: "ns1", ExpectAllow: true},
|
{User: uScheduler, Verb: "get", Resource: "bindings", NS: "ns1", ExpectDecision: authorizer.DecisionAllow},
|
||||||
{User: uScheduler, Verb: "get", Resource: "bindings", NS: "", ExpectAllow: true},
|
{User: uScheduler, Verb: "get", Resource: "bindings", NS: "", ExpectDecision: authorizer.DecisionAllow},
|
||||||
|
|
||||||
// Alice can read and write anything in the right namespace.
|
// Alice can read and write anything in the right namespace.
|
||||||
{User: uAlice, Verb: "get", Resource: "pods", NS: "projectCaribou", ExpectAllow: true},
|
{User: uAlice, Verb: "get", Resource: "pods", NS: "projectCaribou", ExpectDecision: authorizer.DecisionAllow},
|
||||||
{User: uAlice, Verb: "get", Resource: "widgets", NS: "projectCaribou", ExpectAllow: true},
|
{User: uAlice, Verb: "get", Resource: "widgets", NS: "projectCaribou", ExpectDecision: authorizer.DecisionAllow},
|
||||||
{User: uAlice, Verb: "get", Resource: "", NS: "projectCaribou", ExpectAllow: true},
|
{User: uAlice, Verb: "get", Resource: "", NS: "projectCaribou", ExpectDecision: authorizer.DecisionAllow},
|
||||||
{User: uAlice, Verb: "update", Resource: "pods", NS: "projectCaribou", ExpectAllow: true},
|
{User: uAlice, Verb: "update", Resource: "pods", NS: "projectCaribou", ExpectDecision: authorizer.DecisionAllow},
|
||||||
{User: uAlice, Verb: "update", Resource: "widgets", NS: "projectCaribou", ExpectAllow: true},
|
{User: uAlice, Verb: "update", Resource: "widgets", NS: "projectCaribou", ExpectDecision: authorizer.DecisionAllow},
|
||||||
{User: uAlice, Verb: "update", Resource: "", NS: "projectCaribou", ExpectAllow: true},
|
{User: uAlice, Verb: "update", Resource: "", NS: "projectCaribou", ExpectDecision: authorizer.DecisionAllow},
|
||||||
{User: uAlice, Verb: "update", Resource: "foo", NS: "projectCaribou", APIGroup: "bar", ExpectAllow: true},
|
{User: uAlice, Verb: "update", Resource: "foo", NS: "projectCaribou", APIGroup: "bar", ExpectDecision: authorizer.DecisionAllow},
|
||||||
// .. but not the wrong namespace.
|
// .. but not the wrong namespace.
|
||||||
{User: uAlice, Verb: "get", Resource: "pods", NS: "ns1", ExpectAllow: false},
|
{User: uAlice, Verb: "get", Resource: "pods", NS: "ns1", ExpectDecision: authorizer.DecisionNoOpinion},
|
||||||
{User: uAlice, Verb: "get", Resource: "widgets", NS: "ns1", ExpectAllow: false},
|
{User: uAlice, Verb: "get", Resource: "widgets", NS: "ns1", ExpectDecision: authorizer.DecisionNoOpinion},
|
||||||
{User: uAlice, Verb: "get", Resource: "", NS: "ns1", ExpectAllow: false},
|
{User: uAlice, Verb: "get", Resource: "", NS: "ns1", ExpectDecision: authorizer.DecisionNoOpinion},
|
||||||
|
|
||||||
// Chuck can read events, since anyone can.
|
// Chuck can read events, since anyone can.
|
||||||
{User: uChuck, Verb: "get", Resource: "events", NS: "ns1", ExpectAllow: true},
|
{User: uChuck, Verb: "get", Resource: "events", NS: "ns1", ExpectDecision: authorizer.DecisionAllow},
|
||||||
{User: uChuck, Verb: "get", Resource: "events", NS: "", ExpectAllow: true},
|
{User: uChuck, Verb: "get", Resource: "events", NS: "", ExpectDecision: authorizer.DecisionAllow},
|
||||||
// Chuck can't do other things.
|
// Chuck can't do other things.
|
||||||
{User: uChuck, Verb: "update", Resource: "events", NS: "ns1", ExpectAllow: false},
|
{User: uChuck, Verb: "update", Resource: "events", NS: "ns1", ExpectDecision: authorizer.DecisionNoOpinion},
|
||||||
{User: uChuck, Verb: "get", Resource: "pods", NS: "ns1", ExpectAllow: false},
|
{User: uChuck, Verb: "get", Resource: "pods", NS: "ns1", ExpectDecision: authorizer.DecisionNoOpinion},
|
||||||
{User: uChuck, Verb: "get", Resource: "floop", NS: "ns1", ExpectAllow: false},
|
{User: uChuck, Verb: "get", Resource: "floop", NS: "ns1", ExpectDecision: authorizer.DecisionNoOpinion},
|
||||||
// Chunk can't access things with no kind or namespace
|
// Chunk can't access things with no kind or namespace
|
||||||
{User: uChuck, Verb: "get", Path: "/", Resource: "", NS: "", ExpectAllow: false},
|
{User: uChuck, Verb: "get", Path: "/", Resource: "", NS: "", ExpectDecision: authorizer.DecisionNoOpinion},
|
||||||
}
|
}
|
||||||
for i, tc := range testCases {
|
for i, tc := range testCases {
|
||||||
attr := authorizer.AttributesRecord{
|
attr := authorizer.AttributesRecord{
|
||||||
|
@ -133,11 +133,11 @@ func TestAuthorizeV0(t *testing.T) {
|
||||||
|
|
||||||
ResourceRequest: len(tc.NS) > 0 || len(tc.Resource) > 0,
|
ResourceRequest: len(tc.NS) > 0 || len(tc.Resource) > 0,
|
||||||
}
|
}
|
||||||
authorized, _, _ := a.Authorize(attr)
|
decision, _, _ := a.Authorize(attr)
|
||||||
if tc.ExpectAllow != authorized {
|
if tc.ExpectDecision != decision {
|
||||||
t.Logf("tc: %v -> attr %v", tc, attr)
|
t.Logf("tc: %v -> attr %v", tc, attr)
|
||||||
t.Errorf("%d: Expected allowed=%v but actually allowed=%v\n\t%v",
|
t.Errorf("%d: Expected allowed=%v but actually allowed=%v\n\t%v",
|
||||||
i, tc.ExpectAllow, authorized, tc)
|
i, tc.ExpectDecision, decision, tc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -373,72 +373,72 @@ func TestAuthorizeV1beta1(t *testing.T) {
|
||||||
uAPIGroup := user.DefaultInfo{Name: "apigroupuser", UID: "uid8", Groups: authenticatedGroup}
|
uAPIGroup := user.DefaultInfo{Name: "apigroupuser", UID: "uid8", Groups: authenticatedGroup}
|
||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
User user.DefaultInfo
|
User user.DefaultInfo
|
||||||
Verb string
|
Verb string
|
||||||
Resource string
|
Resource string
|
||||||
APIGroup string
|
APIGroup string
|
||||||
NS string
|
NS string
|
||||||
Path string
|
Path string
|
||||||
ExpectAllow bool
|
ExpectDecision authorizer.Decision
|
||||||
}{
|
}{
|
||||||
// Scheduler can read pods
|
// Scheduler can read pods
|
||||||
{User: uScheduler, Verb: "list", Resource: "pods", NS: "ns1", ExpectAllow: true},
|
{User: uScheduler, Verb: "list", Resource: "pods", NS: "ns1", ExpectDecision: authorizer.DecisionAllow},
|
||||||
{User: uScheduler, Verb: "list", Resource: "pods", NS: "", ExpectAllow: true},
|
{User: uScheduler, Verb: "list", Resource: "pods", NS: "", ExpectDecision: authorizer.DecisionAllow},
|
||||||
// Scheduler cannot write pods
|
// Scheduler cannot write pods
|
||||||
{User: uScheduler, Verb: "create", Resource: "pods", NS: "ns1", ExpectAllow: false},
|
{User: uScheduler, Verb: "create", Resource: "pods", NS: "ns1", ExpectDecision: authorizer.DecisionNoOpinion},
|
||||||
{User: uScheduler, Verb: "create", Resource: "pods", NS: "", ExpectAllow: false},
|
{User: uScheduler, Verb: "create", Resource: "pods", NS: "", ExpectDecision: authorizer.DecisionNoOpinion},
|
||||||
// Scheduler can write bindings
|
// Scheduler can write bindings
|
||||||
{User: uScheduler, Verb: "get", Resource: "bindings", NS: "ns1", ExpectAllow: true},
|
{User: uScheduler, Verb: "get", Resource: "bindings", NS: "ns1", ExpectDecision: authorizer.DecisionAllow},
|
||||||
{User: uScheduler, Verb: "get", Resource: "bindings", NS: "", ExpectAllow: true},
|
{User: uScheduler, Verb: "get", Resource: "bindings", NS: "", ExpectDecision: authorizer.DecisionAllow},
|
||||||
|
|
||||||
// Alice can read and write anything in the right namespace.
|
// Alice can read and write anything in the right namespace.
|
||||||
{User: uAlice, Verb: "get", Resource: "pods", NS: "projectCaribou", ExpectAllow: true},
|
{User: uAlice, Verb: "get", Resource: "pods", NS: "projectCaribou", ExpectDecision: authorizer.DecisionAllow},
|
||||||
{User: uAlice, Verb: "get", Resource: "widgets", NS: "projectCaribou", ExpectAllow: true},
|
{User: uAlice, Verb: "get", Resource: "widgets", NS: "projectCaribou", ExpectDecision: authorizer.DecisionAllow},
|
||||||
{User: uAlice, Verb: "get", Resource: "", NS: "projectCaribou", ExpectAllow: true},
|
{User: uAlice, Verb: "get", Resource: "", NS: "projectCaribou", ExpectDecision: authorizer.DecisionAllow},
|
||||||
{User: uAlice, Verb: "update", Resource: "pods", NS: "projectCaribou", ExpectAllow: true},
|
{User: uAlice, Verb: "update", Resource: "pods", NS: "projectCaribou", ExpectDecision: authorizer.DecisionAllow},
|
||||||
{User: uAlice, Verb: "update", Resource: "widgets", NS: "projectCaribou", ExpectAllow: true},
|
{User: uAlice, Verb: "update", Resource: "widgets", NS: "projectCaribou", ExpectDecision: authorizer.DecisionAllow},
|
||||||
{User: uAlice, Verb: "update", Resource: "", NS: "projectCaribou", ExpectAllow: true},
|
{User: uAlice, Verb: "update", Resource: "", NS: "projectCaribou", ExpectDecision: authorizer.DecisionAllow},
|
||||||
// .. but not the wrong namespace.
|
// .. but not the wrong namespace.
|
||||||
{User: uAlice, Verb: "get", Resource: "pods", NS: "ns1", ExpectAllow: false},
|
{User: uAlice, Verb: "get", Resource: "pods", NS: "ns1", ExpectDecision: authorizer.DecisionNoOpinion},
|
||||||
{User: uAlice, Verb: "get", Resource: "widgets", NS: "ns1", ExpectAllow: false},
|
{User: uAlice, Verb: "get", Resource: "widgets", NS: "ns1", ExpectDecision: authorizer.DecisionNoOpinion},
|
||||||
{User: uAlice, Verb: "get", Resource: "", NS: "ns1", ExpectAllow: false},
|
{User: uAlice, Verb: "get", Resource: "", NS: "ns1", ExpectDecision: authorizer.DecisionNoOpinion},
|
||||||
|
|
||||||
// Debbie can write to pods in the right namespace
|
// Debbie can write to pods in the right namespace
|
||||||
{User: uDebbie, Verb: "update", Resource: "pods", NS: "projectCaribou", ExpectAllow: true},
|
{User: uDebbie, Verb: "update", Resource: "pods", NS: "projectCaribou", ExpectDecision: authorizer.DecisionAllow},
|
||||||
|
|
||||||
// Chuck can read events, since anyone can.
|
// Chuck can read events, since anyone can.
|
||||||
{User: uChuck, Verb: "get", Resource: "events", NS: "ns1", ExpectAllow: true},
|
{User: uChuck, Verb: "get", Resource: "events", NS: "ns1", ExpectDecision: authorizer.DecisionAllow},
|
||||||
{User: uChuck, Verb: "get", Resource: "events", NS: "", ExpectAllow: true},
|
{User: uChuck, Verb: "get", Resource: "events", NS: "", ExpectDecision: authorizer.DecisionAllow},
|
||||||
// Chuck can't do other things.
|
// Chuck can't do other things.
|
||||||
{User: uChuck, Verb: "update", Resource: "events", NS: "ns1", ExpectAllow: false},
|
{User: uChuck, Verb: "update", Resource: "events", NS: "ns1", ExpectDecision: authorizer.DecisionNoOpinion},
|
||||||
{User: uChuck, Verb: "get", Resource: "pods", NS: "ns1", ExpectAllow: false},
|
{User: uChuck, Verb: "get", Resource: "pods", NS: "ns1", ExpectDecision: authorizer.DecisionNoOpinion},
|
||||||
{User: uChuck, Verb: "get", Resource: "floop", NS: "ns1", ExpectAllow: false},
|
{User: uChuck, Verb: "get", Resource: "floop", NS: "ns1", ExpectDecision: authorizer.DecisionNoOpinion},
|
||||||
// Chuck can't access things with no resource or namespace
|
// Chuck can't access things with no resource or namespace
|
||||||
{User: uChuck, Verb: "get", Path: "/", Resource: "", NS: "", ExpectAllow: false},
|
{User: uChuck, Verb: "get", Path: "/", Resource: "", NS: "", ExpectDecision: authorizer.DecisionNoOpinion},
|
||||||
// but can access /api
|
// but can access /api
|
||||||
{User: uChuck, Verb: "get", Path: "/api", Resource: "", NS: "", ExpectAllow: true},
|
{User: uChuck, Verb: "get", Path: "/api", Resource: "", NS: "", ExpectDecision: authorizer.DecisionAllow},
|
||||||
// though he cannot write to it
|
// though he cannot write to it
|
||||||
{User: uChuck, Verb: "create", Path: "/api", Resource: "", NS: "", ExpectAllow: false},
|
{User: uChuck, Verb: "create", Path: "/api", Resource: "", NS: "", ExpectDecision: authorizer.DecisionNoOpinion},
|
||||||
// while he can write to /custom
|
// while he can write to /custom
|
||||||
{User: uChuck, Verb: "update", Path: "/custom", Resource: "", NS: "", ExpectAllow: true},
|
{User: uChuck, Verb: "update", Path: "/custom", Resource: "", NS: "", ExpectDecision: authorizer.DecisionAllow},
|
||||||
// he cannot get "/root"
|
// he cannot get "/root"
|
||||||
{User: uChuck, Verb: "get", Path: "/root", Resource: "", NS: "", ExpectAllow: false},
|
{User: uChuck, Verb: "get", Path: "/root", Resource: "", NS: "", ExpectDecision: authorizer.DecisionNoOpinion},
|
||||||
// but can get any subpath
|
// but can get any subpath
|
||||||
{User: uChuck, Verb: "get", Path: "/root/", Resource: "", NS: "", ExpectAllow: true},
|
{User: uChuck, Verb: "get", Path: "/root/", Resource: "", NS: "", ExpectDecision: authorizer.DecisionAllow},
|
||||||
{User: uChuck, Verb: "get", Path: "/root/test/1/2/3", Resource: "", NS: "", ExpectAllow: true},
|
{User: uChuck, Verb: "get", Path: "/root/test/1/2/3", Resource: "", NS: "", ExpectDecision: authorizer.DecisionAllow},
|
||||||
|
|
||||||
// the user "noresource" can get any non-resource request
|
// the user "noresource" can get any non-resource request
|
||||||
{User: uNoResource, Verb: "get", Path: "", Resource: "", NS: "", ExpectAllow: true},
|
{User: uNoResource, Verb: "get", Path: "", Resource: "", NS: "", ExpectDecision: authorizer.DecisionAllow},
|
||||||
{User: uNoResource, Verb: "get", Path: "/", Resource: "", NS: "", ExpectAllow: true},
|
{User: uNoResource, Verb: "get", Path: "/", Resource: "", NS: "", ExpectDecision: authorizer.DecisionAllow},
|
||||||
{User: uNoResource, Verb: "get", Path: "/foo/bar/baz", Resource: "", NS: "", ExpectAllow: true},
|
{User: uNoResource, Verb: "get", Path: "/foo/bar/baz", Resource: "", NS: "", ExpectDecision: authorizer.DecisionAllow},
|
||||||
// but cannot get any request where IsResourceRequest() == true
|
// but cannot get any request where IsResourceRequest() == true
|
||||||
{User: uNoResource, Verb: "get", Path: "/", Resource: "", NS: "bar", ExpectAllow: false},
|
{User: uNoResource, Verb: "get", Path: "/", Resource: "", NS: "bar", ExpectDecision: authorizer.DecisionNoOpinion},
|
||||||
{User: uNoResource, Verb: "get", Path: "/foo/bar/baz", Resource: "foo", NS: "bar", ExpectAllow: false},
|
{User: uNoResource, Verb: "get", Path: "/foo/bar/baz", Resource: "foo", NS: "bar", ExpectDecision: authorizer.DecisionNoOpinion},
|
||||||
|
|
||||||
// Test APIGroup matching
|
// Test APIGroup matching
|
||||||
{User: uAPIGroup, Verb: "get", APIGroup: "x", Resource: "foo", NS: "projectAnyGroup", ExpectAllow: true},
|
{User: uAPIGroup, Verb: "get", APIGroup: "x", Resource: "foo", NS: "projectAnyGroup", ExpectDecision: authorizer.DecisionAllow},
|
||||||
{User: uAPIGroup, Verb: "get", APIGroup: "x", Resource: "foo", NS: "projectEmptyGroup", ExpectAllow: false},
|
{User: uAPIGroup, Verb: "get", APIGroup: "x", Resource: "foo", NS: "projectEmptyGroup", ExpectDecision: authorizer.DecisionNoOpinion},
|
||||||
{User: uAPIGroup, Verb: "get", APIGroup: "x", Resource: "foo", NS: "projectXGroup", ExpectAllow: true},
|
{User: uAPIGroup, Verb: "get", APIGroup: "x", Resource: "foo", NS: "projectXGroup", ExpectDecision: authorizer.DecisionAllow},
|
||||||
}
|
}
|
||||||
for i, tc := range testCases {
|
for i, tc := range testCases {
|
||||||
attr := authorizer.AttributesRecord{
|
attr := authorizer.AttributesRecord{
|
||||||
|
@ -451,10 +451,10 @@ func TestAuthorizeV1beta1(t *testing.T) {
|
||||||
Path: tc.Path,
|
Path: tc.Path,
|
||||||
}
|
}
|
||||||
// t.Logf("tc %2v: %v -> attr %v", i, tc, attr)
|
// t.Logf("tc %2v: %v -> attr %v", i, tc, attr)
|
||||||
authorized, _, _ := a.Authorize(attr)
|
decision, _, _ := a.Authorize(attr)
|
||||||
if tc.ExpectAllow != authorized {
|
if tc.ExpectDecision != decision {
|
||||||
t.Errorf("%d: Expected allowed=%v but actually allowed=%v, for case %+v & %+v",
|
t.Errorf("%d: Expected allowed=%v but actually allowed=%v, for case %+v & %+v",
|
||||||
i, tc.ExpectAllow, authorized, tc, attr)
|
i, tc.ExpectDecision, decision, tc, attr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -236,14 +236,14 @@ func (s *Server) InstallAuthFilter() {
|
||||||
attrs := s.auth.GetRequestAttributes(u, req.Request)
|
attrs := s.auth.GetRequestAttributes(u, req.Request)
|
||||||
|
|
||||||
// Authorize
|
// Authorize
|
||||||
authorized, _, err := s.auth.Authorize(attrs)
|
decision, _, err := s.auth.Authorize(attrs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
msg := fmt.Sprintf("Authorization error (user=%s, verb=%s, resource=%s, subresource=%s)", u.GetName(), attrs.GetVerb(), attrs.GetResource(), attrs.GetSubresource())
|
msg := fmt.Sprintf("Authorization error (user=%s, verb=%s, resource=%s, subresource=%s)", u.GetName(), attrs.GetVerb(), attrs.GetResource(), attrs.GetSubresource())
|
||||||
glog.Errorf(msg, err)
|
glog.Errorf(msg, err)
|
||||||
resp.WriteErrorString(http.StatusInternalServerError, msg)
|
resp.WriteErrorString(http.StatusInternalServerError, msg)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !authorized {
|
if decision != authorizer.DecisionAllow {
|
||||||
msg := fmt.Sprintf("Forbidden (user=%s, verb=%s, resource=%s, subresource=%s)", u.GetName(), attrs.GetVerb(), attrs.GetResource(), attrs.GetSubresource())
|
msg := fmt.Sprintf("Forbidden (user=%s, verb=%s, resource=%s, subresource=%s)", u.GetName(), attrs.GetVerb(), attrs.GetResource(), attrs.GetSubresource())
|
||||||
glog.V(2).Info(msg)
|
glog.V(2).Info(msg)
|
||||||
resp.WriteErrorString(http.StatusForbidden, msg)
|
resp.WriteErrorString(http.StatusForbidden, msg)
|
||||||
|
|
|
@ -183,7 +183,7 @@ func (_ *fakeKubelet) GetCgroupStats(cgroupName string) (*statsapi.ContainerStat
|
||||||
type fakeAuth struct {
|
type fakeAuth struct {
|
||||||
authenticateFunc func(*http.Request) (user.Info, bool, error)
|
authenticateFunc func(*http.Request) (user.Info, bool, error)
|
||||||
attributesFunc func(user.Info, *http.Request) authorizer.Attributes
|
attributesFunc func(user.Info, *http.Request) authorizer.Attributes
|
||||||
authorizeFunc func(authorizer.Attributes) (authorized bool, reason string, err error)
|
authorizeFunc func(authorizer.Attributes) (authorized authorizer.Decision, reason string, err error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *fakeAuth) AuthenticateRequest(req *http.Request) (user.Info, bool, error) {
|
func (f *fakeAuth) AuthenticateRequest(req *http.Request) (user.Info, bool, error) {
|
||||||
|
@ -192,7 +192,7 @@ func (f *fakeAuth) AuthenticateRequest(req *http.Request) (user.Info, bool, erro
|
||||||
func (f *fakeAuth) GetRequestAttributes(u user.Info, req *http.Request) authorizer.Attributes {
|
func (f *fakeAuth) GetRequestAttributes(u user.Info, req *http.Request) authorizer.Attributes {
|
||||||
return f.attributesFunc(u, req)
|
return f.attributesFunc(u, req)
|
||||||
}
|
}
|
||||||
func (f *fakeAuth) Authorize(a authorizer.Attributes) (authorized bool, reason string, err error) {
|
func (f *fakeAuth) Authorize(a authorizer.Attributes) (authorized authorizer.Decision, reason string, err error) {
|
||||||
return f.authorizeFunc(a)
|
return f.authorizeFunc(a)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -232,8 +232,8 @@ func newServerTestWithDebug(enableDebugging bool) *serverTestFramework {
|
||||||
attributesFunc: func(u user.Info, req *http.Request) authorizer.Attributes {
|
attributesFunc: func(u user.Info, req *http.Request) authorizer.Attributes {
|
||||||
return &authorizer.AttributesRecord{User: u}
|
return &authorizer.AttributesRecord{User: u}
|
||||||
},
|
},
|
||||||
authorizeFunc: func(a authorizer.Attributes) (authorized bool, reason string, err error) {
|
authorizeFunc: func(a authorizer.Attributes) (decision authorizer.Decision, reason string, err error) {
|
||||||
return true, "", nil
|
return authorizer.DecisionAllow, "", nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
fw.criHandler = &utiltesting.FakeHandler{
|
fw.criHandler = &utiltesting.FakeHandler{
|
||||||
|
@ -688,12 +688,12 @@ Otherwise, add it to the expected list of paths that map to the "proxy" subresou
|
||||||
}
|
}
|
||||||
return attributesGetter.GetRequestAttributes(u, req)
|
return attributesGetter.GetRequestAttributes(u, req)
|
||||||
}
|
}
|
||||||
fw.fakeAuth.authorizeFunc = func(a authorizer.Attributes) (authorized bool, reason string, err error) {
|
fw.fakeAuth.authorizeFunc = func(a authorizer.Attributes) (decision authorizer.Decision, reason string, err error) {
|
||||||
calledAuthorize = true
|
calledAuthorize = true
|
||||||
if a != expectedAttributes {
|
if a != expectedAttributes {
|
||||||
t.Fatalf("%s: expected attributes\n\t%#v\ngot\n\t%#v", tc.Path, expectedAttributes, a)
|
t.Fatalf("%s: expected attributes\n\t%#v\ngot\n\t%#v", tc.Path, expectedAttributes, a)
|
||||||
}
|
}
|
||||||
return false, "", nil
|
return authorizer.DecisionNoOpinion, "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
req, err := http.NewRequest(tc.Method, fw.testHTTPServer.URL+tc.Path, nil)
|
req, err := http.NewRequest(tc.Method, fw.testHTTPServer.URL+tc.Path, nil)
|
||||||
|
@ -747,9 +747,9 @@ func TestAuthenticationError(t *testing.T) {
|
||||||
calledAttributes = true
|
calledAttributes = true
|
||||||
return expectedAttributes
|
return expectedAttributes
|
||||||
}
|
}
|
||||||
fw.fakeAuth.authorizeFunc = func(a authorizer.Attributes) (authorized bool, reason string, err error) {
|
fw.fakeAuth.authorizeFunc = func(a authorizer.Attributes) (decision authorizer.Decision, reason string, err error) {
|
||||||
calledAuthorize = true
|
calledAuthorize = true
|
||||||
return false, "", errors.New("Failed")
|
return authorizer.DecisionNoOpinion, "", errors.New("Failed")
|
||||||
}
|
}
|
||||||
|
|
||||||
assertHealthFails(t, fw.testHTTPServer.URL+"/healthz", http.StatusInternalServerError)
|
assertHealthFails(t, fw.testHTTPServer.URL+"/healthz", http.StatusInternalServerError)
|
||||||
|
@ -785,9 +785,9 @@ func TestAuthenticationFailure(t *testing.T) {
|
||||||
calledAttributes = true
|
calledAttributes = true
|
||||||
return expectedAttributes
|
return expectedAttributes
|
||||||
}
|
}
|
||||||
fw.fakeAuth.authorizeFunc = func(a authorizer.Attributes) (authorized bool, reason string, err error) {
|
fw.fakeAuth.authorizeFunc = func(a authorizer.Attributes) (decision authorizer.Decision, reason string, err error) {
|
||||||
calledAuthorize = true
|
calledAuthorize = true
|
||||||
return false, "", nil
|
return authorizer.DecisionNoOpinion, "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
assertHealthFails(t, fw.testHTTPServer.URL+"/healthz", http.StatusUnauthorized)
|
assertHealthFails(t, fw.testHTTPServer.URL+"/healthz", http.StatusUnauthorized)
|
||||||
|
@ -823,9 +823,9 @@ func TestAuthorizationSuccess(t *testing.T) {
|
||||||
calledAttributes = true
|
calledAttributes = true
|
||||||
return expectedAttributes
|
return expectedAttributes
|
||||||
}
|
}
|
||||||
fw.fakeAuth.authorizeFunc = func(a authorizer.Attributes) (authorized bool, reason string, err error) {
|
fw.fakeAuth.authorizeFunc = func(a authorizer.Attributes) (decision authorizer.Decision, reason string, err error) {
|
||||||
calledAuthorize = true
|
calledAuthorize = true
|
||||||
return true, "", nil
|
return authorizer.DecisionAllow, "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
assertHealthIsOk(t, fw.testHTTPServer.URL+"/healthz")
|
assertHealthIsOk(t, fw.testHTTPServer.URL+"/healthz")
|
||||||
|
|
|
@ -58,10 +58,10 @@ func (r *REST) Create(ctx genericapirequest.Context, obj runtime.Object, createV
|
||||||
}
|
}
|
||||||
|
|
||||||
authorizationAttributes := authorizationutil.AuthorizationAttributesFrom(localSubjectAccessReview.Spec)
|
authorizationAttributes := authorizationutil.AuthorizationAttributesFrom(localSubjectAccessReview.Spec)
|
||||||
allowed, reason, evaluationErr := r.authorizer.Authorize(authorizationAttributes)
|
decision, reason, evaluationErr := r.authorizer.Authorize(authorizationAttributes)
|
||||||
|
|
||||||
localSubjectAccessReview.Status = authorizationapi.SubjectAccessReviewStatus{
|
localSubjectAccessReview.Status = authorizationapi.SubjectAccessReviewStatus{
|
||||||
Allowed: allowed,
|
Allowed: (decision == authorizer.DecisionAllow),
|
||||||
Reason: reason,
|
Reason: reason,
|
||||||
}
|
}
|
||||||
if evaluationErr != nil {
|
if evaluationErr != nil {
|
||||||
|
|
|
@ -61,10 +61,10 @@ func (r *REST) Create(ctx genericapirequest.Context, obj runtime.Object, createV
|
||||||
authorizationAttributes = authorizationutil.NonResourceAttributesFrom(userToCheck, *selfSAR.Spec.NonResourceAttributes)
|
authorizationAttributes = authorizationutil.NonResourceAttributesFrom(userToCheck, *selfSAR.Spec.NonResourceAttributes)
|
||||||
}
|
}
|
||||||
|
|
||||||
allowed, reason, evaluationErr := r.authorizer.Authorize(authorizationAttributes)
|
decision, reason, evaluationErr := r.authorizer.Authorize(authorizationAttributes)
|
||||||
|
|
||||||
selfSAR.Status = authorizationapi.SubjectAccessReviewStatus{
|
selfSAR.Status = authorizationapi.SubjectAccessReviewStatus{
|
||||||
Allowed: allowed,
|
Allowed: (decision == authorizer.DecisionAllow),
|
||||||
Reason: reason,
|
Reason: reason,
|
||||||
}
|
}
|
||||||
if evaluationErr != nil {
|
if evaluationErr != nil {
|
||||||
|
|
|
@ -51,10 +51,10 @@ func (r *REST) Create(ctx genericapirequest.Context, obj runtime.Object, createV
|
||||||
}
|
}
|
||||||
|
|
||||||
authorizationAttributes := authorizationutil.AuthorizationAttributesFrom(subjectAccessReview.Spec)
|
authorizationAttributes := authorizationutil.AuthorizationAttributesFrom(subjectAccessReview.Spec)
|
||||||
allowed, reason, evaluationErr := r.authorizer.Authorize(authorizationAttributes)
|
decision, reason, evaluationErr := r.authorizer.Authorize(authorizationAttributes)
|
||||||
|
|
||||||
subjectAccessReview.Status = authorizationapi.SubjectAccessReviewStatus{
|
subjectAccessReview.Status = authorizationapi.SubjectAccessReviewStatus{
|
||||||
Allowed: allowed,
|
Allowed: (decision == authorizer.DecisionAllow),
|
||||||
Reason: reason,
|
Reason: reason,
|
||||||
}
|
}
|
||||||
if evaluationErr != nil {
|
if evaluationErr != nil {
|
||||||
|
|
|
@ -38,9 +38,12 @@ type fakeAuthorizer struct {
|
||||||
err error
|
err error
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *fakeAuthorizer) Authorize(attrs authorizer.Attributes) (bool, string, error) {
|
func (f *fakeAuthorizer) Authorize(attrs authorizer.Attributes) (authorizer.Decision, string, error) {
|
||||||
f.attrs = attrs
|
f.attrs = attrs
|
||||||
return f.ok, f.reason, f.err
|
if f.ok {
|
||||||
|
return authorizer.DecisionAllow, f.reason, f.err
|
||||||
|
}
|
||||||
|
return authorizer.DecisionNoOpinion, f.reason, f.err
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCreate(t *testing.T) {
|
func TestCreate(t *testing.T) {
|
||||||
|
|
|
@ -79,12 +79,12 @@ func BindingAuthorized(ctx genericapirequest.Context, roleRef rbac.RoleRef, bind
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
ok, _, err := a.Authorize(attrs)
|
decision, _, err := a.Authorize(attrs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
utilruntime.HandleError(fmt.Errorf(
|
utilruntime.HandleError(fmt.Errorf(
|
||||||
"error authorizing user %#v to bind %#v in namespace %s: %v",
|
"error authorizing user %#v to bind %#v in namespace %s: %v",
|
||||||
user, roleRef, bindingNamespace, err,
|
user, roleRef, bindingNamespace, err,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
return ok
|
return decision == authorizer.DecisionAllow
|
||||||
}
|
}
|
||||||
|
|
|
@ -104,8 +104,8 @@ func (a *gcPermissionsEnforcement) Validate(attributes admission.Attributes) (er
|
||||||
ResourceRequest: true,
|
ResourceRequest: true,
|
||||||
Path: "",
|
Path: "",
|
||||||
}
|
}
|
||||||
allowed, reason, err := a.authorizer.Authorize(deleteAttributes)
|
decision, reason, err := a.authorizer.Authorize(deleteAttributes)
|
||||||
if !allowed {
|
if decision != authorizer.DecisionAllow {
|
||||||
return admission.NewForbidden(attributes, fmt.Errorf("cannot set an ownerRef on a resource you can't delete: %v, %v", reason, err))
|
return admission.NewForbidden(attributes, fmt.Errorf("cannot set an ownerRef on a resource you can't delete: %v, %v", reason, err))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -122,8 +122,8 @@ func (a *gcPermissionsEnforcement) Validate(attributes admission.Attributes) (er
|
||||||
// resources. User needs to have delete permission on all the
|
// resources. User needs to have delete permission on all the
|
||||||
// matched Resources.
|
// matched Resources.
|
||||||
for _, record := range records {
|
for _, record := range records {
|
||||||
allowed, reason, err := a.authorizer.Authorize(record)
|
decision, reason, err := a.authorizer.Authorize(record)
|
||||||
if !allowed {
|
if decision != authorizer.DecisionAllow {
|
||||||
return admission.NewForbidden(attributes, fmt.Errorf("cannot set blockOwnerDeletion if an ownerReference refers to a resource you can't set finalizers on: %v, %v", reason, err))
|
return admission.NewForbidden(attributes, fmt.Errorf("cannot set blockOwnerDeletion if an ownerReference refers to a resource you can't set finalizers on: %v, %v", reason, err))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,40 +34,40 @@ import (
|
||||||
|
|
||||||
type fakeAuthorizer struct{}
|
type fakeAuthorizer struct{}
|
||||||
|
|
||||||
func (fakeAuthorizer) Authorize(a authorizer.Attributes) (bool, string, error) {
|
func (fakeAuthorizer) Authorize(a authorizer.Attributes) (authorizer.Decision, string, error) {
|
||||||
username := a.GetUser().GetName()
|
username := a.GetUser().GetName()
|
||||||
|
|
||||||
if username == "non-deleter" {
|
if username == "non-deleter" {
|
||||||
if a.GetVerb() == "delete" {
|
if a.GetVerb() == "delete" {
|
||||||
return false, "", nil
|
return authorizer.DecisionNoOpinion, "", nil
|
||||||
}
|
}
|
||||||
if a.GetVerb() == "update" && a.GetSubresource() == "finalizers" {
|
if a.GetVerb() == "update" && a.GetSubresource() == "finalizers" {
|
||||||
return false, "", nil
|
return authorizer.DecisionNoOpinion, "", nil
|
||||||
}
|
}
|
||||||
return true, "", nil
|
return authorizer.DecisionAllow, "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if username == "non-pod-deleter" {
|
if username == "non-pod-deleter" {
|
||||||
if a.GetVerb() == "delete" && a.GetResource() == "pods" {
|
if a.GetVerb() == "delete" && a.GetResource() == "pods" {
|
||||||
return false, "", nil
|
return authorizer.DecisionNoOpinion, "", nil
|
||||||
}
|
}
|
||||||
if a.GetVerb() == "update" && a.GetResource() == "pods" && a.GetSubresource() == "finalizers" {
|
if a.GetVerb() == "update" && a.GetResource() == "pods" && a.GetSubresource() == "finalizers" {
|
||||||
return false, "", nil
|
return authorizer.DecisionNoOpinion, "", nil
|
||||||
}
|
}
|
||||||
return true, "", nil
|
return authorizer.DecisionAllow, "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if username == "non-rc-deleter" {
|
if username == "non-rc-deleter" {
|
||||||
if a.GetVerb() == "delete" && a.GetResource() == "replicationcontrollers" {
|
if a.GetVerb() == "delete" && a.GetResource() == "replicationcontrollers" {
|
||||||
return false, "", nil
|
return authorizer.DecisionNoOpinion, "", nil
|
||||||
}
|
}
|
||||||
if a.GetVerb() == "update" && a.GetResource() == "replicationcontrollers" && a.GetSubresource() == "finalizers" {
|
if a.GetVerb() == "update" && a.GetResource() == "replicationcontrollers" && a.GetSubresource() == "finalizers" {
|
||||||
return false, "", nil
|
return authorizer.DecisionNoOpinion, "", nil
|
||||||
}
|
}
|
||||||
return true, "", nil
|
return authorizer.DecisionAllow, "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return true, "", nil
|
return authorizer.DecisionAllow, "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// newGCPermissionsEnforcement returns the admission controller configured for testing.
|
// newGCPermissionsEnforcement returns the admission controller configured for testing.
|
||||||
|
|
|
@ -313,11 +313,11 @@ func authorizedForPolicy(info user.Info, namespace string, policy *extensions.Po
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
attr := buildAttributes(info, namespace, policy)
|
attr := buildAttributes(info, namespace, policy)
|
||||||
allowed, reason, err := authz.Authorize(attr)
|
decision, reason, err := authz.Authorize(attr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.V(5).Infof("cannot authorize for policy: %v,%v", reason, err)
|
glog.V(5).Infof("cannot authorize for policy: %v,%v", reason, err)
|
||||||
}
|
}
|
||||||
return allowed
|
return (decision == authorizer.DecisionAllow)
|
||||||
}
|
}
|
||||||
|
|
||||||
// buildAttributes builds an attributes record for a SAR based on the user info and policy.
|
// buildAttributes builds an attributes record for a SAR based on the user info and policy.
|
||||||
|
|
|
@ -66,13 +66,16 @@ type TestAuthorizer struct {
|
||||||
usernameToNamespaceToAllowedPSPs map[string]map[string]map[string]bool
|
usernameToNamespaceToAllowedPSPs map[string]map[string]map[string]bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *TestAuthorizer) Authorize(a authorizer.Attributes) (authorized bool, reason string, err error) {
|
func (t *TestAuthorizer) Authorize(a authorizer.Attributes) (authorized authorizer.Decision, reason string, err error) {
|
||||||
if t.usernameToNamespaceToAllowedPSPs == nil {
|
if t.usernameToNamespaceToAllowedPSPs == nil {
|
||||||
return true, "", nil
|
return authorizer.DecisionAllow, "", nil
|
||||||
}
|
}
|
||||||
allowedInNamespace := t.usernameToNamespaceToAllowedPSPs[a.GetUser().GetName()][a.GetNamespace()][a.GetName()]
|
allowedInNamespace := t.usernameToNamespaceToAllowedPSPs[a.GetUser().GetName()][a.GetNamespace()][a.GetName()]
|
||||||
allowedClusterWide := t.usernameToNamespaceToAllowedPSPs[a.GetUser().GetName()][""][a.GetName()]
|
allowedClusterWide := t.usernameToNamespaceToAllowedPSPs[a.GetUser().GetName()][""][a.GetName()]
|
||||||
return (allowedInNamespace || allowedClusterWide), "", nil
|
if allowedInNamespace || allowedClusterWide {
|
||||||
|
return authorizer.DecisionAllow, "", nil
|
||||||
|
}
|
||||||
|
return authorizer.DecisionNoOpinion, "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ authorizer.Authorizer = &TestAuthorizer{}
|
var _ authorizer.Authorizer = &TestAuthorizer{}
|
||||||
|
|
|
@ -64,16 +64,16 @@ var (
|
||||||
pvResource = api.Resource("persistentvolumes")
|
pvResource = api.Resource("persistentvolumes")
|
||||||
)
|
)
|
||||||
|
|
||||||
func (r *NodeAuthorizer) Authorize(attrs authorizer.Attributes) (bool, string, error) {
|
func (r *NodeAuthorizer) Authorize(attrs authorizer.Attributes) (authorizer.Decision, string, error) {
|
||||||
nodeName, isNode := r.identifier.NodeIdentity(attrs.GetUser())
|
nodeName, isNode := r.identifier.NodeIdentity(attrs.GetUser())
|
||||||
if !isNode {
|
if !isNode {
|
||||||
// reject requests from non-nodes
|
// reject requests from non-nodes
|
||||||
return false, "", nil
|
return authorizer.DecisionNoOpinion, "", nil
|
||||||
}
|
}
|
||||||
if len(nodeName) == 0 {
|
if len(nodeName) == 0 {
|
||||||
// reject requests from unidentifiable nodes
|
// reject requests from unidentifiable nodes
|
||||||
glog.V(2).Infof("NODE DENY: unknown node for user %q", attrs.GetUser().GetName())
|
glog.V(2).Infof("NODE DENY: unknown node for user %q", attrs.GetUser().GetName())
|
||||||
return false, fmt.Sprintf("unknown node for user %q", attrs.GetUser().GetName()), nil
|
return authorizer.DecisionNoOpinion, fmt.Sprintf("unknown node for user %q", attrs.GetUser().GetName()), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// subdivide access to specific resources
|
// subdivide access to specific resources
|
||||||
|
@ -92,31 +92,34 @@ func (r *NodeAuthorizer) Authorize(attrs authorizer.Attributes) (bool, string, e
|
||||||
}
|
}
|
||||||
|
|
||||||
// Access to other resources is not subdivided, so just evaluate against the statically defined node rules
|
// Access to other resources is not subdivided, so just evaluate against the statically defined node rules
|
||||||
return rbac.RulesAllow(attrs, r.nodeRules...), "", nil
|
if rbac.RulesAllow(attrs, r.nodeRules...) {
|
||||||
|
return authorizer.DecisionAllow, "", nil
|
||||||
|
}
|
||||||
|
return authorizer.DecisionNoOpinion, "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// authorizeGet authorizes "get" requests to objects of the specified type if they are related to the specified node
|
// authorizeGet authorizes "get" requests to objects of the specified type if they are related to the specified node
|
||||||
func (r *NodeAuthorizer) authorizeGet(nodeName string, startingType vertexType, attrs authorizer.Attributes) (bool, string, error) {
|
func (r *NodeAuthorizer) authorizeGet(nodeName string, startingType vertexType, attrs authorizer.Attributes) (authorizer.Decision, string, error) {
|
||||||
if attrs.GetVerb() != "get" || len(attrs.GetName()) == 0 {
|
if attrs.GetVerb() != "get" || len(attrs.GetName()) == 0 {
|
||||||
glog.V(2).Infof("NODE DENY: %s %#v", nodeName, attrs)
|
glog.V(2).Infof("NODE DENY: %s %#v", nodeName, attrs)
|
||||||
return false, "can only get individual resources of this type", nil
|
return authorizer.DecisionNoOpinion, "can only get individual resources of this type", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(attrs.GetSubresource()) > 0 {
|
if len(attrs.GetSubresource()) > 0 {
|
||||||
glog.V(2).Infof("NODE DENY: %s %#v", nodeName, attrs)
|
glog.V(2).Infof("NODE DENY: %s %#v", nodeName, attrs)
|
||||||
return false, "cannot get subresource", nil
|
return authorizer.DecisionNoOpinion, "cannot get subresource", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
ok, err := r.hasPathFrom(nodeName, startingType, attrs.GetNamespace(), attrs.GetName())
|
ok, err := r.hasPathFrom(nodeName, startingType, attrs.GetNamespace(), attrs.GetName())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.V(2).Infof("NODE DENY: %v", err)
|
glog.V(2).Infof("NODE DENY: %v", err)
|
||||||
return false, "no path found to object", nil
|
return authorizer.DecisionNoOpinion, "no path found to object", nil
|
||||||
}
|
}
|
||||||
if !ok {
|
if !ok {
|
||||||
glog.V(2).Infof("NODE DENY: %q %#v", nodeName, attrs)
|
glog.V(2).Infof("NODE DENY: %q %#v", nodeName, attrs)
|
||||||
return false, "no path found to object", nil
|
return authorizer.DecisionNoOpinion, "no path found to object", nil
|
||||||
}
|
}
|
||||||
return ok, "", nil
|
return authorizer.DecisionAllow, "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// hasPathFrom returns true if there is a directed path from the specified type/namespace/name to the specified Node
|
// hasPathFrom returns true if there is a directed path from the specified type/namespace/name to the specified Node
|
||||||
|
|
|
@ -57,71 +57,71 @@ func TestAuthorizer(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
attrs authorizer.AttributesRecord
|
attrs authorizer.AttributesRecord
|
||||||
expect bool
|
expect authorizer.Decision
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "allowed configmap",
|
name: "allowed configmap",
|
||||||
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "get", Resource: "configmaps", Name: "configmap0-pod0-node0", Namespace: "ns0"},
|
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "get", Resource: "configmaps", Name: "configmap0-pod0-node0", Namespace: "ns0"},
|
||||||
expect: true,
|
expect: authorizer.DecisionAllow,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "allowed secret via pod",
|
name: "allowed secret via pod",
|
||||||
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "get", Resource: "secrets", Name: "secret0-pod0-node0", Namespace: "ns0"},
|
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "get", Resource: "secrets", Name: "secret0-pod0-node0", Namespace: "ns0"},
|
||||||
expect: true,
|
expect: authorizer.DecisionAllow,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "allowed shared secret via pod",
|
name: "allowed shared secret via pod",
|
||||||
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "get", Resource: "secrets", Name: "secret0-shared", Namespace: "ns0"},
|
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "get", Resource: "secrets", Name: "secret0-shared", Namespace: "ns0"},
|
||||||
expect: true,
|
expect: authorizer.DecisionAllow,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "allowed shared secret via pvc",
|
name: "allowed shared secret via pvc",
|
||||||
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "get", Resource: "secrets", Name: "secret-pv0-pod0-node0-ns0", Namespace: "ns0"},
|
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "get", Resource: "secrets", Name: "secret-pv0-pod0-node0-ns0", Namespace: "ns0"},
|
||||||
expect: true,
|
expect: authorizer.DecisionAllow,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "allowed pvc",
|
name: "allowed pvc",
|
||||||
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "get", Resource: "persistentvolumeclaims", Name: "pvc0-pod0-node0", Namespace: "ns0"},
|
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "get", Resource: "persistentvolumeclaims", Name: "pvc0-pod0-node0", Namespace: "ns0"},
|
||||||
expect: true,
|
expect: authorizer.DecisionAllow,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "allowed pv",
|
name: "allowed pv",
|
||||||
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "get", Resource: "persistentvolumes", Name: "pv0-pod0-node0-ns0", Namespace: ""},
|
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "get", Resource: "persistentvolumes", Name: "pv0-pod0-node0-ns0", Namespace: ""},
|
||||||
expect: true,
|
expect: authorizer.DecisionAllow,
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
{
|
||||||
name: "disallowed configmap",
|
name: "disallowed configmap",
|
||||||
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "get", Resource: "configmaps", Name: "configmap0-pod0-node1", Namespace: "ns0"},
|
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "get", Resource: "configmaps", Name: "configmap0-pod0-node1", Namespace: "ns0"},
|
||||||
expect: false,
|
expect: authorizer.DecisionNoOpinion,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "disallowed secret via pod",
|
name: "disallowed secret via pod",
|
||||||
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "get", Resource: "secrets", Name: "secret0-pod0-node1", Namespace: "ns0"},
|
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "get", Resource: "secrets", Name: "secret0-pod0-node1", Namespace: "ns0"},
|
||||||
expect: false,
|
expect: authorizer.DecisionNoOpinion,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "disallowed shared secret via pvc",
|
name: "disallowed shared secret via pvc",
|
||||||
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "get", Resource: "secrets", Name: "secret-pv0-pod0-node1-ns0", Namespace: "ns0"},
|
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "get", Resource: "secrets", Name: "secret-pv0-pod0-node1-ns0", Namespace: "ns0"},
|
||||||
expect: false,
|
expect: authorizer.DecisionNoOpinion,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "disallowed pvc",
|
name: "disallowed pvc",
|
||||||
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "get", Resource: "persistentvolumeclaims", Name: "pvc0-pod0-node1", Namespace: "ns0"},
|
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "get", Resource: "persistentvolumeclaims", Name: "pvc0-pod0-node1", Namespace: "ns0"},
|
||||||
expect: false,
|
expect: authorizer.DecisionNoOpinion,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "disallowed pv",
|
name: "disallowed pv",
|
||||||
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "get", Resource: "persistentvolumes", Name: "pv0-pod0-node1-ns0", Namespace: ""},
|
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "get", Resource: "persistentvolumes", Name: "pv0-pod0-node1-ns0", Namespace: ""},
|
||||||
expect: false,
|
expect: authorizer.DecisionNoOpinion,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tc := range tests {
|
for _, tc := range tests {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
ok, _, _ := authz.Authorize(tc.attrs)
|
decision, _, _ := authz.Authorize(tc.attrs)
|
||||||
if ok != tc.expect {
|
if decision != tc.expect {
|
||||||
t.Errorf("expected %v, got %v", tc.expect, ok)
|
t.Errorf("expected %v, got %v", tc.expect, decision)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -186,13 +186,13 @@ func TestAuthorizerSharedResources(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, tc := range testcases {
|
for i, tc := range testcases {
|
||||||
ok, _, err := authz.Authorize(authorizer.AttributesRecord{User: tc.User, ResourceRequest: true, Verb: "get", Resource: "secrets", Namespace: "ns1", Name: tc.Secret})
|
decision, _, err := authz.Authorize(authorizer.AttributesRecord{User: tc.User, ResourceRequest: true, Verb: "get", Resource: "secrets", Namespace: "ns1", Name: tc.Secret})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("%d: unexpected error: %v", i, err)
|
t.Errorf("%d: unexpected error: %v", i, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if ok != tc.ExpectAllowed {
|
if (decision == authorizer.DecisionAllow) != tc.ExpectAllowed {
|
||||||
t.Errorf("%d: expected %v, got %v", i, tc.ExpectAllowed, ok)
|
t.Errorf("%d: expected %v, got %v", i, tc.ExpectAllowed, decision)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -301,47 +301,47 @@ func BenchmarkAuthorization(b *testing.B) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
attrs authorizer.AttributesRecord
|
attrs authorizer.AttributesRecord
|
||||||
expect bool
|
expect authorizer.Decision
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "allowed configmap",
|
name: "allowed configmap",
|
||||||
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "get", Resource: "configmaps", Name: "configmap0-pod0-node0", Namespace: "ns0"},
|
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "get", Resource: "configmaps", Name: "configmap0-pod0-node0", Namespace: "ns0"},
|
||||||
expect: true,
|
expect: authorizer.DecisionAllow,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "allowed secret via pod",
|
name: "allowed secret via pod",
|
||||||
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "get", Resource: "secrets", Name: "secret0-pod0-node0", Namespace: "ns0"},
|
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "get", Resource: "secrets", Name: "secret0-pod0-node0", Namespace: "ns0"},
|
||||||
expect: true,
|
expect: authorizer.DecisionAllow,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "allowed shared secret via pod",
|
name: "allowed shared secret via pod",
|
||||||
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "get", Resource: "secrets", Name: "secret0-shared", Namespace: "ns0"},
|
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "get", Resource: "secrets", Name: "secret0-shared", Namespace: "ns0"},
|
||||||
expect: true,
|
expect: authorizer.DecisionAllow,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "disallowed configmap",
|
name: "disallowed configmap",
|
||||||
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "get", Resource: "configmaps", Name: "configmap0-pod0-node1", Namespace: "ns0"},
|
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "get", Resource: "configmaps", Name: "configmap0-pod0-node1", Namespace: "ns0"},
|
||||||
expect: false,
|
expect: authorizer.DecisionNoOpinion,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "disallowed secret via pod",
|
name: "disallowed secret via pod",
|
||||||
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "get", Resource: "secrets", Name: "secret0-pod0-node1", Namespace: "ns0"},
|
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "get", Resource: "secrets", Name: "secret0-pod0-node1", Namespace: "ns0"},
|
||||||
expect: false,
|
expect: authorizer.DecisionNoOpinion,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "disallowed shared secret via pvc",
|
name: "disallowed shared secret via pvc",
|
||||||
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "get", Resource: "secrets", Name: "secret-pv0-pod0-node1-ns0", Namespace: "ns0"},
|
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "get", Resource: "secrets", Name: "secret-pv0-pod0-node1-ns0", Namespace: "ns0"},
|
||||||
expect: false,
|
expect: authorizer.DecisionNoOpinion,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "disallowed pvc",
|
name: "disallowed pvc",
|
||||||
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "get", Resource: "persistentvolumeclaims", Name: "pvc0-pod0-node1", Namespace: "ns0"},
|
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "get", Resource: "persistentvolumeclaims", Name: "pvc0-pod0-node1", Namespace: "ns0"},
|
||||||
expect: false,
|
expect: authorizer.DecisionNoOpinion,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "disallowed pv",
|
name: "disallowed pv",
|
||||||
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "get", Resource: "persistentvolumes", Name: "pv0-pod0-node1-ns0", Namespace: ""},
|
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "get", Resource: "persistentvolumes", Name: "pv0-pod0-node1-ns0", Namespace: ""},
|
||||||
expect: false,
|
expect: authorizer.DecisionNoOpinion,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -349,9 +349,9 @@ func BenchmarkAuthorization(b *testing.B) {
|
||||||
for _, tc := range tests {
|
for _, tc := range tests {
|
||||||
b.Run(tc.name, func(b *testing.B) {
|
b.Run(tc.name, func(b *testing.B) {
|
||||||
for i := 0; i < b.N; i++ {
|
for i := 0; i < b.N; i++ {
|
||||||
ok, _, _ := authz.Authorize(tc.attrs)
|
decision, _, _ := authz.Authorize(tc.attrs)
|
||||||
if ok != tc.expect {
|
if decision != tc.expect {
|
||||||
b.Errorf("expected %v, got %v", tc.expect, ok)
|
b.Errorf("expected %v, got %v", tc.expect, decision)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -69,12 +69,12 @@ func (v *authorizingVisitor) visit(rule *rbac.PolicyRule, err error) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *RBACAuthorizer) Authorize(requestAttributes authorizer.Attributes) (bool, string, error) {
|
func (r *RBACAuthorizer) Authorize(requestAttributes authorizer.Attributes) (authorizer.Decision, string, error) {
|
||||||
ruleCheckingVisitor := &authorizingVisitor{requestAttributes: requestAttributes}
|
ruleCheckingVisitor := &authorizingVisitor{requestAttributes: requestAttributes}
|
||||||
|
|
||||||
r.authorizationRuleResolver.VisitRulesFor(requestAttributes.GetUser(), requestAttributes.GetNamespace(), ruleCheckingVisitor.visit)
|
r.authorizationRuleResolver.VisitRulesFor(requestAttributes.GetUser(), requestAttributes.GetNamespace(), ruleCheckingVisitor.visit)
|
||||||
if ruleCheckingVisitor.allowed {
|
if ruleCheckingVisitor.allowed {
|
||||||
return true, "", nil
|
return authorizer.DecisionAllow, "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Build a detailed log of the denial.
|
// Build a detailed log of the denial.
|
||||||
|
@ -120,7 +120,7 @@ func (r *RBACAuthorizer) Authorize(requestAttributes authorizer.Attributes) (boo
|
||||||
if len(ruleCheckingVisitor.errors) > 0 {
|
if len(ruleCheckingVisitor.errors) > 0 {
|
||||||
reason = fmt.Sprintf("%v", utilerrors.NewAggregate(ruleCheckingVisitor.errors))
|
reason = fmt.Sprintf("%v", utilerrors.NewAggregate(ruleCheckingVisitor.errors))
|
||||||
}
|
}
|
||||||
return false, reason, nil
|
return authorizer.DecisionNoOpinion, reason, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *RBACAuthorizer) RulesFor(user user.Info, namespace string) ([]authorizer.ResourceRuleInfo, []authorizer.NonResourceRuleInfo, bool, error) {
|
func (r *RBACAuthorizer) RulesFor(user user.Info, namespace string) ([]authorizer.ResourceRuleInfo, []authorizer.NonResourceRuleInfo, bool, error) {
|
||||||
|
|
|
@ -247,13 +247,13 @@ func TestAuthorizer(t *testing.T) {
|
||||||
ruleResolver, _ := rbacregistryvalidation.NewTestRuleResolver(tt.roles, tt.roleBindings, tt.clusterRoles, tt.clusterRoleBindings)
|
ruleResolver, _ := rbacregistryvalidation.NewTestRuleResolver(tt.roles, tt.roleBindings, tt.clusterRoles, tt.clusterRoleBindings)
|
||||||
a := RBACAuthorizer{ruleResolver}
|
a := RBACAuthorizer{ruleResolver}
|
||||||
for _, attr := range tt.shouldPass {
|
for _, attr := range tt.shouldPass {
|
||||||
if authorized, _, _ := a.Authorize(attr); !authorized {
|
if decision, _, _ := a.Authorize(attr); decision != authorizer.DecisionAllow {
|
||||||
t.Errorf("case %d: incorrectly restricted %s", i, attr)
|
t.Errorf("case %d: incorrectly restricted %s", i, attr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, attr := range tt.shouldFail {
|
for _, attr := range tt.shouldFail {
|
||||||
if authorized, _, _ := a.Authorize(attr); authorized {
|
if decision, _, _ := a.Authorize(attr); decision == authorizer.DecisionAllow {
|
||||||
t.Errorf("case %d: incorrectly passed %s", i, attr)
|
t.Errorf("case %d: incorrectly passed %s", i, attr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -133,8 +133,8 @@ var _ initializer.WantsAuthorizer = &WantAuthorizerAdmission{}
|
||||||
// TestAuthorizer is a test stub that fulfills the WantsAuthorizer interface.
|
// TestAuthorizer is a test stub that fulfills the WantsAuthorizer interface.
|
||||||
type TestAuthorizer struct{}
|
type TestAuthorizer struct{}
|
||||||
|
|
||||||
func (t *TestAuthorizer) Authorize(a authorizer.Attributes) (authorized bool, reason string, err error) {
|
func (t *TestAuthorizer) Authorize(a authorizer.Attributes) (authorized authorizer.Decision, reason string, err error) {
|
||||||
return false, "", nil
|
return authorizer.DecisionNoOpinion, "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// wantClientCert is a test stub for testing that fulfulls the WantsClientCert interface.
|
// wantClientCert is a test stub for testing that fulfulls the WantsClientCert interface.
|
||||||
|
|
|
@ -260,7 +260,7 @@ func (i *initializer) Admit(a admission.Attributes) (err error) {
|
||||||
|
|
||||||
func (i *initializer) canInitialize(a admission.Attributes, message string) error {
|
func (i *initializer) canInitialize(a admission.Attributes, message string) error {
|
||||||
// caller must have the ability to mutate un-initialized resources
|
// caller must have the ability to mutate un-initialized resources
|
||||||
authorized, reason, err := i.authorizer.Authorize(authorizer.AttributesRecord{
|
decision, reason, err := i.authorizer.Authorize(authorizer.AttributesRecord{
|
||||||
Name: a.GetName(),
|
Name: a.GetName(),
|
||||||
ResourceRequest: true,
|
ResourceRequest: true,
|
||||||
User: a.GetUserInfo(),
|
User: a.GetUserInfo(),
|
||||||
|
@ -273,7 +273,7 @@ func (i *initializer) canInitialize(a admission.Attributes, message string) erro
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if !authorized {
|
if decision != authorizer.DecisionAllow {
|
||||||
return errors.NewForbidden(a.GetResource().GroupResource(), a.GetName(), fmt.Errorf("%s: %s", message, reason))
|
return errors.NewForbidden(a.GetResource().GroupResource(), a.GetName(), fmt.Errorf("%s: %s", message, reason))
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
|
@ -109,11 +109,11 @@ type fakeAuthorizer struct {
|
||||||
accept bool
|
accept bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *fakeAuthorizer) Authorize(a authorizer.Attributes) (bool, string, error) {
|
func (f *fakeAuthorizer) Authorize(a authorizer.Attributes) (authorizer.Decision, string, error) {
|
||||||
if f.accept {
|
if f.accept {
|
||||||
return true, "", nil
|
return authorizer.DecisionAllow, "", nil
|
||||||
}
|
}
|
||||||
return false, "denied", nil
|
return authorizer.DecisionNoOpinion, "denied", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAdmitUpdate(t *testing.T) {
|
func TestAdmitUpdate(t *testing.T) {
|
||||||
|
|
|
@ -27,7 +27,7 @@ import (
|
||||||
// and always return nil.
|
// and always return nil.
|
||||||
func TestNewAlwaysAllowAuthorizer(t *testing.T) {
|
func TestNewAlwaysAllowAuthorizer(t *testing.T) {
|
||||||
aaa := NewAlwaysAllowAuthorizer()
|
aaa := NewAlwaysAllowAuthorizer()
|
||||||
if authorized, _, _ := aaa.Authorize(nil); !authorized {
|
if decision, _, _ := aaa.Authorize(nil); decision != authorizer.DecisionAllow {
|
||||||
t.Errorf("AlwaysAllowAuthorizer.Authorize did not authorize successfully.")
|
t.Errorf("AlwaysAllowAuthorizer.Authorize did not authorize successfully.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,7 @@ func TestNewAlwaysAllowAuthorizer(t *testing.T) {
|
||||||
// and always return an error as everything is forbidden.
|
// and always return an error as everything is forbidden.
|
||||||
func TestNewAlwaysDenyAuthorizer(t *testing.T) {
|
func TestNewAlwaysDenyAuthorizer(t *testing.T) {
|
||||||
ada := NewAlwaysDenyAuthorizer()
|
ada := NewAlwaysDenyAuthorizer()
|
||||||
if authorized, _, _ := ada.Authorize(nil); authorized {
|
if decision, _, _ := ada.Authorize(nil); decision == authorizer.DecisionAllow {
|
||||||
t.Errorf("AlwaysDenyAuthorizer.Authorize returned nil instead of error.")
|
t.Errorf("AlwaysDenyAuthorizer.Authorize returned nil instead of error.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,10 +47,10 @@ func TestPrivilegedGroupAuthorizer(t *testing.T) {
|
||||||
yes := authorizer.AttributesRecord{User: &user.DefaultInfo{Groups: []string{"no", "allow-01"}}}
|
yes := authorizer.AttributesRecord{User: &user.DefaultInfo{Groups: []string{"no", "allow-01"}}}
|
||||||
no := authorizer.AttributesRecord{User: &user.DefaultInfo{Groups: []string{"no", "deny-01"}}}
|
no := authorizer.AttributesRecord{User: &user.DefaultInfo{Groups: []string{"no", "deny-01"}}}
|
||||||
|
|
||||||
if authorized, _, _ := auth.Authorize(yes); !authorized {
|
if authorized, _, _ := auth.Authorize(yes); authorized != authorizer.DecisionAllow {
|
||||||
t.Errorf("failed")
|
t.Errorf("failed")
|
||||||
}
|
}
|
||||||
if authorized, _, _ := auth.Authorize(no); authorized {
|
if authorized, _, _ := auth.Authorize(no); authorized == authorizer.DecisionAllow {
|
||||||
t.Errorf("failed")
|
t.Errorf("failed")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,8 +28,8 @@ import (
|
||||||
// It is useful in tests and when using kubernetes in an open manner.
|
// It is useful in tests and when using kubernetes in an open manner.
|
||||||
type alwaysAllowAuthorizer struct{}
|
type alwaysAllowAuthorizer struct{}
|
||||||
|
|
||||||
func (alwaysAllowAuthorizer) Authorize(a authorizer.Attributes) (authorized bool, reason string, err error) {
|
func (alwaysAllowAuthorizer) Authorize(a authorizer.Attributes) (authorized authorizer.Decision, reason string, err error) {
|
||||||
return true, "", nil
|
return authorizer.DecisionAllow, "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (alwaysAllowAuthorizer) RulesFor(user user.Info, namespace string) ([]authorizer.ResourceRuleInfo, []authorizer.NonResourceRuleInfo, bool, error) {
|
func (alwaysAllowAuthorizer) RulesFor(user user.Info, namespace string) ([]authorizer.ResourceRuleInfo, []authorizer.NonResourceRuleInfo, bool, error) {
|
||||||
|
@ -56,8 +56,8 @@ func NewAlwaysAllowAuthorizer() *alwaysAllowAuthorizer {
|
||||||
// It is useful in unit tests to force an operation to be forbidden.
|
// It is useful in unit tests to force an operation to be forbidden.
|
||||||
type alwaysDenyAuthorizer struct{}
|
type alwaysDenyAuthorizer struct{}
|
||||||
|
|
||||||
func (alwaysDenyAuthorizer) Authorize(a authorizer.Attributes) (authorized bool, reason string, err error) {
|
func (alwaysDenyAuthorizer) Authorize(a authorizer.Attributes) (decision authorizer.Decision, reason string, err error) {
|
||||||
return false, "Everything is forbidden.", nil
|
return authorizer.DecisionNoOpinion, "Everything is forbidden.", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (alwaysDenyAuthorizer) RulesFor(user user.Info, namespace string) ([]authorizer.ResourceRuleInfo, []authorizer.NonResourceRuleInfo, bool, error) {
|
func (alwaysDenyAuthorizer) RulesFor(user user.Info, namespace string) ([]authorizer.ResourceRuleInfo, []authorizer.NonResourceRuleInfo, bool, error) {
|
||||||
|
@ -73,8 +73,8 @@ func NewAlwaysDenyAuthorizer() *alwaysDenyAuthorizer {
|
||||||
// It is useful in unit tests to force an operation to fail with error.
|
// It is useful in unit tests to force an operation to fail with error.
|
||||||
type alwaysFailAuthorizer struct{}
|
type alwaysFailAuthorizer struct{}
|
||||||
|
|
||||||
func (alwaysFailAuthorizer) Authorize(a authorizer.Attributes) (authorized bool, reason string, err error) {
|
func (alwaysFailAuthorizer) Authorize(a authorizer.Attributes) (authorized authorizer.Decision, reason string, err error) {
|
||||||
return false, "", errors.New("Authorization failure.")
|
return authorizer.DecisionNoOpinion, "", errors.New("Authorization failure.")
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewAlwaysFailAuthorizer() authorizer.Authorizer {
|
func NewAlwaysFailAuthorizer() authorizer.Authorizer {
|
||||||
|
@ -85,18 +85,18 @@ type privilegedGroupAuthorizer struct {
|
||||||
groups []string
|
groups []string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *privilegedGroupAuthorizer) Authorize(attr authorizer.Attributes) (bool, string, error) {
|
func (r *privilegedGroupAuthorizer) Authorize(attr authorizer.Attributes) (authorizer.Decision, string, error) {
|
||||||
if attr.GetUser() == nil {
|
if attr.GetUser() == nil {
|
||||||
return false, "Error", errors.New("no user on request.")
|
return authorizer.DecisionNoOpinion, "Error", errors.New("no user on request.")
|
||||||
}
|
}
|
||||||
for _, attr_group := range attr.GetUser().GetGroups() {
|
for _, attr_group := range attr.GetUser().GetGroups() {
|
||||||
for _, priv_group := range r.groups {
|
for _, priv_group := range r.groups {
|
||||||
if priv_group == attr_group {
|
if priv_group == attr_group {
|
||||||
return true, "", nil
|
return authorizer.DecisionAllow, "", nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false, "", nil
|
return authorizer.DecisionNoOpinion, "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPrivilegedGroups is for use in loopback scenarios
|
// NewPrivilegedGroups is for use in loopback scenarios
|
||||||
|
|
|
@ -47,7 +47,7 @@ func WithAuthorization(handler http.Handler, requestContextMapper request.Reques
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
authorized, reason, err := a.Authorize(attributes)
|
authorized, reason, err := a.Authorize(attributes)
|
||||||
if authorized {
|
if authorized == authorizer.DecisionAllow {
|
||||||
handler.ServeHTTP(w, req)
|
handler.ServeHTTP(w, req)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
|
@ -110,8 +110,8 @@ func WithImpersonation(handler http.Handler, requestContextMapper request.Reques
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
allowed, reason, err := a.Authorize(actingAsAttributes)
|
decision, reason, err := a.Authorize(actingAsAttributes)
|
||||||
if err != nil || !allowed {
|
if err != nil || decision != authorizer.DecisionAllow {
|
||||||
glog.V(4).Infof("Forbidden: %#v, Reason: %s, Error: %v", req.RequestURI, reason, err)
|
glog.V(4).Infof("Forbidden: %#v, Reason: %s, Error: %v", req.RequestURI, reason, err)
|
||||||
responsewriters.Forbidden(ctx, actingAsAttributes, w, req, reason, s)
|
responsewriters.Forbidden(ctx, actingAsAttributes, w, req, reason, s)
|
||||||
return
|
return
|
||||||
|
|
|
@ -35,50 +35,50 @@ import (
|
||||||
|
|
||||||
type impersonateAuthorizer struct{}
|
type impersonateAuthorizer struct{}
|
||||||
|
|
||||||
func (impersonateAuthorizer) Authorize(a authorizer.Attributes) (authorized bool, reason string, err error) {
|
func (impersonateAuthorizer) Authorize(a authorizer.Attributes) (authorized authorizer.Decision, reason string, err error) {
|
||||||
user := a.GetUser()
|
user := a.GetUser()
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case user.GetName() == "system:admin":
|
case user.GetName() == "system:admin":
|
||||||
return true, "", nil
|
return authorizer.DecisionAllow, "", nil
|
||||||
|
|
||||||
case user.GetName() == "tester":
|
case user.GetName() == "tester":
|
||||||
return false, "", fmt.Errorf("works on my machine")
|
return authorizer.DecisionNoOpinion, "", fmt.Errorf("works on my machine")
|
||||||
|
|
||||||
case user.GetName() == "deny-me":
|
case user.GetName() == "deny-me":
|
||||||
return false, "denied", nil
|
return authorizer.DecisionNoOpinion, "denied", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(user.GetGroups()) > 0 && user.GetGroups()[0] == "wheel" && a.GetVerb() == "impersonate" && a.GetResource() == "users" {
|
if len(user.GetGroups()) > 0 && user.GetGroups()[0] == "wheel" && a.GetVerb() == "impersonate" && a.GetResource() == "users" {
|
||||||
return true, "", nil
|
return authorizer.DecisionAllow, "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(user.GetGroups()) > 0 && user.GetGroups()[0] == "sa-impersonater" && a.GetVerb() == "impersonate" && a.GetResource() == "serviceaccounts" {
|
if len(user.GetGroups()) > 0 && user.GetGroups()[0] == "sa-impersonater" && a.GetVerb() == "impersonate" && a.GetResource() == "serviceaccounts" {
|
||||||
return true, "", nil
|
return authorizer.DecisionAllow, "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(user.GetGroups()) > 0 && user.GetGroups()[0] == "regular-impersonater" && a.GetVerb() == "impersonate" && a.GetResource() == "users" {
|
if len(user.GetGroups()) > 0 && user.GetGroups()[0] == "regular-impersonater" && a.GetVerb() == "impersonate" && a.GetResource() == "users" {
|
||||||
return true, "", nil
|
return authorizer.DecisionAllow, "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(user.GetGroups()) > 1 && user.GetGroups()[1] == "group-impersonater" && a.GetVerb() == "impersonate" && a.GetResource() == "groups" {
|
if len(user.GetGroups()) > 1 && user.GetGroups()[1] == "group-impersonater" && a.GetVerb() == "impersonate" && a.GetResource() == "groups" {
|
||||||
return true, "", nil
|
return authorizer.DecisionAllow, "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(user.GetGroups()) > 1 && user.GetGroups()[1] == "extra-setter-scopes" && a.GetVerb() == "impersonate" && a.GetResource() == "userextras" && a.GetSubresource() == "scopes" {
|
if len(user.GetGroups()) > 1 && user.GetGroups()[1] == "extra-setter-scopes" && a.GetVerb() == "impersonate" && a.GetResource() == "userextras" && a.GetSubresource() == "scopes" {
|
||||||
return true, "", nil
|
return authorizer.DecisionAllow, "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(user.GetGroups()) > 1 && user.GetGroups()[1] == "extra-setter-particular-scopes" &&
|
if len(user.GetGroups()) > 1 && user.GetGroups()[1] == "extra-setter-particular-scopes" &&
|
||||||
a.GetVerb() == "impersonate" && a.GetResource() == "userextras" && a.GetSubresource() == "scopes" && a.GetName() == "scope-a" {
|
a.GetVerb() == "impersonate" && a.GetResource() == "userextras" && a.GetSubresource() == "scopes" && a.GetName() == "scope-a" {
|
||||||
return true, "", nil
|
return authorizer.DecisionAllow, "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(user.GetGroups()) > 1 && user.GetGroups()[1] == "extra-setter-project" && a.GetVerb() == "impersonate" && a.GetResource() == "userextras" && a.GetSubresource() == "project" {
|
if len(user.GetGroups()) > 1 && user.GetGroups()[1] == "extra-setter-project" && a.GetVerb() == "impersonate" && a.GetResource() == "userextras" && a.GetSubresource() == "project" {
|
||||||
return true, "", nil
|
return authorizer.DecisionAllow, "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return false, "deny by default", nil
|
return authorizer.DecisionNoOpinion, "deny by default", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestImpersonationFilter(t *testing.T) {
|
func TestImpersonationFilter(t *testing.T) {
|
||||||
|
|
|
@ -437,9 +437,9 @@ type mockAuthorizer struct {
|
||||||
lastURI string
|
lastURI string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (authz *mockAuthorizer) Authorize(a authorizer.Attributes) (authorized bool, reason string, err error) {
|
func (authz *mockAuthorizer) Authorize(a authorizer.Attributes) (authorized authorizer.Decision, reason string, err error) {
|
||||||
authz.lastURI = a.GetPath()
|
authz.lastURI = a.GetPath()
|
||||||
return true, "", nil
|
return authorizer.DecisionAllow, "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type mockAuthenticator struct {
|
type mockAuthenticator struct {
|
||||||
|
|
|
@ -140,7 +140,10 @@ func newWithBackoff(subjectAccessReview authorizationclient.SubjectAccessReviewI
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
func (w *WebhookAuthorizer) Authorize(attr authorizer.Attributes) (authorized bool, reason string, err error) {
|
// TODO(mikedanese): We should eventually fail closed when we encounter and
|
||||||
|
// error. We are failing open now to preserve backwards compatible behavior.
|
||||||
|
// Fix this after deprecation.
|
||||||
|
func (w *WebhookAuthorizer) Authorize(attr authorizer.Attributes) (decision authorizer.Decision, reason string, err error) {
|
||||||
r := &authorization.SubjectAccessReview{}
|
r := &authorization.SubjectAccessReview{}
|
||||||
if user := attr.GetUser(); user != nil {
|
if user := attr.GetUser(); user != nil {
|
||||||
r.Spec = authorization.SubjectAccessReviewSpec{
|
r.Spec = authorization.SubjectAccessReviewSpec{
|
||||||
|
@ -169,7 +172,7 @@ func (w *WebhookAuthorizer) Authorize(attr authorizer.Attributes) (authorized bo
|
||||||
}
|
}
|
||||||
key, err := json.Marshal(r.Spec)
|
key, err := json.Marshal(r.Spec)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, "", err
|
return authorizer.DecisionNoOpinion, "", err
|
||||||
}
|
}
|
||||||
if entry, ok := w.responseCache.Get(string(key)); ok {
|
if entry, ok := w.responseCache.Get(string(key)); ok {
|
||||||
r.Status = entry.(authorization.SubjectAccessReviewStatus)
|
r.Status = entry.(authorization.SubjectAccessReviewStatus)
|
||||||
|
@ -185,7 +188,7 @@ func (w *WebhookAuthorizer) Authorize(attr authorizer.Attributes) (authorized bo
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// An error here indicates bad configuration or an outage. Log for debugging.
|
// An error here indicates bad configuration or an outage. Log for debugging.
|
||||||
glog.Errorf("Failed to make webhook authorizer request: %v", err)
|
glog.Errorf("Failed to make webhook authorizer request: %v", err)
|
||||||
return false, "", err
|
return authorizer.DecisionNoOpinion, "", err
|
||||||
}
|
}
|
||||||
r.Status = result.Status
|
r.Status = result.Status
|
||||||
if r.Status.Allowed {
|
if r.Status.Allowed {
|
||||||
|
@ -194,7 +197,12 @@ func (w *WebhookAuthorizer) Authorize(attr authorizer.Attributes) (authorized bo
|
||||||
w.responseCache.Add(string(key), r.Status, w.unauthorizedTTL)
|
w.responseCache.Add(string(key), r.Status, w.unauthorizedTTL)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return r.Status.Allowed, r.Status.Reason, nil
|
if r.Status.Allowed {
|
||||||
|
return authorizer.DecisionAllow, r.Status.Reason, nil
|
||||||
|
} else {
|
||||||
|
return authorizer.DecisionNoOpinion, r.Status.Reason, nil
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: need to finish the method to get the rules when using webhook mode
|
//TODO: need to finish the method to get the rules when using webhook mode
|
||||||
|
|
|
@ -396,13 +396,13 @@ func TestTLSConfig(t *testing.T) {
|
||||||
|
|
||||||
// Allow all and see if we get an error.
|
// Allow all and see if we get an error.
|
||||||
service.Allow()
|
service.Allow()
|
||||||
authorized, _, err := wh.Authorize(attr)
|
decision, _, err := wh.Authorize(attr)
|
||||||
if tt.wantAuth {
|
if tt.wantAuth {
|
||||||
if !authorized {
|
if decision != authorizer.DecisionAllow {
|
||||||
t.Errorf("expected successful authorization")
|
t.Errorf("expected successful authorization")
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if authorized {
|
if decision == authorizer.DecisionAllow {
|
||||||
t.Errorf("expected failed authorization")
|
t.Errorf("expected failed authorization")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -418,7 +418,7 @@ func TestTLSConfig(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
service.Deny()
|
service.Deny()
|
||||||
if authorized, _, _ := wh.Authorize(attr); authorized {
|
if decision, _, _ := wh.Authorize(attr); decision == authorizer.DecisionAllow {
|
||||||
t.Errorf("%s: incorrectly authorized with DenyAll policy", tt.test)
|
t.Errorf("%s: incorrectly authorized with DenyAll policy", tt.test)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
@ -522,11 +522,11 @@ func TestWebhook(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, tt := range tests {
|
for i, tt := range tests {
|
||||||
authorized, _, err := wh.Authorize(tt.attr)
|
decision, _, err := wh.Authorize(tt.attr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
if !authorized {
|
if decision != authorizer.DecisionAllow {
|
||||||
t.Errorf("case %d: authorization failed", i)
|
t.Errorf("case %d: authorization failed", i)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -567,7 +567,7 @@ func testWebhookCacheCases(t *testing.T, serv *mockService, wh *WebhookAuthorize
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if test.expectedAuthorized != authorized {
|
if test.expectedAuthorized != (authorized == authorizer.DecisionAllow) {
|
||||||
t.Errorf("%d: expected authorized=%v, got %v", i, test.expectedAuthorized, authorized)
|
t.Errorf("%d: expected authorized=%v, got %v", i, test.expectedAuthorized, authorized)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,12 +39,12 @@ import (
|
||||||
// TODO(etune): remove this test once a more comprehensive built-in authorizer is implemented.
|
// TODO(etune): remove this test once a more comprehensive built-in authorizer is implemented.
|
||||||
type sarAuthorizer struct{}
|
type sarAuthorizer struct{}
|
||||||
|
|
||||||
func (sarAuthorizer) Authorize(a authorizer.Attributes) (bool, string, error) {
|
func (sarAuthorizer) Authorize(a authorizer.Attributes) (authorizer.Decision, string, error) {
|
||||||
if a.GetUser().GetName() == "dave" {
|
if a.GetUser().GetName() == "dave" {
|
||||||
return false, "no", errors.New("I'm sorry, Dave")
|
return authorizer.DecisionNoOpinion, "no", errors.New("I'm sorry, Dave")
|
||||||
}
|
}
|
||||||
|
|
||||||
return true, "you're not dave", nil
|
return authorizer.DecisionAllow, "you're not dave", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func alwaysAlice(req *http.Request) (user.Info, bool, error) {
|
func alwaysAlice(req *http.Request) (user.Info, bool, error) {
|
||||||
|
|
|
@ -535,11 +535,11 @@ func TestAuthModeAlwaysDeny(t *testing.T) {
|
||||||
// TODO(etune): remove this test once a more comprehensive built-in authorizer is implemented.
|
// TODO(etune): remove this test once a more comprehensive built-in authorizer is implemented.
|
||||||
type allowAliceAuthorizer struct{}
|
type allowAliceAuthorizer struct{}
|
||||||
|
|
||||||
func (allowAliceAuthorizer) Authorize(a authorizer.Attributes) (bool, string, error) {
|
func (allowAliceAuthorizer) Authorize(a authorizer.Attributes) (authorizer.Decision, string, error) {
|
||||||
if a.GetUser() != nil && a.GetUser().GetName() == "alice" {
|
if a.GetUser() != nil && a.GetUser().GetName() == "alice" {
|
||||||
return true, "", nil
|
return authorizer.DecisionAllow, "", nil
|
||||||
}
|
}
|
||||||
return false, "I can't allow that. Go ask alice.", nil
|
return authorizer.DecisionNoOpinion, "I can't allow that. Go ask alice.", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestAliceNotForbiddenOrUnauthorized tests a user who is known to
|
// TestAliceNotForbiddenOrUnauthorized tests a user who is known to
|
||||||
|
@ -702,24 +702,24 @@ func TestUnknownUserIsUnauthorized(t *testing.T) {
|
||||||
type impersonateAuthorizer struct{}
|
type impersonateAuthorizer struct{}
|
||||||
|
|
||||||
// alice can't act as anyone and bob can't do anything but act-as someone
|
// alice can't act as anyone and bob can't do anything but act-as someone
|
||||||
func (impersonateAuthorizer) Authorize(a authorizer.Attributes) (bool, string, error) {
|
func (impersonateAuthorizer) Authorize(a authorizer.Attributes) (authorizer.Decision, string, error) {
|
||||||
// alice can impersonate service accounts and do other actions
|
// alice can impersonate service accounts and do other actions
|
||||||
if a.GetUser() != nil && a.GetUser().GetName() == "alice" && a.GetVerb() == "impersonate" && a.GetResource() == "serviceaccounts" {
|
if a.GetUser() != nil && a.GetUser().GetName() == "alice" && a.GetVerb() == "impersonate" && a.GetResource() == "serviceaccounts" {
|
||||||
return true, "", nil
|
return authorizer.DecisionAllow, "", nil
|
||||||
}
|
}
|
||||||
if a.GetUser() != nil && a.GetUser().GetName() == "alice" && a.GetVerb() != "impersonate" {
|
if a.GetUser() != nil && a.GetUser().GetName() == "alice" && a.GetVerb() != "impersonate" {
|
||||||
return true, "", nil
|
return authorizer.DecisionAllow, "", nil
|
||||||
}
|
}
|
||||||
// bob can impersonate anyone, but that it
|
// bob can impersonate anyone, but that it
|
||||||
if a.GetUser() != nil && a.GetUser().GetName() == "bob" && a.GetVerb() == "impersonate" {
|
if a.GetUser() != nil && a.GetUser().GetName() == "bob" && a.GetVerb() == "impersonate" {
|
||||||
return true, "", nil
|
return authorizer.DecisionAllow, "", nil
|
||||||
}
|
}
|
||||||
// service accounts can do everything
|
// service accounts can do everything
|
||||||
if a.GetUser() != nil && strings.HasPrefix(a.GetUser().GetName(), serviceaccount.ServiceAccountUsernamePrefix) {
|
if a.GetUser() != nil && strings.HasPrefix(a.GetUser().GetName(), serviceaccount.ServiceAccountUsernamePrefix) {
|
||||||
return true, "", nil
|
return authorizer.DecisionAllow, "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return false, "I can't allow that. Go ask alice.", nil
|
return authorizer.DecisionNoOpinion, "I can't allow that. Go ask alice.", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestImpersonateIsForbidden(t *testing.T) {
|
func TestImpersonateIsForbidden(t *testing.T) {
|
||||||
|
@ -861,9 +861,9 @@ type trackingAuthorizer struct {
|
||||||
requestAttributes []authorizer.Attributes
|
requestAttributes []authorizer.Attributes
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *trackingAuthorizer) Authorize(attributes authorizer.Attributes) (bool, string, error) {
|
func (a *trackingAuthorizer) Authorize(attributes authorizer.Attributes) (authorizer.Decision, string, error) {
|
||||||
a.requestAttributes = append(a.requestAttributes, attributes)
|
a.requestAttributes = append(a.requestAttributes, attributes)
|
||||||
return true, "", nil
|
return authorizer.DecisionAllow, "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestAuthorizationAttributeDetermination tests that authorization attributes are built correctly
|
// TestAuthorizationAttributeDetermination tests that authorization attributes are built correctly
|
||||||
|
|
|
@ -46,6 +46,7 @@ import (
|
||||||
"k8s.io/apiserver/pkg/authentication/authenticatorfactory"
|
"k8s.io/apiserver/pkg/authentication/authenticatorfactory"
|
||||||
authenticatorunion "k8s.io/apiserver/pkg/authentication/request/union"
|
authenticatorunion "k8s.io/apiserver/pkg/authentication/request/union"
|
||||||
"k8s.io/apiserver/pkg/authentication/user"
|
"k8s.io/apiserver/pkg/authentication/user"
|
||||||
|
"k8s.io/apiserver/pkg/authorization/authorizer"
|
||||||
authauthorizer "k8s.io/apiserver/pkg/authorization/authorizer"
|
authauthorizer "k8s.io/apiserver/pkg/authorization/authorizer"
|
||||||
"k8s.io/apiserver/pkg/authorization/authorizerfactory"
|
"k8s.io/apiserver/pkg/authorization/authorizerfactory"
|
||||||
authorizerunion "k8s.io/apiserver/pkg/authorization/union"
|
authorizerunion "k8s.io/apiserver/pkg/authorization/union"
|
||||||
|
@ -148,8 +149,8 @@ func NewMasterComponents(c *Config) *MasterComponents {
|
||||||
// alwaysAllow always allows an action
|
// alwaysAllow always allows an action
|
||||||
type alwaysAllow struct{}
|
type alwaysAllow struct{}
|
||||||
|
|
||||||
func (alwaysAllow) Authorize(requestAttributes authauthorizer.Attributes) (bool, string, error) {
|
func (alwaysAllow) Authorize(requestAttributes authauthorizer.Attributes) (authorizer.Decision, string, error) {
|
||||||
return true, "always allow", nil
|
return authorizer.DecisionAllow, "always allow", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// alwaysEmpty simulates "no authentication" for old tests
|
// alwaysEmpty simulates "no authentication" for old tests
|
||||||
|
|
|
@ -58,11 +58,11 @@ const (
|
||||||
|
|
||||||
type allowAliceAuthorizer struct{}
|
type allowAliceAuthorizer struct{}
|
||||||
|
|
||||||
func (allowAliceAuthorizer) Authorize(a authorizer.Attributes) (bool, string, error) {
|
func (allowAliceAuthorizer) Authorize(a authorizer.Attributes) (authorizer.Decision, string, error) {
|
||||||
if a.GetUser() != nil && a.GetUser().GetName() == "alice" {
|
if a.GetUser() != nil && a.GetUser().GetName() == "alice" {
|
||||||
return true, "", nil
|
return authorizer.DecisionAllow, "", nil
|
||||||
}
|
}
|
||||||
return false, "I can't allow that. Go ask alice.", nil
|
return authorizer.DecisionNoOpinion, "I can't allow that. Go ask alice.", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func testPrefix(t *testing.T, prefix string) {
|
func testPrefix(t *testing.T, prefix string) {
|
||||||
|
|
|
@ -372,7 +372,7 @@ func startServiceAccountTestServer(t *testing.T) (*clientset.Clientset, restclie
|
||||||
// 1. The "root" user is allowed to do anything
|
// 1. The "root" user is allowed to do anything
|
||||||
// 2. ServiceAccounts named "ro" are allowed read-only operations in their namespace
|
// 2. ServiceAccounts named "ro" are allowed read-only operations in their namespace
|
||||||
// 3. ServiceAccounts named "rw" are allowed any operation in their namespace
|
// 3. ServiceAccounts named "rw" are allowed any operation in their namespace
|
||||||
authorizer := authorizer.AuthorizerFunc(func(attrs authorizer.Attributes) (bool, string, error) {
|
authorizer := authorizer.AuthorizerFunc(func(attrs authorizer.Attributes) (authorizer.Decision, string, error) {
|
||||||
username := ""
|
username := ""
|
||||||
if user := attrs.GetUser(); user != nil {
|
if user := attrs.GetUser(); user != nil {
|
||||||
username = user.GetName()
|
username = user.GetName()
|
||||||
|
@ -382,7 +382,7 @@ func startServiceAccountTestServer(t *testing.T) (*clientset.Clientset, restclie
|
||||||
// If the user is "root"...
|
// If the user is "root"...
|
||||||
if username == rootUserName {
|
if username == rootUserName {
|
||||||
// allow them to do anything
|
// allow them to do anything
|
||||||
return true, "", nil
|
return authorizer.DecisionAllow, "", nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the user is a service account...
|
// If the user is a service account...
|
||||||
|
@ -392,15 +392,15 @@ func startServiceAccountTestServer(t *testing.T) (*clientset.Clientset, restclie
|
||||||
switch serviceAccountName {
|
switch serviceAccountName {
|
||||||
case readOnlyServiceAccountName:
|
case readOnlyServiceAccountName:
|
||||||
if attrs.IsReadOnly() {
|
if attrs.IsReadOnly() {
|
||||||
return true, "", nil
|
return authorizer.DecisionAllow, "", nil
|
||||||
}
|
}
|
||||||
case readWriteServiceAccountName:
|
case readWriteServiceAccountName:
|
||||||
return true, "", nil
|
return authorizer.DecisionAllow, "", nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return false, fmt.Sprintf("User %s is denied (ns=%s, readonly=%v, resource=%s)", username, ns, attrs.IsReadOnly(), attrs.GetResource()), nil
|
return authorizer.DecisionNoOpinion, fmt.Sprintf("User %s is denied (ns=%s, readonly=%v, resource=%s)", username, ns, attrs.IsReadOnly(), attrs.GetResource()), nil
|
||||||
})
|
})
|
||||||
|
|
||||||
// Set up admission plugin to auto-assign serviceaccounts to pods
|
// Set up admission plugin to auto-assign serviceaccounts to pods
|
||||||
|
|
Loading…
Reference in New Issue