From 1e7adaa5c045765f587e85c3fdbf442f86aa9b9d Mon Sep 17 00:00:00 2001 From: deads2k Date: Wed, 3 Aug 2016 08:19:57 -0400 Subject: [PATCH] allow restricting subresource access --- plugin/pkg/auth/authorizer/rbac/rbac.go | 6 +- plugin/pkg/auth/authorizer/rbac/rbac_test.go | 63 +++++++++++++++----- 2 files changed, 52 insertions(+), 17 deletions(-) diff --git a/plugin/pkg/auth/authorizer/rbac/rbac.go b/plugin/pkg/auth/authorizer/rbac/rbac.go index bfcb49d16c1..30e6eb5339d 100644 --- a/plugin/pkg/auth/authorizer/rbac/rbac.go +++ b/plugin/pkg/auth/authorizer/rbac/rbac.go @@ -44,10 +44,14 @@ func (r *RBACAuthorizer) Authorize(attr authorizer.Attributes) (bool, string, er // Frame the authorization request as a privilege escalation check. var requestedRule rbac.PolicyRule if attr.IsResourceRequest() { + resource := attr.GetResource() + if len(attr.GetSubresource()) > 0 { + resource = attr.GetResource() + "/" + attr.GetSubresource() + } requestedRule = rbac.PolicyRule{ Verbs: []string{attr.GetVerb()}, APIGroups: []string{attr.GetAPIGroup()}, // TODO(ericchiang): add api version here too? - Resources: []string{attr.GetResource()}, + Resources: []string{resource}, ResourceNames: []string{attr.GetName()}, } } else { diff --git a/plugin/pkg/auth/authorizer/rbac/rbac_test.go b/plugin/pkg/auth/authorizer/rbac/rbac_test.go index 6eefddf0add..892faa81674 100644 --- a/plugin/pkg/auth/authorizer/rbac/rbac_test.go +++ b/plugin/pkg/auth/authorizer/rbac/rbac_test.go @@ -86,12 +86,13 @@ func newRoleBinding(namespace, roleName string, bindType uint16, subjects ...str } type defaultAttributes struct { - user string - groups string - verb string - resource string - namespace string - apiGroup string + user string + groups string + verb string + resource string + subresource string + namespace string + apiGroup string } func (d *defaultAttributes) String() string { @@ -106,7 +107,7 @@ func (d *defaultAttributes) GetVerb() string { return d.verb } func (d *defaultAttributes) IsReadOnly() bool { return d.verb == "get" || d.verb == "watch" } func (d *defaultAttributes) GetNamespace() string { return d.namespace } func (d *defaultAttributes) GetResource() string { return d.resource } -func (d *defaultAttributes) GetSubresource() string { return "" } +func (d *defaultAttributes) GetSubresource() string { return d.subresource } func (d *defaultAttributes) GetName() string { return "" } func (d *defaultAttributes) GetAPIGroup() string { return d.apiGroup } func (d *defaultAttributes) GetAPIVersion() string { return "" } @@ -133,17 +134,17 @@ func TestAuthorizer(t *testing.T) { newRoleBinding("ns1", "admin", bindToClusterRole, "User:admin", "Group:admins"), }, shouldPass: []authorizer.Attributes{ - &defaultAttributes{"admin", "", "get", "Pods", "ns1", ""}, - &defaultAttributes{"admin", "", "watch", "Pods", "ns1", ""}, - &defaultAttributes{"admin", "group1", "watch", "Foobar", "ns1", ""}, - &defaultAttributes{"joe", "admins", "watch", "Foobar", "ns1", ""}, - &defaultAttributes{"joe", "group1,admins", "watch", "Foobar", "ns1", ""}, + &defaultAttributes{"admin", "", "get", "Pods", "", "ns1", ""}, + &defaultAttributes{"admin", "", "watch", "Pods", "", "ns1", ""}, + &defaultAttributes{"admin", "group1", "watch", "Foobar", "", "ns1", ""}, + &defaultAttributes{"joe", "admins", "watch", "Foobar", "", "ns1", ""}, + &defaultAttributes{"joe", "group1,admins", "watch", "Foobar", "", "ns1", ""}, }, shouldFail: []authorizer.Attributes{ - &defaultAttributes{"admin", "", "GET", "Pods", "ns2", ""}, - &defaultAttributes{"admin", "", "GET", "Nodes", "", ""}, - &defaultAttributes{"admin", "admins", "GET", "Pods", "ns2", ""}, - &defaultAttributes{"admin", "admins", "GET", "Nodes", "", ""}, + &defaultAttributes{"admin", "", "GET", "Pods", "", "ns2", ""}, + &defaultAttributes{"admin", "", "GET", "Nodes", "", "", ""}, + &defaultAttributes{"admin", "admins", "GET", "Pods", "", "ns2", ""}, + &defaultAttributes{"admin", "admins", "GET", "Nodes", "", "", ""}, }, }, { @@ -187,6 +188,36 @@ func TestAuthorizer(t *testing.T) { authorizer.AttributesRecord{User: &user.DefaultInfo{Groups: []string{"prefixed"}}, Verb: "get", Path: "/api/v1"}, }, }, + { + // test subresource resolution + clusterRoles: []rbac.ClusterRole{ + newClusterRole("admin", newRule("*", "*", "pods", "*")), + }, + roleBindings: []rbac.RoleBinding{ + newRoleBinding("ns1", "admin", bindToClusterRole, "User:admin", "Group:admins"), + }, + shouldPass: []authorizer.Attributes{ + &defaultAttributes{"admin", "", "get", "pods", "", "ns1", ""}, + }, + shouldFail: []authorizer.Attributes{ + &defaultAttributes{"admin", "", "get", "pods", "status", "ns1", ""}, + }, + }, + { + // test subresource resolution + clusterRoles: []rbac.ClusterRole{ + newClusterRole("admin", newRule("*", "*", "pods/status", "*")), + }, + roleBindings: []rbac.RoleBinding{ + newRoleBinding("ns1", "admin", bindToClusterRole, "User:admin", "Group:admins"), + }, + shouldPass: []authorizer.Attributes{ + &defaultAttributes{"admin", "", "get", "pods", "status", "ns1", ""}, + }, + shouldFail: []authorizer.Attributes{ + &defaultAttributes{"admin", "", "get", "pods", "", "ns1", ""}, + }, + }, } for i, tt := range tests { ruleResolver := validation.NewTestRuleResolver(tt.roles, tt.roleBindings, tt.clusterRoles, tt.clusterRoleBindings)