mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-09-17 23:19:26 +00:00
move authorizers over to new interface
This commit is contained in:
@@ -104,8 +104,8 @@ func (a *gcPermissionsEnforcement) Validate(attributes admission.Attributes) (er
|
||||
ResourceRequest: true,
|
||||
Path: "",
|
||||
}
|
||||
allowed, reason, err := a.authorizer.Authorize(deleteAttributes)
|
||||
if !allowed {
|
||||
decision, reason, err := a.authorizer.Authorize(deleteAttributes)
|
||||
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))
|
||||
}
|
||||
|
||||
@@ -122,8 +122,8 @@ func (a *gcPermissionsEnforcement) Validate(attributes admission.Attributes) (er
|
||||
// resources. User needs to have delete permission on all the
|
||||
// matched Resources.
|
||||
for _, record := range records {
|
||||
allowed, reason, err := a.authorizer.Authorize(record)
|
||||
if !allowed {
|
||||
decision, reason, err := a.authorizer.Authorize(record)
|
||||
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))
|
||||
}
|
||||
}
|
||||
|
@@ -34,40 +34,40 @@ import (
|
||||
|
||||
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()
|
||||
|
||||
if username == "non-deleter" {
|
||||
if a.GetVerb() == "delete" {
|
||||
return false, "", nil
|
||||
return authorizer.DecisionNoOpinion, "", nil
|
||||
}
|
||||
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 a.GetVerb() == "delete" && a.GetResource() == "pods" {
|
||||
return false, "", nil
|
||||
return authorizer.DecisionNoOpinion, "", nil
|
||||
}
|
||||
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 a.GetVerb() == "delete" && a.GetResource() == "replicationcontrollers" {
|
||||
return false, "", nil
|
||||
return authorizer.DecisionNoOpinion, "", nil
|
||||
}
|
||||
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.
|
||||
|
@@ -313,11 +313,11 @@ func authorizedForPolicy(info user.Info, namespace string, policy *extensions.Po
|
||||
return false
|
||||
}
|
||||
attr := buildAttributes(info, namespace, policy)
|
||||
allowed, reason, err := authz.Authorize(attr)
|
||||
decision, reason, err := authz.Authorize(attr)
|
||||
if err != nil {
|
||||
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.
|
||||
|
@@ -66,13 +66,16 @@ type TestAuthorizer struct {
|
||||
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 {
|
||||
return true, "", nil
|
||||
return authorizer.DecisionAllow, "", nil
|
||||
}
|
||||
allowedInNamespace := t.usernameToNamespaceToAllowedPSPs[a.GetUser().GetName()][a.GetNamespace()][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{}
|
||||
|
@@ -64,16 +64,16 @@ var (
|
||||
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())
|
||||
if !isNode {
|
||||
// reject requests from non-nodes
|
||||
return false, "", nil
|
||||
return authorizer.DecisionNoOpinion, "", nil
|
||||
}
|
||||
if len(nodeName) == 0 {
|
||||
// reject requests from unidentifiable nodes
|
||||
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
|
||||
@@ -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
|
||||
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
|
||||
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 {
|
||||
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 {
|
||||
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())
|
||||
if err != nil {
|
||||
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 {
|
||||
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
|
||||
|
@@ -57,71 +57,71 @@ func TestAuthorizer(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
attrs authorizer.AttributesRecord
|
||||
expect bool
|
||||
expect authorizer.Decision
|
||||
}{
|
||||
{
|
||||
name: "allowed configmap",
|
||||
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",
|
||||
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",
|
||||
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",
|
||||
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",
|
||||
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",
|
||||
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",
|
||||
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",
|
||||
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",
|
||||
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",
|
||||
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",
|
||||
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 {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
ok, _, _ := authz.Authorize(tc.attrs)
|
||||
if ok != tc.expect {
|
||||
t.Errorf("expected %v, got %v", tc.expect, ok)
|
||||
decision, _, _ := authz.Authorize(tc.attrs)
|
||||
if decision != tc.expect {
|
||||
t.Errorf("expected %v, got %v", tc.expect, decision)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -186,13 +186,13 @@ func TestAuthorizerSharedResources(t *testing.T) {
|
||||
}
|
||||
|
||||
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 {
|
||||
t.Errorf("%d: unexpected error: %v", i, err)
|
||||
continue
|
||||
}
|
||||
if ok != tc.ExpectAllowed {
|
||||
t.Errorf("%d: expected %v, got %v", i, tc.ExpectAllowed, ok)
|
||||
if (decision == authorizer.DecisionAllow) != tc.ExpectAllowed {
|
||||
t.Errorf("%d: expected %v, got %v", i, tc.ExpectAllowed, decision)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -301,47 +301,47 @@ func BenchmarkAuthorization(b *testing.B) {
|
||||
tests := []struct {
|
||||
name string
|
||||
attrs authorizer.AttributesRecord
|
||||
expect bool
|
||||
expect authorizer.Decision
|
||||
}{
|
||||
{
|
||||
name: "allowed configmap",
|
||||
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",
|
||||
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",
|
||||
attrs: authorizer.AttributesRecord{User: node0, ResourceRequest: true, Verb: "get", Resource: "secrets", Name: "secret0-shared", Namespace: "ns0"},
|
||||
expect: true,
|
||||
expect: authorizer.DecisionAllow,
|
||||
},
|
||||
{
|
||||
name: "disallowed configmap",
|
||||
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",
|
||||
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",
|
||||
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",
|
||||
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",
|
||||
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 {
|
||||
b.Run(tc.name, func(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
ok, _, _ := authz.Authorize(tc.attrs)
|
||||
if ok != tc.expect {
|
||||
b.Errorf("expected %v, got %v", tc.expect, ok)
|
||||
decision, _, _ := authz.Authorize(tc.attrs)
|
||||
if decision != tc.expect {
|
||||
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
|
||||
}
|
||||
|
||||
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}
|
||||
|
||||
r.authorizationRuleResolver.VisitRulesFor(requestAttributes.GetUser(), requestAttributes.GetNamespace(), ruleCheckingVisitor.visit)
|
||||
if ruleCheckingVisitor.allowed {
|
||||
return true, "", nil
|
||||
return authorizer.DecisionAllow, "", nil
|
||||
}
|
||||
|
||||
// Build a detailed log of the denial.
|
||||
@@ -120,7 +120,7 @@ func (r *RBACAuthorizer) Authorize(requestAttributes authorizer.Attributes) (boo
|
||||
if len(ruleCheckingVisitor.errors) > 0 {
|
||||
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) {
|
||||
|
@@ -247,13 +247,13 @@ func TestAuthorizer(t *testing.T) {
|
||||
ruleResolver, _ := rbacregistryvalidation.NewTestRuleResolver(tt.roles, tt.roleBindings, tt.clusterRoles, tt.clusterRoleBindings)
|
||||
a := RBACAuthorizer{ruleResolver}
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user