Merge pull request #39383 from liggitt/bind-check

Automatic merge from submit-queue (batch tested with PRs 39694, 39383, 39651, 39691, 39497)

Allow rolebinding/clusterrolebinding with explicit bind permission check

Fixes https://github.com/kubernetes/kubernetes/issues/39176
Fixes https://github.com/kubernetes/kubernetes/issues/39258

Allows creating/updating a rolebinding/clusterrolebinding if the user has explicitly been granted permission to perform the "bind" verb against the referenced role/clusterrole (previously, they could only bind if they already had all the permissions in the referenced role via an RBAC role themselves)

```release-note
To create or update an RBAC RoleBinding or ClusterRoleBinding object, a user must:
1. Be authorized to make the create or update API request
2. Be allowed to bind the referenced role, either by already having all of the permissions contained in the referenced role, or by having the "bind" permission on the referenced role.
```
This commit is contained in:
Kubernetes Submit Queue
2017-01-10 21:25:13 -08:00
committed by GitHub
11 changed files with 160 additions and 12 deletions

View File

@@ -168,6 +168,25 @@ func (s statusCode) String() string {
// Declare a set of raw objects to use.
var (
writeJobsRoleBinding = `
{
"apiVersion": "rbac.authorization.k8s.io/v1alpha1",
"kind": "RoleBinding",
"metadata": {
"name": "pi"%s
},
"roleRef": {
"apiGroup": "rbac.authorization.k8s.io",
"kind": "ClusterRole",
"name": "write-jobs"
},
"subjects": [{
"apiVersion": "rbac/v1alpha1",
"kind": "User",
"name": "admin"
}]
}`
aJob = `
{
"apiVersion": "batch/v1",
@@ -291,6 +310,18 @@ func TestRBAC(t *testing.T) {
ObjectMeta: api.ObjectMeta{Name: "write-jobs"},
Rules: []rbacapi.PolicyRule{ruleWriteJobs},
},
{
ObjectMeta: api.ObjectMeta{Name: "create-rolebindings"},
Rules: []rbacapi.PolicyRule{
rbacapi.NewRule("create").Groups("rbac.authorization.k8s.io").Resources("rolebindings").RuleOrDie(),
},
},
{
ObjectMeta: api.ObjectMeta{Name: "bind-any-clusterrole"},
Rules: []rbacapi.PolicyRule{
rbacapi.NewRule("bind").Groups("rbac.authorization.k8s.io").Resources("clusterroles").RuleOrDie(),
},
},
},
clusterRoleBindings: []rbacapi.ClusterRoleBinding{
{
@@ -298,6 +329,20 @@ func TestRBAC(t *testing.T) {
Subjects: []rbacapi.Subject{{Kind: "User", Name: "job-writer"}},
RoleRef: rbacapi.RoleRef{Kind: "ClusterRole", Name: "write-jobs"},
},
{
ObjectMeta: api.ObjectMeta{Name: "create-rolebindings"},
Subjects: []rbacapi.Subject{
{Kind: "User", Name: "job-writer"},
{Kind: "User", Name: "nonescalating-rolebinding-writer"},
{Kind: "User", Name: "any-rolebinding-writer"},
},
RoleRef: rbacapi.RoleRef{Kind: "ClusterRole", Name: "create-rolebindings"},
},
{
ObjectMeta: api.ObjectMeta{Name: "bind-any-clusterrole"},
Subjects: []rbacapi.Subject{{Kind: "User", Name: "any-rolebinding-writer"}},
RoleRef: rbacapi.RoleRef{Kind: "ClusterRole", Name: "bind-any-clusterrole"},
},
},
roleBindings: []rbacapi.RoleBinding{
{
@@ -305,6 +350,11 @@ func TestRBAC(t *testing.T) {
Subjects: []rbacapi.Subject{{Kind: "User", Name: "job-writer-namespace"}},
RoleRef: rbacapi.RoleRef{Kind: "ClusterRole", Name: "write-jobs"},
},
{
ObjectMeta: api.ObjectMeta{Name: "create-rolebindings", Namespace: "job-namespace"},
Subjects: []rbacapi.Subject{{Kind: "User", Name: "job-writer-namespace"}},
RoleRef: rbacapi.RoleRef{Kind: "ClusterRole", Name: "create-rolebindings"},
},
},
},
requests: []request{
@@ -331,6 +381,21 @@ func TestRBAC(t *testing.T) {
{"job-writer-namespace", "GET", "batch", "jobs", "job-namespace", "pi", "", http.StatusNotFound},
{"job-writer-namespace", "POST", "batch", "jobs", "job-namespace", "", aJob, http.StatusCreated},
{"job-writer-namespace", "GET", "batch", "jobs", "job-namespace", "pi", "", http.StatusOK},
// cannot bind role anywhere
{"user-with-no-permissions", "POST", "rbac.authorization.k8s.io", "rolebindings", "job-namespace", "", writeJobsRoleBinding, http.StatusForbidden},
// can only bind role in namespace where they have covering permissions
{"job-writer-namespace", "POST", "rbac.authorization.k8s.io", "rolebindings", "forbidden-namespace", "", writeJobsRoleBinding, http.StatusForbidden},
{"job-writer-namespace", "POST", "rbac.authorization.k8s.io", "rolebindings", "job-namespace", "", writeJobsRoleBinding, http.StatusCreated},
{superUser, "DELETE", "rbac.authorization.k8s.io", "rolebindings", "job-namespace", "pi", "", http.StatusOK},
// can bind role in any namespace where they have covering permissions
{"job-writer", "POST", "rbac.authorization.k8s.io", "rolebindings", "forbidden-namespace", "", writeJobsRoleBinding, http.StatusCreated},
{superUser, "DELETE", "rbac.authorization.k8s.io", "rolebindings", "forbidden-namespace", "pi", "", http.StatusOK},
// cannot bind role because they don't have covering permissions
{"nonescalating-rolebinding-writer", "POST", "rbac.authorization.k8s.io", "rolebindings", "job-namespace", "", writeJobsRoleBinding, http.StatusForbidden},
// can bind role because they have explicit bind permission
{"any-rolebinding-writer", "POST", "rbac.authorization.k8s.io", "rolebindings", "job-namespace", "", writeJobsRoleBinding, http.StatusCreated},
{superUser, "DELETE", "rbac.authorization.k8s.io", "rolebindings", "job-namespace", "pi", "", http.StatusOK},
},
},
}