| ... | ... |
@@ -14618,6 +14618,7 @@ |
| 14618 | 14618 |
"required": [ |
| 14619 | 14619 |
"userNames", |
| 14620 | 14620 |
"groupNames", |
| 14621 |
+ "subjects", |
|
| 14621 | 14622 |
"roleRef" |
| 14622 | 14623 |
], |
| 14623 | 14624 |
"properties": {
|
| ... | ... |
@@ -14646,6 +14647,13 @@ |
| 14646 | 14646 |
}, |
| 14647 | 14647 |
"description": "all the groups directly bound to the role" |
| 14648 | 14648 |
}, |
| 14649 |
+ "subjects": {
|
|
| 14650 |
+ "type": "array", |
|
| 14651 |
+ "items": {
|
|
| 14652 |
+ "$ref": "v1.ObjectReference" |
|
| 14653 |
+ }, |
|
| 14654 |
+ "description": "references to subjects bound to the role. Only User, Group, SystemUser, SystemGroup, and ServiceAccount are allowed." |
|
| 14655 |
+ }, |
|
| 14649 | 14656 |
"roleRef": {
|
| 14650 | 14657 |
"$ref": "v1.ObjectReference", |
| 14651 | 14658 |
"description": "reference to the policy role" |
| ... | ... |
@@ -16900,6 +16908,7 @@ |
| 16900 | 16900 |
"required": [ |
| 16901 | 16901 |
"userNames", |
| 16902 | 16902 |
"groupNames", |
| 16903 |
+ "subjects", |
|
| 16903 | 16904 |
"roleRef" |
| 16904 | 16905 |
], |
| 16905 | 16906 |
"properties": {
|
| ... | ... |
@@ -16928,6 +16937,13 @@ |
| 16928 | 16928 |
}, |
| 16929 | 16929 |
"description": "all the groups directly bound to the role" |
| 16930 | 16930 |
}, |
| 16931 |
+ "subjects": {
|
|
| 16932 |
+ "type": "array", |
|
| 16933 |
+ "items": {
|
|
| 16934 |
+ "$ref": "v1.ObjectReference" |
|
| 16935 |
+ }, |
|
| 16936 |
+ "description": "references to subjects bound to the role. Only User, Group, SystemUser, SystemGroup, and ServiceAccount are allowed." |
|
| 16937 |
+ }, |
|
| 16931 | 16938 |
"roleRef": {
|
| 16932 | 16939 |
"$ref": "v1.ObjectReference", |
| 16933 | 16940 |
"description": "a reference to a role" |
| ... | ... |
@@ -181,29 +181,17 @@ func deepCopy_api_ClusterRoleBinding(in api.ClusterRoleBinding, out *api.Cluster |
| 181 | 181 |
} else {
|
| 182 | 182 |
out.ObjectMeta = newVal.(pkgapi.ObjectMeta) |
| 183 | 183 |
} |
| 184 |
- if in.Users != nil {
|
|
| 185 |
- out.Users = make(util.StringSet) |
|
| 186 |
- for key, val := range in.Users {
|
|
| 187 |
- if newVal, err := c.DeepCopy(val); err != nil {
|
|
| 188 |
- return err |
|
| 189 |
- } else {
|
|
| 190 |
- out.Users[key] = newVal.(util.Empty) |
|
| 191 |
- } |
|
| 192 |
- } |
|
| 193 |
- } else {
|
|
| 194 |
- out.Users = nil |
|
| 195 |
- } |
|
| 196 |
- if in.Groups != nil {
|
|
| 197 |
- out.Groups = make(util.StringSet) |
|
| 198 |
- for key, val := range in.Groups {
|
|
| 199 |
- if newVal, err := c.DeepCopy(val); err != nil {
|
|
| 184 |
+ if in.Subjects != nil {
|
|
| 185 |
+ out.Subjects = make([]pkgapi.ObjectReference, len(in.Subjects)) |
|
| 186 |
+ for i := range in.Subjects {
|
|
| 187 |
+ if newVal, err := c.DeepCopy(in.Subjects[i]); err != nil {
|
|
| 200 | 188 |
return err |
| 201 | 189 |
} else {
|
| 202 |
- out.Groups[key] = newVal.(util.Empty) |
|
| 190 |
+ out.Subjects[i] = newVal.(pkgapi.ObjectReference) |
|
| 203 | 191 |
} |
| 204 | 192 |
} |
| 205 | 193 |
} else {
|
| 206 |
- out.Groups = nil |
|
| 194 |
+ out.Subjects = nil |
|
| 207 | 195 |
} |
| 208 | 196 |
if newVal, err := c.DeepCopy(in.RoleRef); err != nil {
|
| 209 | 197 |
return err |
| ... | ... |
@@ -560,29 +548,17 @@ func deepCopy_api_RoleBinding(in api.RoleBinding, out *api.RoleBinding, c *conve |
| 560 | 560 |
} else {
|
| 561 | 561 |
out.ObjectMeta = newVal.(pkgapi.ObjectMeta) |
| 562 | 562 |
} |
| 563 |
- if in.Users != nil {
|
|
| 564 |
- out.Users = make(util.StringSet) |
|
| 565 |
- for key, val := range in.Users {
|
|
| 566 |
- if newVal, err := c.DeepCopy(val); err != nil {
|
|
| 567 |
- return err |
|
| 568 |
- } else {
|
|
| 569 |
- out.Users[key] = newVal.(util.Empty) |
|
| 570 |
- } |
|
| 571 |
- } |
|
| 572 |
- } else {
|
|
| 573 |
- out.Users = nil |
|
| 574 |
- } |
|
| 575 |
- if in.Groups != nil {
|
|
| 576 |
- out.Groups = make(util.StringSet) |
|
| 577 |
- for key, val := range in.Groups {
|
|
| 578 |
- if newVal, err := c.DeepCopy(val); err != nil {
|
|
| 563 |
+ if in.Subjects != nil {
|
|
| 564 |
+ out.Subjects = make([]pkgapi.ObjectReference, len(in.Subjects)) |
|
| 565 |
+ for i := range in.Subjects {
|
|
| 566 |
+ if newVal, err := c.DeepCopy(in.Subjects[i]); err != nil {
|
|
| 579 | 567 |
return err |
| 580 | 568 |
} else {
|
| 581 |
- out.Groups[key] = newVal.(util.Empty) |
|
| 569 |
+ out.Subjects[i] = newVal.(pkgapi.ObjectReference) |
|
| 582 | 570 |
} |
| 583 | 571 |
} |
| 584 | 572 |
} else {
|
| 585 |
- out.Groups = nil |
|
| 573 |
+ out.Subjects = nil |
|
| 586 | 574 |
} |
| 587 | 575 |
if newVal, err := c.DeepCopy(in.RoleRef); err != nil {
|
| 588 | 576 |
return err |
| ... | ... |
@@ -1,6 +1,7 @@ |
| 1 | 1 |
package api_test |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 |
+ "fmt" |
|
| 4 | 5 |
"math/rand" |
| 5 | 6 |
"reflect" |
| 6 | 7 |
"strings" |
| ... | ... |
@@ -11,8 +12,10 @@ import ( |
| 11 | 11 |
"k8s.io/kubernetes/pkg/api" |
| 12 | 12 |
"k8s.io/kubernetes/pkg/api/meta" |
| 13 | 13 |
apitesting "k8s.io/kubernetes/pkg/api/testing" |
| 14 |
+ "k8s.io/kubernetes/pkg/api/validation" |
|
| 14 | 15 |
"k8s.io/kubernetes/pkg/conversion" |
| 15 | 16 |
"k8s.io/kubernetes/pkg/runtime" |
| 17 |
+ "k8s.io/kubernetes/pkg/types" |
|
| 16 | 18 |
"k8s.io/kubernetes/pkg/util" |
| 17 | 19 |
|
| 18 | 20 |
osapi "github.com/openshift/origin/pkg/api" |
| ... | ... |
@@ -24,6 +27,7 @@ import ( |
| 24 | 24 |
deploy "github.com/openshift/origin/pkg/deploy/api" |
| 25 | 25 |
image "github.com/openshift/origin/pkg/image/api" |
| 26 | 26 |
template "github.com/openshift/origin/pkg/template/api" |
| 27 |
+ uservalidation "github.com/openshift/origin/pkg/user/api/validation" |
|
| 27 | 28 |
) |
| 28 | 29 |
|
| 29 | 30 |
func fuzzInternalObject(t *testing.T, forVersion string, item runtime.Object, seed int64) runtime.Object {
|
| ... | ... |
@@ -42,6 +46,82 @@ func fuzzInternalObject(t *testing.T, forVersion string, item runtime.Object, se |
| 42 | 42 |
func(j *authorizationapi.ClusterPolicyBinding, c fuzz.Continue) {
|
| 43 | 43 |
j.RoleBindings = make(map[string]*authorizationapi.ClusterRoleBinding) |
| 44 | 44 |
}, |
| 45 |
+ func(j *authorizationapi.RoleBinding, c fuzz.Continue) {
|
|
| 46 |
+ c.FuzzNoCustom(j) |
|
| 47 |
+ for i := range j.Subjects {
|
|
| 48 |
+ kinds := []string{authorizationapi.UserKind, authorizationapi.SystemUserKind, authorizationapi.GroupKind, authorizationapi.SystemGroupKind, authorizationapi.ServiceAccountKind}
|
|
| 49 |
+ j.Subjects[i].Kind = kinds[c.Intn(len(kinds))] |
|
| 50 |
+ switch j.Subjects[i].Kind {
|
|
| 51 |
+ case authorizationapi.UserKind: |
|
| 52 |
+ j.Subjects[i].Namespace = "" |
|
| 53 |
+ if valid, _ := uservalidation.ValidateUserName(j.Subjects[i].Name, false); !valid {
|
|
| 54 |
+ j.Subjects[i].Name = fmt.Sprintf("validusername%d", i)
|
|
| 55 |
+ } |
|
| 56 |
+ |
|
| 57 |
+ case authorizationapi.GroupKind: |
|
| 58 |
+ j.Subjects[i].Namespace = "" |
|
| 59 |
+ if valid, _ := uservalidation.ValidateGroupName(j.Subjects[i].Name, false); !valid {
|
|
| 60 |
+ j.Subjects[i].Name = fmt.Sprintf("validgroupname%d", i)
|
|
| 61 |
+ } |
|
| 62 |
+ |
|
| 63 |
+ case authorizationapi.ServiceAccountKind: |
|
| 64 |
+ if valid, _ := validation.ValidateNamespaceName(j.Subjects[i].Namespace, false); !valid {
|
|
| 65 |
+ j.Subjects[i].Namespace = fmt.Sprintf("sanamespacehere%d", i)
|
|
| 66 |
+ } |
|
| 67 |
+ if valid, _ := validation.ValidateServiceAccountName(j.Subjects[i].Name, false); !valid {
|
|
| 68 |
+ j.Subjects[i].Name = fmt.Sprintf("sanamehere%d", i)
|
|
| 69 |
+ } |
|
| 70 |
+ |
|
| 71 |
+ case authorizationapi.SystemUserKind, authorizationapi.SystemGroupKind: |
|
| 72 |
+ j.Subjects[i].Namespace = "" |
|
| 73 |
+ j.Subjects[i].Name = ":" + j.Subjects[i].Name |
|
| 74 |
+ |
|
| 75 |
+ } |
|
| 76 |
+ |
|
| 77 |
+ j.Subjects[i].UID = types.UID("")
|
|
| 78 |
+ j.Subjects[i].APIVersion = "" |
|
| 79 |
+ j.Subjects[i].ResourceVersion = "" |
|
| 80 |
+ j.Subjects[i].FieldPath = "" |
|
| 81 |
+ } |
|
| 82 |
+ }, |
|
| 83 |
+ func(j *authorizationapi.ClusterRoleBinding, c fuzz.Continue) {
|
|
| 84 |
+ c.FuzzNoCustom(j) |
|
| 85 |
+ for i := range j.Subjects {
|
|
| 86 |
+ kinds := []string{authorizationapi.UserKind, authorizationapi.SystemUserKind, authorizationapi.GroupKind, authorizationapi.SystemGroupKind, authorizationapi.ServiceAccountKind}
|
|
| 87 |
+ j.Subjects[i].Kind = kinds[c.Intn(len(kinds))] |
|
| 88 |
+ switch j.Subjects[i].Kind {
|
|
| 89 |
+ case authorizationapi.UserKind: |
|
| 90 |
+ j.Subjects[i].Namespace = "" |
|
| 91 |
+ if valid, _ := uservalidation.ValidateUserName(j.Subjects[i].Name, false); !valid {
|
|
| 92 |
+ j.Subjects[i].Name = fmt.Sprintf("validusername%d", i)
|
|
| 93 |
+ } |
|
| 94 |
+ |
|
| 95 |
+ case authorizationapi.GroupKind: |
|
| 96 |
+ j.Subjects[i].Namespace = "" |
|
| 97 |
+ if valid, _ := uservalidation.ValidateGroupName(j.Subjects[i].Name, false); !valid {
|
|
| 98 |
+ j.Subjects[i].Name = fmt.Sprintf("validgroupname%d", i)
|
|
| 99 |
+ } |
|
| 100 |
+ |
|
| 101 |
+ case authorizationapi.ServiceAccountKind: |
|
| 102 |
+ if valid, _ := validation.ValidateNamespaceName(j.Subjects[i].Namespace, false); !valid {
|
|
| 103 |
+ j.Subjects[i].Namespace = fmt.Sprintf("sanamespacehere%d", i)
|
|
| 104 |
+ } |
|
| 105 |
+ if valid, _ := validation.ValidateServiceAccountName(j.Subjects[i].Name, false); !valid {
|
|
| 106 |
+ j.Subjects[i].Name = fmt.Sprintf("sanamehere%d", i)
|
|
| 107 |
+ } |
|
| 108 |
+ |
|
| 109 |
+ case authorizationapi.SystemUserKind, authorizationapi.SystemGroupKind: |
|
| 110 |
+ j.Subjects[i].Namespace = "" |
|
| 111 |
+ j.Subjects[i].Name = ":" + j.Subjects[i].Name |
|
| 112 |
+ |
|
| 113 |
+ } |
|
| 114 |
+ |
|
| 115 |
+ j.Subjects[i].UID = types.UID("")
|
|
| 116 |
+ j.Subjects[i].APIVersion = "" |
|
| 117 |
+ j.Subjects[i].ResourceVersion = "" |
|
| 118 |
+ j.Subjects[i].FieldPath = "" |
|
| 119 |
+ } |
|
| 120 |
+ }, |
|
| 45 | 121 |
func(j *template.Template, c fuzz.Continue) {
|
| 46 | 122 |
c.Fuzz(&j.ObjectMeta) |
| 47 | 123 |
c.Fuzz(&j.Parameters) |
| ... | ... |
@@ -194,6 +194,18 @@ func deepCopy_v1_ClusterRoleBinding(in v1.ClusterRoleBinding, out *v1.ClusterRol |
| 194 | 194 |
} else {
|
| 195 | 195 |
out.GroupNames = nil |
| 196 | 196 |
} |
| 197 |
+ if in.Subjects != nil {
|
|
| 198 |
+ out.Subjects = make([]pkgapiv1.ObjectReference, len(in.Subjects)) |
|
| 199 |
+ for i := range in.Subjects {
|
|
| 200 |
+ if newVal, err := c.DeepCopy(in.Subjects[i]); err != nil {
|
|
| 201 |
+ return err |
|
| 202 |
+ } else {
|
|
| 203 |
+ out.Subjects[i] = newVal.(pkgapiv1.ObjectReference) |
|
| 204 |
+ } |
|
| 205 |
+ } |
|
| 206 |
+ } else {
|
|
| 207 |
+ out.Subjects = nil |
|
| 208 |
+ } |
|
| 197 | 209 |
if newVal, err := c.DeepCopy(in.RoleRef); err != nil {
|
| 198 | 210 |
return err |
| 199 | 211 |
} else {
|
| ... | ... |
@@ -565,6 +577,18 @@ func deepCopy_v1_RoleBinding(in v1.RoleBinding, out *v1.RoleBinding, c *conversi |
| 565 | 565 |
} else {
|
| 566 | 566 |
out.GroupNames = nil |
| 567 | 567 |
} |
| 568 |
+ if in.Subjects != nil {
|
|
| 569 |
+ out.Subjects = make([]pkgapiv1.ObjectReference, len(in.Subjects)) |
|
| 570 |
+ for i := range in.Subjects {
|
|
| 571 |
+ if newVal, err := c.DeepCopy(in.Subjects[i]); err != nil {
|
|
| 572 |
+ return err |
|
| 573 |
+ } else {
|
|
| 574 |
+ out.Subjects[i] = newVal.(pkgapiv1.ObjectReference) |
|
| 575 |
+ } |
|
| 576 |
+ } |
|
| 577 |
+ } else {
|
|
| 578 |
+ out.Subjects = nil |
|
| 579 |
+ } |
|
| 568 | 580 |
if newVal, err := c.DeepCopy(in.RoleRef); err != nil {
|
| 569 | 581 |
return err |
| 570 | 582 |
} else {
|
| ... | ... |
@@ -194,6 +194,18 @@ func deepCopy_v1beta3_ClusterRoleBinding(in v1beta3.ClusterRoleBinding, out *v1b |
| 194 | 194 |
} else {
|
| 195 | 195 |
out.GroupNames = nil |
| 196 | 196 |
} |
| 197 |
+ if in.Subjects != nil {
|
|
| 198 |
+ out.Subjects = make([]pkgapiv1beta3.ObjectReference, len(in.Subjects)) |
|
| 199 |
+ for i := range in.Subjects {
|
|
| 200 |
+ if newVal, err := c.DeepCopy(in.Subjects[i]); err != nil {
|
|
| 201 |
+ return err |
|
| 202 |
+ } else {
|
|
| 203 |
+ out.Subjects[i] = newVal.(pkgapiv1beta3.ObjectReference) |
|
| 204 |
+ } |
|
| 205 |
+ } |
|
| 206 |
+ } else {
|
|
| 207 |
+ out.Subjects = nil |
|
| 208 |
+ } |
|
| 197 | 209 |
if newVal, err := c.DeepCopy(in.RoleRef); err != nil {
|
| 198 | 210 |
return err |
| 199 | 211 |
} else {
|
| ... | ... |
@@ -573,6 +585,18 @@ func deepCopy_v1beta3_RoleBinding(in v1beta3.RoleBinding, out *v1beta3.RoleBindi |
| 573 | 573 |
} else {
|
| 574 | 574 |
out.GroupNames = nil |
| 575 | 575 |
} |
| 576 |
+ if in.Subjects != nil {
|
|
| 577 |
+ out.Subjects = make([]pkgapiv1beta3.ObjectReference, len(in.Subjects)) |
|
| 578 |
+ for i := range in.Subjects {
|
|
| 579 |
+ if newVal, err := c.DeepCopy(in.Subjects[i]); err != nil {
|
|
| 580 |
+ return err |
|
| 581 |
+ } else {
|
|
| 582 |
+ out.Subjects[i] = newVal.(pkgapiv1beta3.ObjectReference) |
|
| 583 |
+ } |
|
| 584 |
+ } |
|
| 585 |
+ } else {
|
|
| 586 |
+ out.Subjects = nil |
|
| 587 |
+ } |
|
| 576 | 588 |
if newVal, err := c.DeepCopy(in.RoleRef); err != nil {
|
| 577 | 589 |
return err |
| 578 | 590 |
} else {
|
| ... | ... |
@@ -167,8 +167,7 @@ func ToRoleBinding(in *ClusterRoleBinding) *RoleBinding {
|
| 167 | 167 |
|
| 168 | 168 |
ret := &RoleBinding{}
|
| 169 | 169 |
ret.ObjectMeta = in.ObjectMeta |
| 170 |
- ret.Users = in.Users |
|
| 171 |
- ret.Groups = in.Groups |
|
| 170 |
+ ret.Subjects = in.Subjects |
|
| 172 | 171 |
ret.RoleRef = ToRoleRef(in.RoleRef) |
| 173 | 172 |
return ret |
| 174 | 173 |
} |
| ... | ... |
@@ -235,8 +234,7 @@ func ToClusterRoleBinding(in *RoleBinding) *ClusterRoleBinding {
|
| 235 | 235 |
|
| 236 | 236 |
ret := &ClusterRoleBinding{}
|
| 237 | 237 |
ret.ObjectMeta = in.ObjectMeta |
| 238 |
- ret.Users = in.Users |
|
| 239 |
- ret.Groups = in.Groups |
|
| 238 |
+ ret.Subjects = in.Subjects |
|
| 240 | 239 |
ret.RoleRef = ToClusterRoleRef(in.RoleRef) |
| 241 | 240 |
|
| 242 | 241 |
return ret |
| ... | ... |
@@ -5,7 +5,12 @@ import ( |
| 5 | 5 |
"sort" |
| 6 | 6 |
"strings" |
| 7 | 7 |
|
| 8 |
+ kapi "k8s.io/kubernetes/pkg/api" |
|
| 9 |
+ "k8s.io/kubernetes/pkg/api/validation" |
|
| 10 |
+ "k8s.io/kubernetes/pkg/controller/serviceaccount" |
|
| 8 | 11 |
kutil "k8s.io/kubernetes/pkg/util" |
| 12 |
+ |
|
| 13 |
+ // uservalidation "github.com/openshift/origin/pkg/user/api/validation" |
|
| 9 | 14 |
) |
| 10 | 15 |
|
| 11 | 16 |
func ExpandResources(rawResources kutil.StringSet) kutil.StringSet {
|
| ... | ... |
@@ -85,3 +90,91 @@ func GetPolicyBindingName(policyRefNamespace string) string {
|
| 85 | 85 |
} |
| 86 | 86 |
|
| 87 | 87 |
var ClusterPolicyBindingName = GetPolicyBindingName("")
|
| 88 |
+ |
|
| 89 |
+func BuildSubjects(users, groups []string, userNameValidator, groupNameValidator validation.ValidateNameFunc) []kapi.ObjectReference {
|
|
| 90 |
+ subjects := []kapi.ObjectReference{}
|
|
| 91 |
+ |
|
| 92 |
+ for _, user := range users {
|
|
| 93 |
+ saNamespace, saName, err := serviceaccount.SplitUsername(user) |
|
| 94 |
+ if err == nil {
|
|
| 95 |
+ subjects = append(subjects, kapi.ObjectReference{Kind: ServiceAccountKind, Namespace: saNamespace, Name: saName})
|
|
| 96 |
+ continue |
|
| 97 |
+ } |
|
| 98 |
+ |
|
| 99 |
+ kind := UserKind |
|
| 100 |
+ if valid, _ := userNameValidator(user, false); !valid {
|
|
| 101 |
+ kind = SystemUserKind |
|
| 102 |
+ } |
|
| 103 |
+ |
|
| 104 |
+ subjects = append(subjects, kapi.ObjectReference{Kind: kind, Name: user})
|
|
| 105 |
+ } |
|
| 106 |
+ |
|
| 107 |
+ for _, group := range groups {
|
|
| 108 |
+ kind := GroupKind |
|
| 109 |
+ if valid, _ := groupNameValidator(group, false); !valid {
|
|
| 110 |
+ kind = SystemGroupKind |
|
| 111 |
+ } |
|
| 112 |
+ |
|
| 113 |
+ subjects = append(subjects, kapi.ObjectReference{Kind: kind, Name: group})
|
|
| 114 |
+ } |
|
| 115 |
+ |
|
| 116 |
+ return subjects |
|
| 117 |
+} |
|
| 118 |
+ |
|
| 119 |
+// StringSubjectsFor returns users and groups for comparison against user.Info. currentNamespace is used to |
|
| 120 |
+// to create usernames for service accounts where namespace=="". |
|
| 121 |
+func StringSubjectsFor(currentNamespace string, subjects []kapi.ObjectReference) ([]string, []string) {
|
|
| 122 |
+ users := []string{}
|
|
| 123 |
+ groups := []string{}
|
|
| 124 |
+ |
|
| 125 |
+ for _, subject := range subjects {
|
|
| 126 |
+ switch subject.Kind {
|
|
| 127 |
+ case ServiceAccountKind: |
|
| 128 |
+ namespace := currentNamespace |
|
| 129 |
+ if len(subject.Namespace) > 0 {
|
|
| 130 |
+ namespace = subject.Namespace |
|
| 131 |
+ } |
|
| 132 |
+ users = append(users, serviceaccount.MakeUsername(namespace, subject.Name)) |
|
| 133 |
+ |
|
| 134 |
+ case UserKind, SystemUserKind: |
|
| 135 |
+ users = append(users, subject.Name) |
|
| 136 |
+ |
|
| 137 |
+ case GroupKind, SystemGroupKind: |
|
| 138 |
+ groups = append(groups, subject.Name) |
|
| 139 |
+ } |
|
| 140 |
+ } |
|
| 141 |
+ |
|
| 142 |
+ return users, groups |
|
| 143 |
+} |
|
| 144 |
+ |
|
| 145 |
+// SubjectsStrings returns users, groups, serviceaccounts, unknown for display purposes. currentNamespace is used to |
|
| 146 |
+// hide the subject.Namespace for ServiceAccounts in the currentNamespace |
|
| 147 |
+func SubjectsStrings(currentNamespace string, subjects []kapi.ObjectReference) ([]string, []string, []string, []string) {
|
|
| 148 |
+ users := []string{}
|
|
| 149 |
+ groups := []string{}
|
|
| 150 |
+ sas := []string{}
|
|
| 151 |
+ others := []string{}
|
|
| 152 |
+ |
|
| 153 |
+ for _, subject := range subjects {
|
|
| 154 |
+ switch subject.Kind {
|
|
| 155 |
+ case ServiceAccountKind: |
|
| 156 |
+ if len(subject.Namespace) > 0 && currentNamespace != subject.Namespace {
|
|
| 157 |
+ sas = append(sas, subject.Namespace+"/"+subject.Name) |
|
| 158 |
+ } else {
|
|
| 159 |
+ sas = append(sas, subject.Name) |
|
| 160 |
+ } |
|
| 161 |
+ |
|
| 162 |
+ case UserKind, SystemUserKind: |
|
| 163 |
+ users = append(users, subject.Name) |
|
| 164 |
+ |
|
| 165 |
+ case GroupKind, SystemGroupKind: |
|
| 166 |
+ groups = append(groups, subject.Name) |
|
| 167 |
+ |
|
| 168 |
+ default: |
|
| 169 |
+ others = append(others, fmt.Sprintf("%s/%s/%s", subject.Kind, subject.Namespace, subject.Name))
|
|
| 170 |
+ |
|
| 171 |
+ } |
|
| 172 |
+ } |
|
| 173 |
+ |
|
| 174 |
+ return users, groups, sas, others |
|
| 175 |
+} |
| ... | ... |
@@ -19,6 +19,12 @@ const ( |
| 19 | 19 |
ResourceAll = "*" |
| 20 | 20 |
VerbAll = "*" |
| 21 | 21 |
NonResourceAll = "*" |
| 22 |
+ |
|
| 23 |
+ UserKind = "User" |
|
| 24 |
+ GroupKind = "Group" |
|
| 25 |
+ ServiceAccountKind = "ServiceAccount" |
|
| 26 |
+ SystemUserKind = "SystemUser" |
|
| 27 |
+ SystemGroupKind = "SystemGroup" |
|
| 22 | 28 |
) |
| 23 | 29 |
|
| 24 | 30 |
const ( |
| ... | ... |
@@ -142,10 +148,8 @@ type RoleBinding struct {
|
| 142 | 142 |
kapi.TypeMeta |
| 143 | 143 |
kapi.ObjectMeta |
| 144 | 144 |
|
| 145 |
- // Users holds all the usernames directly bound to the role |
|
| 146 |
- Users util.StringSet |
|
| 147 |
- // Groups holds all the groups directly bound to the role |
|
| 148 |
- Groups util.StringSet |
|
| 145 |
+ // Subjects hold object references of to authorize with this rule |
|
| 146 |
+ Subjects []kapi.ObjectReference |
|
| 149 | 147 |
|
| 150 | 148 |
// RoleRef can only reference the current namespace and the global namespace |
| 151 | 149 |
// If the RoleRef cannot be resolved, the Authorizer must return an error. |
| ... | ... |
@@ -311,10 +315,8 @@ type ClusterRoleBinding struct {
|
| 311 | 311 |
kapi.TypeMeta |
| 312 | 312 |
kapi.ObjectMeta |
| 313 | 313 |
|
| 314 |
- // Users holds all the usernames directly bound to the role |
|
| 315 |
- Users util.StringSet |
|
| 316 |
- // GroupNames holds all the groups directly bound to the role |
|
| 317 |
- Groups util.StringSet |
|
| 314 |
+ // Subjects hold object references of to authorize with this rule |
|
| 315 |
+ Subjects []kapi.ObjectReference |
|
| 318 | 316 |
|
| 319 | 317 |
// RoleRef can only reference the current namespace and the global namespace |
| 320 | 318 |
// If the ClusterRoleRef cannot be resolved, the Authorizer must return an error. |
| ... | ... |
@@ -8,6 +8,7 @@ import ( |
| 8 | 8 |
"k8s.io/kubernetes/pkg/util" |
| 9 | 9 |
|
| 10 | 10 |
newer "github.com/openshift/origin/pkg/authorization/api" |
| 11 |
+ uservalidation "github.com/openshift/origin/pkg/user/api/validation" |
|
| 11 | 12 |
) |
| 12 | 13 |
|
| 13 | 14 |
func convert_v1_ResourceAccessReview_To_api_ResourceAccessReview(in *ResourceAccessReview, out *newer.ResourceAccessReview, s conversion.Scope) error {
|
| ... | ... |
@@ -181,8 +182,12 @@ func convert_v1_RoleBinding_To_api_RoleBinding(in *RoleBinding, out *newer.RoleB |
| 181 | 181 |
return err |
| 182 | 182 |
} |
| 183 | 183 |
|
| 184 |
- out.Users = util.NewStringSet(in.UserNames...) |
|
| 185 |
- out.Groups = util.NewStringSet(in.GroupNames...) |
|
| 184 |
+ // if the users and groups fields are cleared, then respect only subjects. The field was set in the DefaultConvert above |
|
| 185 |
+ if in.UserNames == nil && in.GroupNames == nil {
|
|
| 186 |
+ return nil |
|
| 187 |
+ } |
|
| 188 |
+ |
|
| 189 |
+ out.Subjects = newer.BuildSubjects(in.UserNames, in.GroupNames, uservalidation.ValidateUserName, uservalidation.ValidateGroupName) |
|
| 186 | 190 |
|
| 187 | 191 |
return nil |
| 188 | 192 |
} |
| ... | ... |
@@ -192,8 +197,7 @@ func convert_api_RoleBinding_To_v1_RoleBinding(in *newer.RoleBinding, out *RoleB |
| 192 | 192 |
return err |
| 193 | 193 |
} |
| 194 | 194 |
|
| 195 |
- out.UserNames = in.Users.List() |
|
| 196 |
- out.GroupNames = in.Groups.List() |
|
| 195 |
+ out.UserNames, out.GroupNames = newer.StringSubjectsFor(in.Namespace, in.Subjects) |
|
| 197 | 196 |
|
| 198 | 197 |
return nil |
| 199 | 198 |
} |
| ... | ... |
@@ -228,8 +232,12 @@ func convert_v1_ClusterRoleBinding_To_api_ClusterRoleBinding(in *ClusterRoleBind |
| 228 | 228 |
return err |
| 229 | 229 |
} |
| 230 | 230 |
|
| 231 |
- out.Users = util.NewStringSet(in.UserNames...) |
|
| 232 |
- out.Groups = util.NewStringSet(in.GroupNames...) |
|
| 231 |
+ // if the users and groups fields are cleared, then respect only subjects. The field was set in the DefaultConvert above |
|
| 232 |
+ if in.UserNames == nil && in.GroupNames == nil {
|
|
| 233 |
+ return nil |
|
| 234 |
+ } |
|
| 235 |
+ |
|
| 236 |
+ out.Subjects = newer.BuildSubjects(in.UserNames, in.GroupNames, uservalidation.ValidateUserName, uservalidation.ValidateGroupName) |
|
| 233 | 237 |
|
| 234 | 238 |
return nil |
| 235 | 239 |
} |
| ... | ... |
@@ -239,8 +247,7 @@ func convert_api_ClusterRoleBinding_To_v1_ClusterRoleBinding(in *newer.ClusterRo |
| 239 | 239 |
return err |
| 240 | 240 |
} |
| 241 | 241 |
|
| 242 |
- out.UserNames = in.Users.List() |
|
| 243 |
- out.GroupNames = in.Groups.List() |
|
| 242 |
+ out.UserNames, out.GroupNames = newer.StringSubjectsFor(in.Namespace, in.Subjects) |
|
| 244 | 243 |
|
| 245 | 244 |
return nil |
| 246 | 245 |
} |
| ... | ... |
@@ -55,6 +55,8 @@ type RoleBinding struct {
|
| 55 | 55 |
UserNames []string `json:"userNames" description:"all the usernames directly bound to the role"` |
| 56 | 56 |
// GroupNames holds all the groups directly bound to the role |
| 57 | 57 |
GroupNames []string `json:"groupNames" description:"all the groups directly bound to the role"` |
| 58 |
+ // Subjects hold object references to authorize with this rule |
|
| 59 |
+ Subjects []kapi.ObjectReference `json:"subjects" description:"references to subjects bound to the role. Only User, Group, SystemUser, SystemGroup, and ServiceAccount are allowed."` |
|
| 58 | 60 |
|
| 59 | 61 |
// RoleRef can only reference the current namespace and the global namespace |
| 60 | 62 |
// If the RoleRef cannot be resolved, the Authorizer must return an error. |
| ... | ... |
@@ -234,6 +236,8 @@ type ClusterRoleBinding struct {
|
| 234 | 234 |
UserNames []string `json:"userNames" description:"all user names directly bound to the role"` |
| 235 | 235 |
// GroupNames holds all the groups directly bound to the role |
| 236 | 236 |
GroupNames []string `json:"groupNames" description:"all the groups directly bound to the role"` |
| 237 |
+ // Subjects hold object references to authorize with this rule |
|
| 238 |
+ Subjects []kapi.ObjectReference `json:"subjects" description:"references to subjects bound to the role. Only User, Group, SystemUser, SystemGroup, and ServiceAccount are allowed."` |
|
| 237 | 239 |
|
| 238 | 240 |
// RoleRef can only reference the current namespace and the global namespace |
| 239 | 241 |
// If the ClusterRoleRef cannot be resolved, the Authorizer must return an error. |
| ... | ... |
@@ -8,6 +8,7 @@ import ( |
| 8 | 8 |
"k8s.io/kubernetes/pkg/util" |
| 9 | 9 |
|
| 10 | 10 |
newer "github.com/openshift/origin/pkg/authorization/api" |
| 11 |
+ uservalidation "github.com/openshift/origin/pkg/user/api/validation" |
|
| 11 | 12 |
) |
| 12 | 13 |
|
| 13 | 14 |
func convert_v1beta3_ResourceAccessReview_To_api_ResourceAccessReview(in *ResourceAccessReview, out *newer.ResourceAccessReview, s conversion.Scope) error {
|
| ... | ... |
@@ -182,8 +183,12 @@ func convert_v1beta3_RoleBinding_To_api_RoleBinding(in *RoleBinding, out *newer. |
| 182 | 182 |
return err |
| 183 | 183 |
} |
| 184 | 184 |
|
| 185 |
- out.Users = util.NewStringSet(in.UserNames...) |
|
| 186 |
- out.Groups = util.NewStringSet(in.GroupNames...) |
|
| 185 |
+ // if the users and groups fields are cleared, then respect only subjects. The field was set in the DefaultConvert above |
|
| 186 |
+ if in.UserNames == nil && in.GroupNames == nil {
|
|
| 187 |
+ return nil |
|
| 188 |
+ } |
|
| 189 |
+ |
|
| 190 |
+ out.Subjects = newer.BuildSubjects(in.UserNames, in.GroupNames, uservalidation.ValidateUserName, uservalidation.ValidateGroupName) |
|
| 187 | 191 |
|
| 188 | 192 |
return nil |
| 189 | 193 |
} |
| ... | ... |
@@ -193,8 +198,7 @@ func convert_api_RoleBinding_To_v1beta3_RoleBinding(in *newer.RoleBinding, out * |
| 193 | 193 |
return err |
| 194 | 194 |
} |
| 195 | 195 |
|
| 196 |
- out.UserNames = in.Users.List() |
|
| 197 |
- out.GroupNames = in.Groups.List() |
|
| 196 |
+ out.UserNames, out.GroupNames = newer.StringSubjectsFor(in.Namespace, in.Subjects) |
|
| 198 | 197 |
|
| 199 | 198 |
return nil |
| 200 | 199 |
} |
| ... | ... |
@@ -229,8 +233,12 @@ func convert_v1beta3_ClusterRoleBinding_To_api_ClusterRoleBinding(in *ClusterRol |
| 229 | 229 |
return err |
| 230 | 230 |
} |
| 231 | 231 |
|
| 232 |
- out.Users = util.NewStringSet(in.UserNames...) |
|
| 233 |
- out.Groups = util.NewStringSet(in.GroupNames...) |
|
| 232 |
+ // if the users and groups fields are cleared, then respect only subjects. The field was set in the DefaultConvert above |
|
| 233 |
+ if in.UserNames == nil && in.GroupNames == nil {
|
|
| 234 |
+ return nil |
|
| 235 |
+ } |
|
| 236 |
+ |
|
| 237 |
+ out.Subjects = newer.BuildSubjects(in.UserNames, in.GroupNames, uservalidation.ValidateUserName, uservalidation.ValidateGroupName) |
|
| 234 | 238 |
|
| 235 | 239 |
return nil |
| 236 | 240 |
} |
| ... | ... |
@@ -240,8 +248,7 @@ func convert_api_ClusterRoleBinding_To_v1beta3_ClusterRoleBinding(in *newer.Clus |
| 240 | 240 |
return err |
| 241 | 241 |
} |
| 242 | 242 |
|
| 243 |
- out.UserNames = in.Users.List() |
|
| 244 |
- out.GroupNames = in.Groups.List() |
|
| 243 |
+ out.UserNames, out.GroupNames = newer.StringSubjectsFor(in.Namespace, in.Subjects) |
|
| 245 | 244 |
|
| 246 | 245 |
return nil |
| 247 | 246 |
} |
| ... | ... |
@@ -58,6 +58,8 @@ type RoleBinding struct {
|
| 58 | 58 |
UserNames []string `json:"userNames"` |
| 59 | 59 |
// GroupNames holds all the groups directly bound to the role |
| 60 | 60 |
GroupNames []string `json:"groupNames"` |
| 61 |
+ // Subjects hold object references to authorize with this rule |
|
| 62 |
+ Subjects []kapi.ObjectReference `json:"subjects"` |
|
| 61 | 63 |
|
| 62 | 64 |
// Since Policy is a singleton, this is sufficient knowledge to locate a role |
| 63 | 65 |
// RoleRefs can only reference the current namespace and the global namespace |
| ... | ... |
@@ -229,6 +231,8 @@ type ClusterRoleBinding struct {
|
| 229 | 229 |
UserNames []string `json:"userNames"` |
| 230 | 230 |
// GroupNames holds all the groups directly bound to the role |
| 231 | 231 |
GroupNames []string `json:"groupNames"` |
| 232 |
+ // Subjects hold object references to authorize with this rule |
|
| 233 |
+ Subjects []kapi.ObjectReference `json:"subjects"` |
|
| 232 | 234 |
|
| 233 | 235 |
// Since Policy is a singleton, this is sufficient knowledge to locate a role |
| 234 | 236 |
// ClusterRoleRefs can only reference the current namespace and the global namespace |
| ... | ... |
@@ -1,12 +1,16 @@ |
| 1 | 1 |
package validation |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 |
+ "fmt" |
|
| 5 |
+ |
|
| 6 |
+ kapi "k8s.io/kubernetes/pkg/api" |
|
| 4 | 7 |
"k8s.io/kubernetes/pkg/api/validation" |
| 5 | 8 |
"k8s.io/kubernetes/pkg/util" |
| 6 | 9 |
"k8s.io/kubernetes/pkg/util/fielderrors" |
| 7 | 10 |
|
| 8 | 11 |
oapi "github.com/openshift/origin/pkg/api" |
| 9 | 12 |
authorizationapi "github.com/openshift/origin/pkg/authorization/api" |
| 13 |
+ uservalidation "github.com/openshift/origin/pkg/user/api/validation" |
|
| 10 | 14 |
) |
| 11 | 15 |
|
| 12 | 16 |
func ValidateSubjectAccessReview(review *authorizationapi.SubjectAccessReview) fielderrors.ValidationErrorList {
|
| ... | ... |
@@ -248,6 +252,67 @@ func ValidateRoleBinding(roleBinding *authorizationapi.RoleBinding, isNamespaced |
| 248 | 248 |
} |
| 249 | 249 |
} |
| 250 | 250 |
|
| 251 |
+ for i, subject := range roleBinding.Subjects {
|
|
| 252 |
+ allErrs = append(allErrs, ValidateRoleBindingSubject(subject, isNamespaced).Prefix(fmt.Sprintf("subjects[%d]", i))...)
|
|
| 253 |
+ } |
|
| 254 |
+ |
|
| 255 |
+ return allErrs |
|
| 256 |
+} |
|
| 257 |
+ |
|
| 258 |
+func ValidateRoleBindingSubject(subject kapi.ObjectReference, isNamespaced bool) fielderrors.ValidationErrorList {
|
|
| 259 |
+ allErrs := fielderrors.ValidationErrorList{}
|
|
| 260 |
+ |
|
| 261 |
+ if len(subject.Name) == 0 {
|
|
| 262 |
+ allErrs = append(allErrs, fielderrors.NewFieldRequired("name"))
|
|
| 263 |
+ } |
|
| 264 |
+ if len(subject.UID) != 0 {
|
|
| 265 |
+ allErrs = append(allErrs, fielderrors.NewFieldForbidden("uid", subject.UID))
|
|
| 266 |
+ } |
|
| 267 |
+ if len(subject.APIVersion) != 0 {
|
|
| 268 |
+ allErrs = append(allErrs, fielderrors.NewFieldForbidden("apiVersion", subject.APIVersion))
|
|
| 269 |
+ } |
|
| 270 |
+ if len(subject.ResourceVersion) != 0 {
|
|
| 271 |
+ allErrs = append(allErrs, fielderrors.NewFieldForbidden("resourceVersion", subject.ResourceVersion))
|
|
| 272 |
+ } |
|
| 273 |
+ if len(subject.FieldPath) != 0 {
|
|
| 274 |
+ allErrs = append(allErrs, fielderrors.NewFieldForbidden("fieldPath", subject.FieldPath))
|
|
| 275 |
+ } |
|
| 276 |
+ |
|
| 277 |
+ switch subject.Kind {
|
|
| 278 |
+ case authorizationapi.ServiceAccountKind: |
|
| 279 |
+ if valid, reason := validation.ValidateServiceAccountName(subject.Name, false); len(subject.Name) > 0 && !valid {
|
|
| 280 |
+ allErrs = append(allErrs, fielderrors.NewFieldInvalid("name", subject.Name, reason))
|
|
| 281 |
+ } |
|
| 282 |
+ if !isNamespaced && len(subject.Namespace) == 0 {
|
|
| 283 |
+ allErrs = append(allErrs, fielderrors.NewFieldRequired("namespace"))
|
|
| 284 |
+ } |
|
| 285 |
+ |
|
| 286 |
+ case authorizationapi.UserKind: |
|
| 287 |
+ if valid, reason := uservalidation.ValidateUserName(subject.Name, false); len(subject.Name) > 0 && !valid {
|
|
| 288 |
+ allErrs = append(allErrs, fielderrors.NewFieldInvalid("name", subject.Name, reason))
|
|
| 289 |
+ } |
|
| 290 |
+ |
|
| 291 |
+ case authorizationapi.GroupKind: |
|
| 292 |
+ if valid, reason := uservalidation.ValidateGroupName(subject.Name, false); len(subject.Name) > 0 && !valid {
|
|
| 293 |
+ allErrs = append(allErrs, fielderrors.NewFieldInvalid("name", subject.Name, reason))
|
|
| 294 |
+ } |
|
| 295 |
+ |
|
| 296 |
+ case authorizationapi.SystemUserKind: |
|
| 297 |
+ isValidSAName, _ := validation.ValidateServiceAccountName(subject.Name, false) |
|
| 298 |
+ isValidUserName, _ := uservalidation.ValidateUserName(subject.Name, false) |
|
| 299 |
+ if isValidSAName || isValidUserName {
|
|
| 300 |
+ allErrs = append(allErrs, fielderrors.NewFieldInvalid("name", subject.Name, "conforms to User.name or ServiceAccount.name restrictions"))
|
|
| 301 |
+ } |
|
| 302 |
+ |
|
| 303 |
+ case authorizationapi.SystemGroupKind: |
|
| 304 |
+ if valid, _ := uservalidation.ValidateGroupName(subject.Name, false); len(subject.Name) > 0 && valid {
|
|
| 305 |
+ allErrs = append(allErrs, fielderrors.NewFieldInvalid("name", subject.Name, "conforms to Group.name restrictions"))
|
|
| 306 |
+ } |
|
| 307 |
+ |
|
| 308 |
+ default: |
|
| 309 |
+ allErrs = append(allErrs, fielderrors.NewFieldValueNotSupported("kind", subject.Kind, []string{authorizationapi.ServiceAccountKind, authorizationapi.UserKind, authorizationapi.GroupKind, authorizationapi.SystemGroupKind, authorizationapi.SystemUserKind}))
|
|
| 310 |
+ } |
|
| 311 |
+ |
|
| 251 | 312 |
return allErrs |
| 252 | 313 |
} |
| 253 | 314 |
|
| ... | ... |
@@ -168,6 +168,13 @@ func TestValidateRoleBinding(t *testing.T) {
|
| 168 | 168 |
&authorizationapi.RoleBinding{
|
| 169 | 169 |
ObjectMeta: kapi.ObjectMeta{Namespace: kapi.NamespaceDefault, Name: "master"},
|
| 170 | 170 |
RoleRef: kapi.ObjectReference{Namespace: "master", Name: "valid"},
|
| 171 |
+ Subjects: []kapi.ObjectReference{
|
|
| 172 |
+ {Name: "validsaname", Kind: authorizationapi.ServiceAccountKind},
|
|
| 173 |
+ {Name: "valid@username", Kind: authorizationapi.UserKind},
|
|
| 174 |
+ {Name: "system:admin", Kind: authorizationapi.SystemUserKind},
|
|
| 175 |
+ {Name: "valid@groupname", Kind: authorizationapi.GroupKind},
|
|
| 176 |
+ {Name: "system:authenticated", Kind: authorizationapi.SystemGroupKind},
|
|
| 177 |
+ }, |
|
| 171 | 178 |
}, |
| 172 | 179 |
true, |
| 173 | 180 |
) |
| ... | ... |
@@ -212,6 +219,60 @@ func TestValidateRoleBinding(t *testing.T) {
|
| 212 | 212 |
T: fielderrors.ValidationErrorTypeRequired, |
| 213 | 213 |
F: "roleRef.name", |
| 214 | 214 |
}, |
| 215 |
+ "bad subject kind": {
|
|
| 216 |
+ A: authorizationapi.RoleBinding{
|
|
| 217 |
+ ObjectMeta: kapi.ObjectMeta{Namespace: kapi.NamespaceDefault, Name: "master"},
|
|
| 218 |
+ RoleRef: kapi.ObjectReference{Namespace: "master", Name: "valid"},
|
|
| 219 |
+ Subjects: []kapi.ObjectReference{{Name: "subject"}},
|
|
| 220 |
+ }, |
|
| 221 |
+ T: fielderrors.ValidationErrorTypeNotSupported, |
|
| 222 |
+ F: "subjects[0].kind", |
|
| 223 |
+ }, |
|
| 224 |
+ "bad subject name": {
|
|
| 225 |
+ A: authorizationapi.RoleBinding{
|
|
| 226 |
+ ObjectMeta: kapi.ObjectMeta{Namespace: kapi.NamespaceDefault, Name: "master"},
|
|
| 227 |
+ RoleRef: kapi.ObjectReference{Namespace: "master", Name: "valid"},
|
|
| 228 |
+ Subjects: []kapi.ObjectReference{{Name: "subject:bad", Kind: authorizationapi.ServiceAccountKind}},
|
|
| 229 |
+ }, |
|
| 230 |
+ T: fielderrors.ValidationErrorTypeInvalid, |
|
| 231 |
+ F: "subjects[0].name", |
|
| 232 |
+ }, |
|
| 233 |
+ "bad system user name": {
|
|
| 234 |
+ A: authorizationapi.RoleBinding{
|
|
| 235 |
+ ObjectMeta: kapi.ObjectMeta{Namespace: kapi.NamespaceDefault, Name: "master"},
|
|
| 236 |
+ RoleRef: kapi.ObjectReference{Namespace: "master", Name: "valid"},
|
|
| 237 |
+ Subjects: []kapi.ObjectReference{{Name: "user", Kind: authorizationapi.SystemUserKind}},
|
|
| 238 |
+ }, |
|
| 239 |
+ T: fielderrors.ValidationErrorTypeInvalid, |
|
| 240 |
+ F: "subjects[0].name", |
|
| 241 |
+ }, |
|
| 242 |
+ "bad system group name": {
|
|
| 243 |
+ A: authorizationapi.RoleBinding{
|
|
| 244 |
+ ObjectMeta: kapi.ObjectMeta{Namespace: kapi.NamespaceDefault, Name: "master"},
|
|
| 245 |
+ RoleRef: kapi.ObjectReference{Namespace: "master", Name: "valid"},
|
|
| 246 |
+ Subjects: []kapi.ObjectReference{{Name: "valid", Kind: authorizationapi.SystemGroupKind}},
|
|
| 247 |
+ }, |
|
| 248 |
+ T: fielderrors.ValidationErrorTypeInvalid, |
|
| 249 |
+ F: "subjects[0].name", |
|
| 250 |
+ }, |
|
| 251 |
+ "forbidden fields": {
|
|
| 252 |
+ A: authorizationapi.RoleBinding{
|
|
| 253 |
+ ObjectMeta: kapi.ObjectMeta{Namespace: kapi.NamespaceDefault, Name: "master"},
|
|
| 254 |
+ RoleRef: kapi.ObjectReference{Namespace: "master", Name: "valid"},
|
|
| 255 |
+ Subjects: []kapi.ObjectReference{{Name: "subject", Kind: authorizationapi.ServiceAccountKind, APIVersion: "foo"}},
|
|
| 256 |
+ }, |
|
| 257 |
+ T: fielderrors.ValidationErrorTypeForbidden, |
|
| 258 |
+ F: "subjects[0].apiVersion", |
|
| 259 |
+ }, |
|
| 260 |
+ "missing subject name": {
|
|
| 261 |
+ A: authorizationapi.RoleBinding{
|
|
| 262 |
+ ObjectMeta: kapi.ObjectMeta{Namespace: kapi.NamespaceDefault, Name: "master"},
|
|
| 263 |
+ RoleRef: kapi.ObjectReference{Namespace: "master", Name: "valid"},
|
|
| 264 |
+ Subjects: []kapi.ObjectReference{{Kind: authorizationapi.ServiceAccountKind}},
|
|
| 265 |
+ }, |
|
| 266 |
+ T: fielderrors.ValidationErrorTypeRequired, |
|
| 267 |
+ F: "subjects[0].name", |
|
| 268 |
+ }, |
|
| 215 | 269 |
} |
| 216 | 270 |
for k, v := range errorCases {
|
| 217 | 271 |
errs := ValidateRoleBinding(&v.A, true) |
| ... | ... |
@@ -8,6 +8,7 @@ import ( |
| 8 | 8 |
|
| 9 | 9 |
kapi "k8s.io/kubernetes/pkg/api" |
| 10 | 10 |
"k8s.io/kubernetes/pkg/auth/user" |
| 11 |
+ "k8s.io/kubernetes/pkg/controller/serviceaccount" |
|
| 11 | 12 |
"k8s.io/kubernetes/pkg/util" |
| 12 | 13 |
|
| 13 | 14 |
authorizationapi "github.com/openshift/origin/pkg/authorization/api" |
| ... | ... |
@@ -65,6 +66,58 @@ func TestResourceNameAllow(t *testing.T) {
|
| 65 | 65 |
test.test(t) |
| 66 | 66 |
} |
| 67 | 67 |
|
| 68 |
+func TestClusterBindingServiceAccountSubject(t *testing.T) {
|
|
| 69 |
+ test := &authorizeTest{
|
|
| 70 |
+ context: kapi.WithUser(kapi.WithNamespace(kapi.NewContext(), kapi.NamespaceNone), &user.DefaultInfo{Name: serviceaccount.MakeUsername("foo", "default")}),
|
|
| 71 |
+ attributes: &DefaultAuthorizationAttributes{
|
|
| 72 |
+ Verb: "get", |
|
| 73 |
+ Resource: "users", |
|
| 74 |
+ ResourceName: "any", |
|
| 75 |
+ }, |
|
| 76 |
+ expectedAllowed: true, |
|
| 77 |
+ expectedReason: "allowed by cluster rule", |
|
| 78 |
+ } |
|
| 79 |
+ test.clusterPolicies = newDefaultClusterPolicies() |
|
| 80 |
+ test.clusterBindings = newDefaultClusterPolicyBindings() |
|
| 81 |
+ test.test(t) |
|
| 82 |
+} |
|
| 83 |
+ |
|
| 84 |
+func TestLocalBindingServiceAccountSubject(t *testing.T) {
|
|
| 85 |
+ test := &authorizeTest{
|
|
| 86 |
+ context: kapi.WithUser(kapi.WithNamespace(kapi.NewContext(), "adze"), &user.DefaultInfo{Name: serviceaccount.MakeUsername("adze", "second")}),
|
|
| 87 |
+ attributes: &DefaultAuthorizationAttributes{
|
|
| 88 |
+ Verb: "get", |
|
| 89 |
+ Resource: "pods", |
|
| 90 |
+ }, |
|
| 91 |
+ expectedAllowed: true, |
|
| 92 |
+ expectedReason: "allowed by rule in adze", |
|
| 93 |
+ } |
|
| 94 |
+ test.clusterPolicies = newDefaultClusterPolicies() |
|
| 95 |
+ test.policies = append(test.policies, newAdzePolicies()...) |
|
| 96 |
+ test.clusterBindings = newDefaultClusterPolicyBindings() |
|
| 97 |
+ test.bindings = append(test.bindings, newAdzeBindings()...) |
|
| 98 |
+ |
|
| 99 |
+ test.test(t) |
|
| 100 |
+} |
|
| 101 |
+ |
|
| 102 |
+func TestLocalBindingOtherServiceAccountSubject(t *testing.T) {
|
|
| 103 |
+ test := &authorizeTest{
|
|
| 104 |
+ context: kapi.WithUser(kapi.WithNamespace(kapi.NewContext(), "adze"), &user.DefaultInfo{Name: serviceaccount.MakeUsername("other", "first")}),
|
|
| 105 |
+ attributes: &DefaultAuthorizationAttributes{
|
|
| 106 |
+ Verb: "get", |
|
| 107 |
+ Resource: "pods", |
|
| 108 |
+ }, |
|
| 109 |
+ expectedAllowed: true, |
|
| 110 |
+ expectedReason: "allowed by rule in adze", |
|
| 111 |
+ } |
|
| 112 |
+ test.clusterPolicies = newDefaultClusterPolicies() |
|
| 113 |
+ test.policies = append(test.policies, newAdzePolicies()...) |
|
| 114 |
+ test.clusterBindings = newDefaultClusterPolicyBindings() |
|
| 115 |
+ test.bindings = append(test.bindings, newAdzeBindings()...) |
|
| 116 |
+ |
|
| 117 |
+ test.test(t) |
|
| 118 |
+} |
|
| 119 |
+ |
|
| 68 | 120 |
func TestDeniedWithError(t *testing.T) {
|
| 69 | 121 |
test := &authorizeTest{
|
| 70 | 122 |
context: kapi.WithUser(kapi.WithNamespace(kapi.NewContext(), "adze"), &user.DefaultInfo{Name: "Anna"}),
|
| ... | ... |
@@ -86,7 +139,7 @@ func TestDeniedWithError(t *testing.T) {
|
| 86 | 86 |
RoleRef: kapi.ObjectReference{
|
| 87 | 87 |
Name: "not-a-real-binding", |
| 88 | 88 |
}, |
| 89 |
- Users: util.NewStringSet("Anna"),
|
|
| 89 |
+ Subjects: []kapi.ObjectReference{{Kind: authorizationapi.UserKind, Name: "Anna"}},
|
|
| 90 | 90 |
} |
| 91 | 91 |
test.policyRetrievalError = errors.New("my special error")
|
| 92 | 92 |
|
| ... | ... |
@@ -114,7 +167,7 @@ func TestAllowedWithMissingBinding(t *testing.T) {
|
| 114 | 114 |
RoleRef: kapi.ObjectReference{
|
| 115 | 115 |
Name: "not-a-real-binding", |
| 116 | 116 |
}, |
| 117 |
- Users: util.NewStringSet("Anna"),
|
|
| 117 |
+ Subjects: []kapi.ObjectReference{{Kind: authorizationapi.UserKind, Name: "Anna"}},
|
|
| 118 | 118 |
} |
| 119 | 119 |
|
| 120 | 120 |
test.test(t) |
| ... | ... |
@@ -446,8 +499,7 @@ func newDefaultClusterPolicyBindings() []authorizationapi.ClusterPolicyBinding {
|
| 446 | 446 |
RoleRef: kapi.ObjectReference{
|
| 447 | 447 |
Name: "cluster-admin", |
| 448 | 448 |
}, |
| 449 |
- Users: util.NewStringSet("ClusterAdmin"),
|
|
| 450 |
- Groups: util.NewStringSet("RootUsers"),
|
|
| 449 |
+ Subjects: []kapi.ObjectReference{{Kind: authorizationapi.UserKind, Name: "ClusterAdmin"}, {Kind: authorizationapi.GroupKind, Name: "RootUsers"}, {Name: "default", Namespace: "foo", Kind: authorizationapi.ServiceAccountKind}},
|
|
| 451 | 450 |
}, |
| 452 | 451 |
"user-only": {
|
| 453 | 452 |
ObjectMeta: kapi.ObjectMeta{
|
| ... | ... |
@@ -456,7 +508,7 @@ func newDefaultClusterPolicyBindings() []authorizationapi.ClusterPolicyBinding {
|
| 456 | 456 |
RoleRef: kapi.ObjectReference{
|
| 457 | 457 |
Name: "basic-user", |
| 458 | 458 |
}, |
| 459 |
- Users: util.NewStringSet("just-a-user"),
|
|
| 459 |
+ Subjects: []kapi.ObjectReference{{Kind: authorizationapi.UserKind, Name: "just-a-user"}},
|
|
| 460 | 460 |
}, |
| 461 | 461 |
}, |
| 462 | 462 |
} |
| ... | ... |
@@ -504,7 +556,7 @@ func newAdzeBindings() []authorizationapi.PolicyBinding {
|
| 504 | 504 |
RoleRef: kapi.ObjectReference{
|
| 505 | 505 |
Name: bootstrappolicy.AdminRoleName, |
| 506 | 506 |
}, |
| 507 |
- Users: util.NewStringSet("Anna"),
|
|
| 507 |
+ Subjects: []kapi.ObjectReference{{Kind: authorizationapi.UserKind, Name: "Anna"}},
|
|
| 508 | 508 |
}, |
| 509 | 509 |
"viewers": {
|
| 510 | 510 |
ObjectMeta: kapi.ObjectMeta{
|
| ... | ... |
@@ -514,7 +566,11 @@ func newAdzeBindings() []authorizationapi.PolicyBinding {
|
| 514 | 514 |
RoleRef: kapi.ObjectReference{
|
| 515 | 515 |
Name: bootstrappolicy.ViewRoleName, |
| 516 | 516 |
}, |
| 517 |
- Users: util.NewStringSet("Valerie"),
|
|
| 517 |
+ Subjects: []kapi.ObjectReference{
|
|
| 518 |
+ {Kind: authorizationapi.UserKind, Name: "Valerie"},
|
|
| 519 |
+ {Name: "first", Namespace: "other", Kind: authorizationapi.ServiceAccountKind},
|
|
| 520 |
+ {Name: "second", Kind: authorizationapi.ServiceAccountKind},
|
|
| 521 |
+ }, |
|
| 518 | 522 |
}, |
| 519 | 523 |
"editors": {
|
| 520 | 524 |
ObjectMeta: kapi.ObjectMeta{
|
| ... | ... |
@@ -524,7 +580,7 @@ func newAdzeBindings() []authorizationapi.PolicyBinding {
|
| 524 | 524 |
RoleRef: kapi.ObjectReference{
|
| 525 | 525 |
Name: bootstrappolicy.EditRoleName, |
| 526 | 526 |
}, |
| 527 |
- Users: util.NewStringSet("Ellen"),
|
|
| 527 |
+ Subjects: []kapi.ObjectReference{{Kind: authorizationapi.UserKind, Name: "Ellen"}},
|
|
| 528 | 528 |
}, |
| 529 | 529 |
}, |
| 530 | 530 |
}, |
| ... | ... |
@@ -543,7 +599,7 @@ func newAdzeBindings() []authorizationapi.PolicyBinding {
|
| 543 | 543 |
Name: "restrictedViewer", |
| 544 | 544 |
Namespace: "adze", |
| 545 | 545 |
}, |
| 546 |
- Users: util.NewStringSet("Rachel"),
|
|
| 546 |
+ Subjects: []kapi.ObjectReference{{Kind: authorizationapi.UserKind, Name: "Rachel"}},
|
|
| 547 | 547 |
}, |
| 548 | 548 |
}, |
| 549 | 549 |
}, |
| ... | ... |
@@ -463,7 +463,7 @@ func newMalletBindings() []authorizationapi.PolicyBinding {
|
| 463 | 463 |
RoleRef: kapi.ObjectReference{
|
| 464 | 464 |
Name: bootstrappolicy.AdminRoleName, |
| 465 | 465 |
}, |
| 466 |
- Users: util.NewStringSet("Matthew"),
|
|
| 466 |
+ Subjects: []kapi.ObjectReference{{Kind: authorizationapi.UserKind, Name: "Matthew"}},
|
|
| 467 | 467 |
}, |
| 468 | 468 |
"viewers": {
|
| 469 | 469 |
ObjectMeta: kapi.ObjectMeta{
|
| ... | ... |
@@ -473,7 +473,7 @@ func newMalletBindings() []authorizationapi.PolicyBinding {
|
| 473 | 473 |
RoleRef: kapi.ObjectReference{
|
| 474 | 474 |
Name: bootstrappolicy.ViewRoleName, |
| 475 | 475 |
}, |
| 476 |
- Users: util.NewStringSet("Victor"),
|
|
| 476 |
+ Subjects: []kapi.ObjectReference{{Kind: authorizationapi.UserKind, Name: "Victor"}},
|
|
| 477 | 477 |
}, |
| 478 | 478 |
"editors": {
|
| 479 | 479 |
ObjectMeta: kapi.ObjectMeta{
|
| ... | ... |
@@ -483,7 +483,7 @@ func newMalletBindings() []authorizationapi.PolicyBinding {
|
| 483 | 483 |
RoleRef: kapi.ObjectReference{
|
| 484 | 484 |
Name: bootstrappolicy.EditRoleName, |
| 485 | 485 |
}, |
| 486 |
- Users: util.NewStringSet("Edgar"),
|
|
| 486 |
+ Subjects: []kapi.ObjectReference{{Kind: authorizationapi.UserKind, Name: "Edgar"}},
|
|
| 487 | 487 |
}, |
| 488 | 488 |
}, |
| 489 | 489 |
}, |
| ... | ... |
@@ -534,7 +534,7 @@ func newInvalidExtensionBindings() []authorizationapi.PolicyBinding {
|
| 534 | 534 |
Name: "badExtension", |
| 535 | 535 |
Namespace: "mallet", |
| 536 | 536 |
}, |
| 537 |
- Users: util.NewStringSet("Brad"),
|
|
| 537 |
+ Subjects: []kapi.ObjectReference{{Kind: authorizationapi.UserKind, Name: "Brad"}},
|
|
| 538 | 538 |
}, |
| 539 | 539 |
}, |
| 540 | 540 |
}, |
| ... | ... |
@@ -34,7 +34,7 @@ func TestSubjects(t *testing.T) {
|
| 34 | 34 |
Verb: "get", |
| 35 | 35 |
Resource: "pods", |
| 36 | 36 |
}, |
| 37 |
- expectedUsers: util.NewStringSet("Anna", "ClusterAdmin", "Ellen", "Valerie"),
|
|
| 37 |
+ expectedUsers: util.NewStringSet("Anna", "ClusterAdmin", "Ellen", "Valerie", "system:serviceaccount:adze:second", "system:serviceaccount:foo:default", "system:serviceaccount:other:first"),
|
|
| 38 | 38 |
expectedGroups: util.NewStringSet("RootUsers", "system:cluster-admins", "system:cluster-readers", "system:masters", "system:nodes"),
|
| 39 | 39 |
} |
| 40 | 40 |
test.clusterPolicies = newDefaultClusterPolicies() |
| ... | ... |
@@ -208,10 +208,15 @@ func (a RoleBindingAdapter) RoleRef() kapi.ObjectReference {
|
| 208 | 208 |
} |
| 209 | 209 |
|
| 210 | 210 |
func (a RoleBindingAdapter) Users() util.StringSet {
|
| 211 |
- return a.roleBinding.Users |
|
| 211 |
+ users, _ := authorizationapi.StringSubjectsFor(a.roleBinding.Namespace, a.roleBinding.Subjects) |
|
| 212 |
+ |
|
| 213 |
+ return util.NewStringSet(users...) |
|
| 212 | 214 |
} |
| 215 |
+ |
|
| 213 | 216 |
func (a RoleBindingAdapter) Groups() util.StringSet {
|
| 214 |
- return a.roleBinding.Groups |
|
| 217 |
+ _, groups := authorizationapi.StringSubjectsFor(a.roleBinding.Namespace, a.roleBinding.Subjects) |
|
| 218 |
+ |
|
| 219 |
+ return util.NewStringSet(groups...) |
|
| 215 | 220 |
} |
| 216 | 221 |
|
| 217 | 222 |
type ClusterPolicyBindingAdapter struct {
|
| ... | ... |
@@ -260,8 +265,12 @@ func (a ClusterRoleBindingAdapter) RoleRef() kapi.ObjectReference {
|
| 260 | 260 |
} |
| 261 | 261 |
|
| 262 | 262 |
func (a ClusterRoleBindingAdapter) Users() util.StringSet {
|
| 263 |
- return a.roleBinding.Users |
|
| 263 |
+ users, _ := authorizationapi.StringSubjectsFor(a.roleBinding.Namespace, a.roleBinding.Subjects) |
|
| 264 |
+ |
|
| 265 |
+ return util.NewStringSet(users...) |
|
| 264 | 266 |
} |
| 265 | 267 |
func (a ClusterRoleBindingAdapter) Groups() util.StringSet {
|
| 266 |
- return a.roleBinding.Groups |
|
| 268 |
+ _, groups := authorizationapi.StringSubjectsFor(a.roleBinding.Namespace, a.roleBinding.Subjects) |
|
| 269 |
+ |
|
| 270 |
+ return util.NewStringSet(groups...) |
|
| 267 | 271 |
} |
| ... | ... |
@@ -44,7 +44,7 @@ func testNewClusterBindings() []authorizationapi.ClusterPolicyBinding {
|
| 44 | 44 |
"cluster-admins": {
|
| 45 | 45 |
ObjectMeta: kapi.ObjectMeta{Name: "cluster-admins"},
|
| 46 | 46 |
RoleRef: kapi.ObjectReference{Name: "cluster-admin"},
|
| 47 |
- Users: util.NewStringSet("system:admin"),
|
|
| 47 |
+ Subjects: []kapi.ObjectReference{{Kind: authorizationapi.SystemUserKind, Name: "system:admin"}},
|
|
| 48 | 48 |
}, |
| 49 | 49 |
}, |
| 50 | 50 |
}, |
| ... | ... |
@@ -7,12 +7,13 @@ import ( |
| 7 | 7 |
|
| 8 | 8 |
"github.com/spf13/cobra" |
| 9 | 9 |
|
| 10 |
- "k8s.io/kubernetes/pkg/controller/serviceaccount" |
|
| 10 |
+ kapi "k8s.io/kubernetes/pkg/api" |
|
| 11 | 11 |
kcmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" |
| 12 | 12 |
"k8s.io/kubernetes/pkg/util" |
| 13 | 13 |
|
| 14 | 14 |
authorizationapi "github.com/openshift/origin/pkg/authorization/api" |
| 15 | 15 |
"github.com/openshift/origin/pkg/cmd/util/clientcmd" |
| 16 |
+ uservalidation "github.com/openshift/origin/pkg/user/api/validation" |
|
| 16 | 17 |
) |
| 17 | 18 |
|
| 18 | 19 |
const ( |
| ... | ... |
@@ -32,8 +33,9 @@ type RoleModificationOptions struct {
|
| 32 | 32 |
RoleName string |
| 33 | 33 |
RoleBindingAccessor RoleBindingAccessor |
| 34 | 34 |
|
| 35 |
- Users []string |
|
| 36 |
- Groups []string |
|
| 35 |
+ Users []string |
|
| 36 |
+ Groups []string |
|
| 37 |
+ Subjects []kapi.ObjectReference |
|
| 37 | 38 |
} |
| 38 | 39 |
|
| 39 | 40 |
// NewCmdAddRoleToGroup implements the OpenShift cli add-role-to-group command |
| ... | ... |
@@ -246,7 +248,7 @@ func (o *RoleModificationOptions) CompleteUserWithSA(f *clientcmd.Factory, args |
| 246 | 246 |
o.RoleBindingAccessor = NewLocalRoleBindingAccessor(roleBindingNamespace, osClient) |
| 247 | 247 |
|
| 248 | 248 |
for _, sa := range saNames {
|
| 249 |
- o.Users = append(o.Users, serviceaccount.MakeUsername(roleBindingNamespace, sa)) |
|
| 249 |
+ o.Subjects = append(o.Subjects, kapi.ObjectReference{Name: sa, Kind: "ServiceAccount"})
|
|
| 250 | 250 |
} |
| 251 | 251 |
|
| 252 | 252 |
return nil |
| ... | ... |
@@ -293,7 +295,7 @@ func (o *RoleModificationOptions) AddRole() error {
|
| 293 | 293 |
var roleBinding *authorizationapi.RoleBinding |
| 294 | 294 |
isUpdate := true |
| 295 | 295 |
if len(roleBindings) == 0 {
|
| 296 |
- roleBinding = &authorizationapi.RoleBinding{Users: util.NewStringSet(), Groups: util.NewStringSet()}
|
|
| 296 |
+ roleBinding = &authorizationapi.RoleBinding{}
|
|
| 297 | 297 |
isUpdate = false |
| 298 | 298 |
} else {
|
| 299 | 299 |
// only need to add the user or group to a single roleBinding on the role. Just choose the first one |
| ... | ... |
@@ -303,8 +305,21 @@ func (o *RoleModificationOptions) AddRole() error {
|
| 303 | 303 |
roleBinding.RoleRef.Namespace = o.RoleNamespace |
| 304 | 304 |
roleBinding.RoleRef.Name = o.RoleName |
| 305 | 305 |
|
| 306 |
- roleBinding.Users.Insert(o.Users...) |
|
| 307 |
- roleBinding.Groups.Insert(o.Groups...) |
|
| 306 |
+ newSubjects := authorizationapi.BuildSubjects(o.Users, o.Groups, uservalidation.ValidateUserName, uservalidation.ValidateGroupName) |
|
| 307 |
+ newSubjects = append(newSubjects, o.Subjects...) |
|
| 308 |
+ |
|
| 309 |
+subjectCheck: |
|
| 310 |
+ for _, newSubject := range newSubjects {
|
|
| 311 |
+ for _, existingSubject := range roleBinding.Subjects {
|
|
| 312 |
+ if existingSubject.Kind == newSubject.Kind && |
|
| 313 |
+ existingSubject.Name == newSubject.Name && |
|
| 314 |
+ existingSubject.Namespace == newSubject.Namespace {
|
|
| 315 |
+ continue subjectCheck |
|
| 316 |
+ } |
|
| 317 |
+ } |
|
| 318 |
+ |
|
| 319 |
+ roleBinding.Subjects = append(roleBinding.Subjects, newSubject) |
|
| 320 |
+ } |
|
| 308 | 321 |
|
| 309 | 322 |
if isUpdate {
|
| 310 | 323 |
err = o.RoleBindingAccessor.UpdateRoleBinding(roleBinding) |
| ... | ... |
@@ -328,9 +343,11 @@ func (o *RoleModificationOptions) RemoveRole() error {
|
| 328 | 328 |
return fmt.Errorf("unable to locate RoleBinding for %v/%v", o.RoleNamespace, o.RoleName)
|
| 329 | 329 |
} |
| 330 | 330 |
|
| 331 |
+ subjectsToRemove := authorizationapi.BuildSubjects(o.Users, o.Groups, uservalidation.ValidateUserName, uservalidation.ValidateGroupName) |
|
| 332 |
+ subjectsToRemove = append(subjectsToRemove, o.Subjects...) |
|
| 333 |
+ |
|
| 331 | 334 |
for _, roleBinding := range roleBindings {
|
| 332 |
- roleBinding.Groups.Delete(o.Groups...) |
|
| 333 |
- roleBinding.Users.Delete(o.Users...) |
|
| 335 |
+ roleBinding.Subjects = removeSubjects(roleBinding.Subjects, subjectsToRemove) |
|
| 334 | 336 |
|
| 335 | 337 |
err = o.RoleBindingAccessor.UpdateRoleBinding(roleBinding) |
| 336 | 338 |
if err != nil {
|
| ... | ... |
@@ -340,3 +357,23 @@ func (o *RoleModificationOptions) RemoveRole() error {
|
| 340 | 340 |
|
| 341 | 341 |
return nil |
| 342 | 342 |
} |
| 343 |
+ |
|
| 344 |
+func removeSubjects(haystack, needles []kapi.ObjectReference) []kapi.ObjectReference {
|
|
| 345 |
+ newSubjects := []kapi.ObjectReference{}
|
|
| 346 |
+ |
|
| 347 |
+existingLoop: |
|
| 348 |
+ for _, existingSubject := range haystack {
|
|
| 349 |
+ for _, toRemove := range needles {
|
|
| 350 |
+ if existingSubject.Kind == toRemove.Kind && |
|
| 351 |
+ existingSubject.Name == toRemove.Name && |
|
| 352 |
+ existingSubject.Namespace == toRemove.Namespace {
|
|
| 353 |
+ continue existingLoop |
|
| 354 |
+ |
|
| 355 |
+ } |
|
| 356 |
+ } |
|
| 357 |
+ |
|
| 358 |
+ newSubjects = append(newSubjects, existingSubject) |
|
| 359 |
+ } |
|
| 360 |
+ |
|
| 361 |
+ return newSubjects |
|
| 362 |
+} |
| ... | ... |
@@ -7,6 +7,7 @@ import ( |
| 7 | 7 |
|
| 8 | 8 |
"github.com/spf13/cobra" |
| 9 | 9 |
|
| 10 |
+ kapi "k8s.io/kubernetes/pkg/api" |
|
| 10 | 11 |
"k8s.io/kubernetes/pkg/fields" |
| 11 | 12 |
kcmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util" |
| 12 | 13 |
"k8s.io/kubernetes/pkg/labels" |
| ... | ... |
@@ -15,6 +16,7 @@ import ( |
| 15 | 15 |
authorizationapi "github.com/openshift/origin/pkg/authorization/api" |
| 16 | 16 |
"github.com/openshift/origin/pkg/client" |
| 17 | 17 |
"github.com/openshift/origin/pkg/cmd/util/clientcmd" |
| 18 |
+ uservalidation "github.com/openshift/origin/pkg/user/api/validation" |
|
| 18 | 19 |
) |
| 19 | 20 |
|
| 20 | 21 |
const ( |
| ... | ... |
@@ -103,20 +105,25 @@ func (o *RemoveFromProjectOptions) Run() error {
|
| 103 | 103 |
|
| 104 | 104 |
usersRemoved := util.StringSet{}
|
| 105 | 105 |
groupsRemoved := util.StringSet{}
|
| 106 |
+ sasRemoved := util.StringSet{}
|
|
| 107 |
+ othersRemoved := util.StringSet{}
|
|
| 108 |
+ |
|
| 109 |
+ subjectsToRemove := authorizationapi.BuildSubjects(o.Users, o.Groups, uservalidation.ValidateUserName, uservalidation.ValidateGroupName) |
|
| 106 | 110 |
|
| 107 | 111 |
for _, currPolicyBinding := range bindingList.Items {
|
| 108 | 112 |
for _, currBinding := range authorizationapi.SortRoleBindings(currPolicyBinding.RoleBindings, true) {
|
| 109 |
- bindingHasGroups := len(o.Groups) > 0 && currBinding.Groups.HasAny(o.Groups...) |
|
| 110 |
- bindingHasUsers := len(o.Users) > 0 && currBinding.Users.HasAny(o.Users...) |
|
| 111 |
- if !bindingHasGroups && !bindingHasUsers {
|
|
| 112 |
- continue |
|
| 113 |
- } |
|
| 113 |
+ originalSubjects := make([]kapi.ObjectReference, len(currBinding.Subjects)) |
|
| 114 |
+ copy(originalSubjects, currBinding.Subjects) |
|
| 115 |
+ oldUsers, oldGroups, oldSAs, oldOthers := authorizationapi.SubjectsStrings(currBinding.Namespace, originalSubjects) |
|
| 116 |
+ oldUsersSet, oldGroupsSet, oldSAsSet, oldOtherSet := util.NewStringSet(oldUsers...), util.NewStringSet(oldGroups...), util.NewStringSet(oldSAs...), util.NewStringSet(oldOthers...) |
|
| 114 | 117 |
|
| 115 |
- existingGroups := util.NewStringSet(currBinding.Groups.List()...) |
|
| 116 |
- existingUsers := util.NewStringSet(currBinding.Users.List()...) |
|
| 118 |
+ currBinding.Subjects = removeSubjects(currBinding.Subjects, subjectsToRemove) |
|
| 119 |
+ newUsers, newGroups, newSAs, newOthers := authorizationapi.SubjectsStrings(currBinding.Namespace, currBinding.Subjects) |
|
| 120 |
+ newUsersSet, newGroupsSet, newSAsSet, newOtherSet := util.NewStringSet(newUsers...), util.NewStringSet(newGroups...), util.NewStringSet(newSAs...), util.NewStringSet(newOthers...) |
|
| 117 | 121 |
|
| 118 |
- currBinding.Groups.Delete(o.Groups...) |
|
| 119 |
- currBinding.Users.Delete(o.Users...) |
|
| 122 |
+ if len(currBinding.Subjects) == len(originalSubjects) {
|
|
| 123 |
+ continue |
|
| 124 |
+ } |
|
| 120 | 125 |
|
| 121 | 126 |
_, err = o.Client.RoleBindings(o.BindingNamespace).Update(currBinding) |
| 122 | 127 |
if err != nil {
|
| ... | ... |
@@ -127,23 +134,32 @@ func (o *RemoveFromProjectOptions) Run() error {
|
| 127 | 127 |
if len(currBinding.RoleRef.Namespace) == 0 {
|
| 128 | 128 |
roleDisplayName = currBinding.RoleRef.Name |
| 129 | 129 |
} |
| 130 |
- if diff := existingGroups.Difference(currBinding.Groups); len(diff) != 0 {
|
|
| 130 |
+ |
|
| 131 |
+ if diff := oldUsersSet.Difference(newUsersSet); len(diff) != 0 {
|
|
| 132 |
+ fmt.Fprintf(o.Out, "Removing %s from users %v in project %s.\n", roleDisplayName, diff.List(), o.BindingNamespace) |
|
| 133 |
+ usersRemoved.Insert(diff.List()...) |
|
| 134 |
+ } |
|
| 135 |
+ if diff := oldGroupsSet.Difference(newGroupsSet); len(diff) != 0 {
|
|
| 131 | 136 |
fmt.Fprintf(o.Out, "Removing %s from groups %v in project %s.\n", roleDisplayName, diff.List(), o.BindingNamespace) |
| 132 | 137 |
groupsRemoved.Insert(diff.List()...) |
| 133 | 138 |
} |
| 134 |
- if diff := existingUsers.Difference(currBinding.Users); len(diff) != 0 {
|
|
| 135 |
- fmt.Fprintf(o.Out, "Removing %s from users %v in project %s.\n", roleDisplayName, diff.List(), o.BindingNamespace) |
|
| 136 |
- usersRemoved.Insert(diff.List()...) |
|
| 139 |
+ if diff := oldSAsSet.Difference(newSAsSet); len(diff) != 0 {
|
|
| 140 |
+ fmt.Fprintf(o.Out, "Removing %s from serviceaccounts %v in project %s.\n", roleDisplayName, diff.List(), o.BindingNamespace) |
|
| 141 |
+ sasRemoved.Insert(diff.List()...) |
|
| 142 |
+ } |
|
| 143 |
+ if diff := oldOtherSet.Difference(newOtherSet); len(diff) != 0 {
|
|
| 144 |
+ fmt.Fprintf(o.Out, "Removing %s from subjects %v in project %s.\n", roleDisplayName, diff.List(), o.BindingNamespace) |
|
| 145 |
+ othersRemoved.Insert(diff.List()...) |
|
| 137 | 146 |
} |
| 138 | 147 |
} |
| 139 | 148 |
} |
| 140 | 149 |
|
| 141 |
- if diff := util.NewStringSet(o.Groups...).Difference(groupsRemoved); len(diff) != 0 {
|
|
| 142 |
- fmt.Fprintf(o.Out, "Groups %v were not bound to roles in project %s.\n", diff.List(), o.BindingNamespace) |
|
| 143 |
- } |
|
| 144 | 150 |
if diff := util.NewStringSet(o.Users...).Difference(usersRemoved); len(diff) != 0 {
|
| 145 | 151 |
fmt.Fprintf(o.Out, "Users %v were not bound to roles in project %s.\n", diff.List(), o.BindingNamespace) |
| 146 | 152 |
} |
| 153 |
+ if diff := util.NewStringSet(o.Groups...).Difference(groupsRemoved); len(diff) != 0 {
|
|
| 154 |
+ fmt.Fprintf(o.Out, "Groups %v were not bound to roles in project %s.\n", diff.List(), o.BindingNamespace) |
|
| 155 |
+ } |
|
| 147 | 156 |
|
| 148 | 157 |
return nil |
| 149 | 158 |
} |
| ... | ... |
@@ -128,8 +128,7 @@ func (o *NewProjectOptions) Run(useNodeSelector bool) error {
|
| 128 | 128 |
RoleName: binding.RoleRef.Name, |
| 129 | 129 |
RoleNamespace: binding.RoleRef.Namespace, |
| 130 | 130 |
RoleBindingAccessor: policy.NewLocalRoleBindingAccessor(o.ProjectName, o.Client), |
| 131 |
- Users: binding.Users.List(), |
|
| 132 |
- Groups: binding.Groups.List(), |
|
| 131 |
+ Subjects: binding.Subjects, |
|
| 133 | 132 |
} |
| 134 | 133 |
if err := addRole.AddRole(); err != nil {
|
| 135 | 134 |
fmt.Printf("Could not add service accounts to the %v role: %v\n", binding.RoleRef.Name, err)
|
| ... | ... |
@@ -1003,6 +1003,7 @@ func (d *PolicyBindingDescriber) Describe(namespace, name string) (string, error |
| 1003 | 1003 |
} |
| 1004 | 1004 |
|
| 1005 | 1005 |
func DescribePolicyBinding(policyBinding *authorizationapi.PolicyBinding) (string, error) {
|
| 1006 |
+ |
|
| 1006 | 1007 |
return tabbedString(func(out *tabwriter.Writer) error {
|
| 1007 | 1008 |
formatMeta(out, policyBinding.ObjectMeta) |
| 1008 | 1009 |
formatString(out, "Last Modified", policyBinding.LastModified) |
| ... | ... |
@@ -1011,10 +1012,14 @@ func DescribePolicyBinding(policyBinding *authorizationapi.PolicyBinding) (strin |
| 1011 | 1011 |
// using .List() here because I always want the sorted order that it provides |
| 1012 | 1012 |
for _, key := range util.KeySet(reflect.ValueOf(policyBinding.RoleBindings)).List() {
|
| 1013 | 1013 |
roleBinding := policyBinding.RoleBindings[key] |
| 1014 |
+ users, groups, sas, others := authorizationapi.SubjectsStrings(roleBinding.Namespace, roleBinding.Subjects) |
|
| 1015 |
+ |
|
| 1014 | 1016 |
formatString(out, "RoleBinding["+key+"]", " ") |
| 1015 | 1017 |
formatString(out, "\tRole", roleBinding.RoleRef.Name) |
| 1016 |
- formatString(out, "\tUsers", roleBinding.Users.List()) |
|
| 1017 |
- formatString(out, "\tGroups", roleBinding.Groups.List()) |
|
| 1018 |
+ formatString(out, "\tUsers", strings.Join(users, ", ")) |
|
| 1019 |
+ formatString(out, "\tGroups", strings.Join(groups, ", ")) |
|
| 1020 |
+ formatString(out, "\tServiceAccounts", strings.Join(sas, ", ")) |
|
| 1021 |
+ formatString(out, "\tSubjects", strings.Join(others, ", ")) |
|
| 1018 | 1022 |
} |
| 1019 | 1023 |
|
| 1020 | 1024 |
return nil |
| ... | ... |
@@ -1048,12 +1053,16 @@ func (d *RoleBindingDescriber) Describe(namespace, name string) (string, error) |
| 1048 | 1048 |
|
| 1049 | 1049 |
// DescribeRoleBinding prints out information about a role binding and its associated role |
| 1050 | 1050 |
func DescribeRoleBinding(roleBinding *authorizationapi.RoleBinding, role *authorizationapi.Role, err error) (string, error) {
|
| 1051 |
+ users, groups, sas, others := authorizationapi.SubjectsStrings(roleBinding.Namespace, roleBinding.Subjects) |
|
| 1052 |
+ |
|
| 1051 | 1053 |
return tabbedString(func(out *tabwriter.Writer) error {
|
| 1052 | 1054 |
formatMeta(out, roleBinding.ObjectMeta) |
| 1053 | 1055 |
|
| 1054 | 1056 |
formatString(out, "Role", roleBinding.RoleRef.Namespace+"/"+roleBinding.RoleRef.Name) |
| 1055 |
- formatString(out, "Users", roleBinding.Users.List()) |
|
| 1056 |
- formatString(out, "Groups", roleBinding.Groups.List()) |
|
| 1057 |
+ formatString(out, "Users", strings.Join(users, ", ")) |
|
| 1058 |
+ formatString(out, "Groups", strings.Join(groups, ", ")) |
|
| 1059 |
+ formatString(out, "ServiceAccounts", strings.Join(sas, ", ")) |
|
| 1060 |
+ formatString(out, "Subjects", strings.Join(others, ", ")) |
|
| 1057 | 1061 |
|
| 1058 | 1062 |
switch {
|
| 1059 | 1063 |
case err != nil: |
| ... | ... |
@@ -39,7 +39,7 @@ var ( |
| 39 | 39 |
templateColumns = []string{"NAME", "DESCRIPTION", "PARAMETERS", "OBJECTS"}
|
| 40 | 40 |
policyColumns = []string{"NAME", "ROLES", "LAST MODIFIED"}
|
| 41 | 41 |
policyBindingColumns = []string{"NAME", "ROLE BINDINGS", "LAST MODIFIED"}
|
| 42 |
- roleBindingColumns = []string{"NAME", "ROLE", "USERS", "GROUPS"}
|
|
| 42 |
+ roleBindingColumns = []string{"NAME", "ROLE", "USERS", "GROUPS", "SERVICE ACCOUNTS", "SUBJECTS"}
|
|
| 43 | 43 |
roleColumns = []string{"NAME"}
|
| 44 | 44 |
|
| 45 | 45 |
oauthClientColumns = []string{"NAME", "SECRET", "WWW-CHALLENGE", "REDIRECT URIS"}
|
| ... | ... |
@@ -512,7 +512,9 @@ func printRoleBinding(roleBinding *authorizationapi.RoleBinding, w io.Writer, wi |
| 512 | 512 |
return err |
| 513 | 513 |
} |
| 514 | 514 |
} |
| 515 |
- _, err := fmt.Fprintf(w, "%s\t%s\t%v\t%v\n", roleBinding.Name, roleBinding.RoleRef.Namespace+"/"+roleBinding.RoleRef.Name, roleBinding.Users.List(), roleBinding.Groups.List()) |
|
| 515 |
+ users, groups, sas, others := authorizationapi.SubjectsStrings(roleBinding.Namespace, roleBinding.Subjects) |
|
| 516 |
+ |
|
| 517 |
+ _, err := fmt.Fprintf(w, "%s\t%s\t%v\t%v\t%v\t%v\n", roleBinding.Name, roleBinding.RoleRef.Namespace+"/"+roleBinding.RoleRef.Name, strings.Join(users, ", "), strings.Join(groups, ", "), strings.Join(sas, ", "), strings.Join(others, ", ")) |
|
| 516 | 518 |
return err |
| 517 | 519 |
} |
| 518 | 520 |
|
| ... | ... |
@@ -518,7 +518,7 @@ func GetBootstrapOpenshiftRoleBindings(openshiftNamespace string) []authorizatio |
| 518 | 518 |
Name: OpenshiftSharedResourceViewRoleName, |
| 519 | 519 |
Namespace: openshiftNamespace, |
| 520 | 520 |
}, |
| 521 |
- Groups: util.NewStringSet(AuthenticatedGroup), |
|
| 521 |
+ Subjects: []kapi.ObjectReference{{Kind: authorizationapi.SystemGroupKind, Name: AuthenticatedGroup}},
|
|
| 522 | 522 |
}, |
| 523 | 523 |
} |
| 524 | 524 |
} |
| ... | ... |
@@ -532,7 +532,7 @@ func GetBootstrapClusterRoleBindings() []authorizationapi.ClusterRoleBinding {
|
| 532 | 532 |
RoleRef: kapi.ObjectReference{
|
| 533 | 533 |
Name: MasterRoleName, |
| 534 | 534 |
}, |
| 535 |
- Groups: util.NewStringSet(MastersGroup), |
|
| 535 |
+ Subjects: []kapi.ObjectReference{{Kind: authorizationapi.SystemGroupKind, Name: MastersGroup}},
|
|
| 536 | 536 |
}, |
| 537 | 537 |
{
|
| 538 | 538 |
ObjectMeta: kapi.ObjectMeta{
|
| ... | ... |
@@ -541,7 +541,7 @@ func GetBootstrapClusterRoleBindings() []authorizationapi.ClusterRoleBinding {
|
| 541 | 541 |
RoleRef: kapi.ObjectReference{
|
| 542 | 542 |
Name: ClusterAdminRoleName, |
| 543 | 543 |
}, |
| 544 |
- Groups: util.NewStringSet(ClusterAdminGroup), |
|
| 544 |
+ Subjects: []kapi.ObjectReference{{Kind: authorizationapi.SystemGroupKind, Name: ClusterAdminGroup}},
|
|
| 545 | 545 |
}, |
| 546 | 546 |
{
|
| 547 | 547 |
ObjectMeta: kapi.ObjectMeta{
|
| ... | ... |
@@ -550,7 +550,7 @@ func GetBootstrapClusterRoleBindings() []authorizationapi.ClusterRoleBinding {
|
| 550 | 550 |
RoleRef: kapi.ObjectReference{
|
| 551 | 551 |
Name: ClusterReaderRoleName, |
| 552 | 552 |
}, |
| 553 |
- Groups: util.NewStringSet(ClusterReaderGroup), |
|
| 553 |
+ Subjects: []kapi.ObjectReference{{Kind: authorizationapi.SystemGroupKind, Name: ClusterReaderGroup}},
|
|
| 554 | 554 |
}, |
| 555 | 555 |
{
|
| 556 | 556 |
ObjectMeta: kapi.ObjectMeta{
|
| ... | ... |
@@ -559,7 +559,7 @@ func GetBootstrapClusterRoleBindings() []authorizationapi.ClusterRoleBinding {
|
| 559 | 559 |
RoleRef: kapi.ObjectReference{
|
| 560 | 560 |
Name: BasicUserRoleName, |
| 561 | 561 |
}, |
| 562 |
- Groups: util.NewStringSet(AuthenticatedGroup), |
|
| 562 |
+ Subjects: []kapi.ObjectReference{{Kind: authorizationapi.SystemGroupKind, Name: AuthenticatedGroup}},
|
|
| 563 | 563 |
}, |
| 564 | 564 |
{
|
| 565 | 565 |
ObjectMeta: kapi.ObjectMeta{
|
| ... | ... |
@@ -568,7 +568,7 @@ func GetBootstrapClusterRoleBindings() []authorizationapi.ClusterRoleBinding {
|
| 568 | 568 |
RoleRef: kapi.ObjectReference{
|
| 569 | 569 |
Name: SelfProvisionerRoleName, |
| 570 | 570 |
}, |
| 571 |
- Groups: util.NewStringSet(AuthenticatedGroup), |
|
| 571 |
+ Subjects: []kapi.ObjectReference{{Kind: authorizationapi.SystemGroupKind, Name: AuthenticatedGroup}},
|
|
| 572 | 572 |
}, |
| 573 | 573 |
{
|
| 574 | 574 |
ObjectMeta: kapi.ObjectMeta{
|
| ... | ... |
@@ -577,7 +577,7 @@ func GetBootstrapClusterRoleBindings() []authorizationapi.ClusterRoleBinding {
|
| 577 | 577 |
RoleRef: kapi.ObjectReference{
|
| 578 | 578 |
Name: OAuthTokenDeleterRoleName, |
| 579 | 579 |
}, |
| 580 |
- Groups: util.NewStringSet(AuthenticatedGroup, UnauthenticatedGroup), |
|
| 580 |
+ Subjects: []kapi.ObjectReference{{Kind: authorizationapi.SystemGroupKind, Name: AuthenticatedGroup}, {Kind: authorizationapi.SystemGroupKind, Name: UnauthenticatedGroup}},
|
|
| 581 | 581 |
}, |
| 582 | 582 |
{
|
| 583 | 583 |
ObjectMeta: kapi.ObjectMeta{
|
| ... | ... |
@@ -586,7 +586,7 @@ func GetBootstrapClusterRoleBindings() []authorizationapi.ClusterRoleBinding {
|
| 586 | 586 |
RoleRef: kapi.ObjectReference{
|
| 587 | 587 |
Name: StatusCheckerRoleName, |
| 588 | 588 |
}, |
| 589 |
- Groups: util.NewStringSet(AuthenticatedGroup, UnauthenticatedGroup), |
|
| 589 |
+ Subjects: []kapi.ObjectReference{{Kind: authorizationapi.SystemGroupKind, Name: AuthenticatedGroup}, {Kind: authorizationapi.SystemGroupKind, Name: UnauthenticatedGroup}},
|
|
| 590 | 590 |
}, |
| 591 | 591 |
{
|
| 592 | 592 |
ObjectMeta: kapi.ObjectMeta{
|
| ... | ... |
@@ -595,7 +595,7 @@ func GetBootstrapClusterRoleBindings() []authorizationapi.ClusterRoleBinding {
|
| 595 | 595 |
RoleRef: kapi.ObjectReference{
|
| 596 | 596 |
Name: RouterRoleName, |
| 597 | 597 |
}, |
| 598 |
- Groups: util.NewStringSet(RouterGroup), |
|
| 598 |
+ Subjects: []kapi.ObjectReference{{Kind: authorizationapi.SystemGroupKind, Name: RouterGroup}},
|
|
| 599 | 599 |
}, |
| 600 | 600 |
{
|
| 601 | 601 |
ObjectMeta: kapi.ObjectMeta{
|
| ... | ... |
@@ -604,7 +604,7 @@ func GetBootstrapClusterRoleBindings() []authorizationapi.ClusterRoleBinding {
|
| 604 | 604 |
RoleRef: kapi.ObjectReference{
|
| 605 | 605 |
Name: RegistryRoleName, |
| 606 | 606 |
}, |
| 607 |
- Groups: util.NewStringSet(RegistryGroup), |
|
| 607 |
+ Subjects: []kapi.ObjectReference{{Kind: authorizationapi.SystemGroupKind, Name: RegistryGroup}},
|
|
| 608 | 608 |
}, |
| 609 | 609 |
{
|
| 610 | 610 |
ObjectMeta: kapi.ObjectMeta{
|
| ... | ... |
@@ -613,7 +613,7 @@ func GetBootstrapClusterRoleBindings() []authorizationapi.ClusterRoleBinding {
|
| 613 | 613 |
RoleRef: kapi.ObjectReference{
|
| 614 | 614 |
Name: NodeRoleName, |
| 615 | 615 |
}, |
| 616 |
- Groups: util.NewStringSet(NodesGroup), |
|
| 616 |
+ Subjects: []kapi.ObjectReference{{Kind: authorizationapi.SystemGroupKind, Name: NodesGroup}},
|
|
| 617 | 617 |
}, |
| 618 | 618 |
{
|
| 619 | 619 |
ObjectMeta: kapi.ObjectMeta{
|
| ... | ... |
@@ -623,7 +623,7 @@ func GetBootstrapClusterRoleBindings() []authorizationapi.ClusterRoleBinding {
|
| 623 | 623 |
Name: NodeProxierRoleName, |
| 624 | 624 |
}, |
| 625 | 625 |
// Allow node identities to run node proxies |
| 626 |
- Groups: util.NewStringSet(NodesGroup), |
|
| 626 |
+ Subjects: []kapi.ObjectReference{{Kind: authorizationapi.SystemGroupKind, Name: NodesGroup}},
|
|
| 627 | 627 |
}, |
| 628 | 628 |
{
|
| 629 | 629 |
ObjectMeta: kapi.ObjectMeta{
|
| ... | ... |
@@ -633,7 +633,7 @@ func GetBootstrapClusterRoleBindings() []authorizationapi.ClusterRoleBinding {
|
| 633 | 633 |
Name: SDNReaderRoleName, |
| 634 | 634 |
}, |
| 635 | 635 |
// Allow node identities to run SDN plugins |
| 636 |
- Groups: util.NewStringSet(NodesGroup), |
|
| 636 |
+ Subjects: []kapi.ObjectReference{{Kind: authorizationapi.SystemGroupKind, Name: NodesGroup}},
|
|
| 637 | 637 |
}, |
| 638 | 638 |
{
|
| 639 | 639 |
ObjectMeta: kapi.ObjectMeta{
|
| ... | ... |
@@ -642,7 +642,7 @@ func GetBootstrapClusterRoleBindings() []authorizationapi.ClusterRoleBinding {
|
| 642 | 642 |
RoleRef: kapi.ObjectReference{
|
| 643 | 643 |
Name: WebHooksRoleName, |
| 644 | 644 |
}, |
| 645 |
- Groups: util.NewStringSet(AuthenticatedGroup, UnauthenticatedGroup), |
|
| 645 |
+ Subjects: []kapi.ObjectReference{{Kind: authorizationapi.SystemGroupKind, Name: AuthenticatedGroup}, {Kind: authorizationapi.SystemGroupKind, Name: UnauthenticatedGroup}},
|
|
| 646 | 646 |
}, |
| 647 | 647 |
} |
| 648 | 648 |
} |
| ... | ... |
@@ -3,7 +3,6 @@ package bootstrappolicy |
| 3 | 3 |
import ( |
| 4 | 4 |
kapi "k8s.io/kubernetes/pkg/api" |
| 5 | 5 |
"k8s.io/kubernetes/pkg/controller/serviceaccount" |
| 6 |
- "k8s.io/kubernetes/pkg/util" |
|
| 7 | 6 |
|
| 8 | 7 |
authorizationapi "github.com/openshift/origin/pkg/authorization/api" |
| 9 | 8 |
) |
| ... | ... |
@@ -18,7 +17,7 @@ func GetBootstrapServiceAccountProjectRoleBindings(namespace string) []authoriza |
| 18 | 18 |
RoleRef: kapi.ObjectReference{
|
| 19 | 19 |
Name: ImagePullerRoleName, |
| 20 | 20 |
}, |
| 21 |
- Groups: util.NewStringSet(serviceaccount.MakeNamespaceGroupName(namespace)), |
|
| 21 |
+ Subjects: []kapi.ObjectReference{{Kind: authorizationapi.SystemGroupKind, Name: serviceaccount.MakeNamespaceGroupName(namespace)}},
|
|
| 22 | 22 |
}, |
| 23 | 23 |
{
|
| 24 | 24 |
ObjectMeta: kapi.ObjectMeta{
|
| ... | ... |
@@ -28,7 +27,7 @@ func GetBootstrapServiceAccountProjectRoleBindings(namespace string) []authoriza |
| 28 | 28 |
RoleRef: kapi.ObjectReference{
|
| 29 | 29 |
Name: ImageBuilderRoleName, |
| 30 | 30 |
}, |
| 31 |
- Users: util.NewStringSet(serviceaccount.MakeUsername(namespace, BuilderServiceAccountName)), |
|
| 31 |
+ Subjects: []kapi.ObjectReference{{Kind: authorizationapi.ServiceAccountKind, Name: BuilderServiceAccountName}},
|
|
| 32 | 32 |
}, |
| 33 | 33 |
{
|
| 34 | 34 |
ObjectMeta: kapi.ObjectMeta{
|
| ... | ... |
@@ -38,7 +37,7 @@ func GetBootstrapServiceAccountProjectRoleBindings(namespace string) []authoriza |
| 38 | 38 |
RoleRef: kapi.ObjectReference{
|
| 39 | 39 |
Name: DeployerRoleName, |
| 40 | 40 |
}, |
| 41 |
- Users: util.NewStringSet(serviceaccount.MakeUsername(namespace, DeployerServiceAccountName)), |
|
| 41 |
+ Subjects: []kapi.ObjectReference{{Kind: authorizationapi.ServiceAccountKind, Name: DeployerServiceAccountName}},
|
|
| 42 | 42 |
}, |
| 43 | 43 |
} |
| 44 | 44 |
} |
| ... | ... |
@@ -56,22 +56,22 @@ func (c *MasterConfig) ensureOpenShiftInfraNamespace() {
|
| 56 | 56 |
} |
| 57 | 57 |
|
| 58 | 58 |
// Ensure service account cluster role bindings exist |
| 59 |
- clusterRolesToUsernames := map[string][]string{
|
|
| 60 |
- bootstrappolicy.BuildControllerRoleName: {serviceaccount.MakeUsername(ns, c.BuildControllerServiceAccount)},
|
|
| 61 |
- bootstrappolicy.DeploymentControllerRoleName: {serviceaccount.MakeUsername(ns, c.DeploymentControllerServiceAccount)},
|
|
| 62 |
- bootstrappolicy.ReplicationControllerRoleName: {serviceaccount.MakeUsername(ns, c.ReplicationControllerServiceAccount)},
|
|
| 59 |
+ clusterRolesToSubjects := map[string][]kapi.ObjectReference{
|
|
| 60 |
+ bootstrappolicy.BuildControllerRoleName: {{Namespace: ns, Name: c.BuildControllerServiceAccount, Kind: "ServiceAccount"}},
|
|
| 61 |
+ bootstrappolicy.DeploymentControllerRoleName: {{Namespace: ns, Name: c.DeploymentControllerServiceAccount, Kind: "ServiceAccount"}},
|
|
| 62 |
+ bootstrappolicy.ReplicationControllerRoleName: {{Namespace: ns, Name: c.ReplicationControllerServiceAccount, Kind: "ServiceAccount"}},
|
|
| 63 | 63 |
} |
| 64 | 64 |
roleAccessor := policy.NewClusterRoleBindingAccessor(c.ServiceAccountRoleBindingClient()) |
| 65 |
- for clusterRole, usernames := range clusterRolesToUsernames {
|
|
| 65 |
+ for clusterRole, subjects := range clusterRolesToSubjects {
|
|
| 66 | 66 |
addRole := &policy.RoleModificationOptions{
|
| 67 | 67 |
RoleName: clusterRole, |
| 68 | 68 |
RoleBindingAccessor: roleAccessor, |
| 69 |
- Users: usernames, |
|
| 69 |
+ Subjects: subjects, |
|
| 70 | 70 |
} |
| 71 | 71 |
if err := addRole.AddRole(); err != nil {
|
| 72 |
- glog.Errorf("Could not add %v users to the %v cluster role: %v\n", usernames, clusterRole, err)
|
|
| 72 |
+ glog.Errorf("Could not add %v subjects to the %v cluster role: %v\n", subjects, clusterRole, err)
|
|
| 73 | 73 |
} else {
|
| 74 |
- glog.V(2).Infof("Added %v users to the %v cluster role: %v\n", usernames, clusterRole, err)
|
|
| 74 |
+ glog.V(2).Infof("Added %v subjects to the %v cluster role: %v\n", subjects, clusterRole, err)
|
|
| 75 | 75 |
} |
| 76 | 76 |
} |
| 77 | 77 |
} |
| ... | ... |
@@ -128,8 +128,7 @@ func (c *MasterConfig) ensureDefaultNamespaceServiceAccountRoles() {
|
| 128 | 128 |
RoleName: binding.RoleRef.Name, |
| 129 | 129 |
RoleNamespace: binding.RoleRef.Namespace, |
| 130 | 130 |
RoleBindingAccessor: policy.NewLocalRoleBindingAccessor(kapi.NamespaceDefault, c.ServiceAccountRoleBindingClient()), |
| 131 |
- Users: binding.Users.List(), |
|
| 132 |
- Groups: binding.Groups.List(), |
|
| 131 |
+ Subjects: binding.Subjects, |
|
| 133 | 132 |
} |
| 134 | 133 |
if err := addRole.AddRole(); err != nil {
|
| 135 | 134 |
glog.Errorf("Could not add service accounts to the %v role in the %v namespace: %v\n", binding.RoleRef.Name, kapi.NamespaceDefault, err)
|
| ... | ... |
@@ -1,7 +1,7 @@ |
| 1 | 1 |
package delegated |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 |
- "k8s.io/kubernetes/pkg/util" |
|
| 4 |
+ kapi "k8s.io/kubernetes/pkg/api" |
|
| 5 | 5 |
|
| 6 | 6 |
authorizationapi "github.com/openshift/origin/pkg/authorization/api" |
| 7 | 7 |
"github.com/openshift/origin/pkg/cmd/server/bootstrappolicy" |
| ... | ... |
@@ -39,7 +39,7 @@ func DefaultTemplate() *templateapi.Template {
|
| 39 | 39 |
binding := &authorizationapi.RoleBinding{}
|
| 40 | 40 |
binding.Name = "admins" |
| 41 | 41 |
binding.Namespace = ns |
| 42 |
- binding.Users = util.NewStringSet("${" + ProjectAdminUserParam + "}")
|
|
| 42 |
+ binding.Subjects = []kapi.ObjectReference{{Kind: authorizationapi.UserKind, Name: "${" + ProjectAdminUserParam + "}"}}
|
|
| 43 | 43 |
binding.RoleRef.Name = bootstrappolicy.AdminRoleName |
| 44 | 44 |
ret.Objects = append(ret.Objects, binding) |
| 45 | 45 |
|
| ... | ... |
@@ -8,17 +8,20 @@ set -o pipefail |
| 8 | 8 |
|
| 9 | 9 |
oc policy add-role-to-group cluster-admin system:unauthenticated |
| 10 | 10 |
oc policy add-role-to-user cluster-admin system:no-user |
| 11 |
+oc get rolebinding/cluster-admin --no-headers |
|
| 11 | 12 |
oc get rolebinding/cluster-admin --no-headers | grep -q "system:no-user" |
| 12 | 13 |
|
| 13 | 14 |
oc policy add-role-to-user cluster-admin -z=one,two --serviceaccount=three,four |
| 14 |
-oc get rolebinding/cluster-admin --no-headers | grep -q "system:serviceaccount:cmd-policy:one" |
|
| 15 |
-oc get rolebinding/cluster-admin --no-headers | grep -q "system:serviceaccount:cmd-policy:four" |
|
| 15 |
+oc get rolebinding/cluster-admin --no-headers |
|
| 16 |
+oc get rolebinding/cluster-admin --no-headers | grep -q "one" |
|
| 17 |
+oc get rolebinding/cluster-admin --no-headers | grep -q "four" |
|
| 16 | 18 |
|
| 17 | 19 |
oc policy remove-role-from-group cluster-admin system:unauthenticated |
| 18 | 20 |
|
| 19 | 21 |
oc policy remove-role-from-user cluster-admin system:no-user |
| 20 | 22 |
oc policy remove-role-from-user cluster-admin -z=one,two --serviceaccount=three,four |
| 21 |
-[ ! "$(oc get rolebinding/cluster-admin --no-headers | grep -q "system:serviceaccount:cmd-policy:four")" ] |
|
| 23 |
+oc get rolebinding/cluster-admin --no-headers |
|
| 24 |
+[ ! "$(oc get rolebinding/cluster-admin --no-headers | grep -q "four")" ] |
|
| 22 | 25 |
|
| 23 | 26 |
oc policy remove-group system:unauthenticated |
| 24 | 27 |
oc policy remove-user system:no-user |
| ... | ... |
@@ -6,12 +6,11 @@ import ( |
| 6 | 6 |
"reflect" |
| 7 | 7 |
"testing" |
| 8 | 8 |
|
| 9 |
- "k8s.io/kubernetes/pkg/util" |
|
| 10 |
- |
|
| 11 | 9 |
authorizationapi "github.com/openshift/origin/pkg/authorization/api" |
| 12 | 10 |
groupscmd "github.com/openshift/origin/pkg/cmd/admin/groups" |
| 13 | 11 |
projectapi "github.com/openshift/origin/pkg/project/api" |
| 14 | 12 |
userapi "github.com/openshift/origin/pkg/user/api" |
| 13 |
+ uservalidation "github.com/openshift/origin/pkg/user/api/validation" |
|
| 15 | 14 |
testutil "github.com/openshift/origin/test/util" |
| 16 | 15 |
) |
| 17 | 16 |
|
| ... | ... |
@@ -85,7 +84,7 @@ func TestBasicUserBasedGroupManipulation(t *testing.T) {
|
| 85 | 85 |
roleBinding := &authorizationapi.RoleBinding{}
|
| 86 | 86 |
roleBinding.Name = "admins" |
| 87 | 87 |
roleBinding.RoleRef.Name = "admin" |
| 88 |
- roleBinding.Groups = util.NewStringSet(valerieGroups...) |
|
| 88 |
+ roleBinding.Subjects = authorizationapi.BuildSubjects([]string{}, valerieGroups, uservalidation.ValidateUserName, uservalidation.ValidateGroupName)
|
|
| 89 | 89 |
_, err = clusterAdminClient.RoleBindings("empty").Create(roleBinding)
|
| 90 | 90 |
if err != nil {
|
| 91 | 91 |
t.Fatalf("unexpected error: %v", err)
|
| ... | ... |
@@ -145,7 +144,7 @@ func TestBasicGroupManipulation(t *testing.T) {
|
| 145 | 145 |
roleBinding := &authorizationapi.RoleBinding{}
|
| 146 | 146 |
roleBinding.Name = "admins" |
| 147 | 147 |
roleBinding.RoleRef.Name = "admin" |
| 148 |
- roleBinding.Groups = util.NewStringSet(theGroup.Name) |
|
| 148 |
+ roleBinding.Subjects = authorizationapi.BuildSubjects([]string{}, []string{theGroup.Name}, uservalidation.ValidateUserName, uservalidation.ValidateGroupName)
|
|
| 149 | 149 |
_, err = clusterAdminClient.RoleBindings("empty").Create(roleBinding)
|
| 150 | 150 |
if err != nil {
|
| 151 | 151 |
t.Fatalf("unexpected error: %v", err)
|
| ... | ... |
@@ -8,6 +8,7 @@ import ( |
| 8 | 8 |
|
| 9 | 9 |
testutil "github.com/openshift/origin/test/util" |
| 10 | 10 |
|
| 11 |
+ authorizationinterfaces "github.com/openshift/origin/pkg/authorization/interfaces" |
|
| 11 | 12 |
policy "github.com/openshift/origin/pkg/cmd/admin/policy" |
| 12 | 13 |
"github.com/openshift/origin/pkg/cmd/server/bootstrappolicy" |
| 13 | 14 |
) |
| ... | ... |
@@ -50,11 +51,12 @@ func TestPolicyCommands(t *testing.T) {
|
| 50 | 50 |
if err != nil {
|
| 51 | 51 |
t.Fatalf("unexpected error: %v", err)
|
| 52 | 52 |
} |
| 53 |
- if !viewers.Users.Has("valerie") {
|
|
| 54 |
- t.Errorf("expected valerie in users: %v", viewers.Users)
|
|
| 53 |
+ binding := authorizationinterfaces.NewLocalRoleBindingAdapter(viewers) |
|
| 54 |
+ if !binding.Users().Has("valerie") {
|
|
| 55 |
+ t.Errorf("expected valerie in users: %v", binding.Users())
|
|
| 55 | 56 |
} |
| 56 |
- if !viewers.Groups.Has("my-group") {
|
|
| 57 |
- t.Errorf("expected my-group in groups: %v", viewers.Groups)
|
|
| 57 |
+ if !binding.Groups().Has("my-group") {
|
|
| 58 |
+ t.Errorf("expected my-group in groups: %v", binding.Groups())
|
|
| 58 | 59 |
} |
| 59 | 60 |
|
| 60 | 61 |
removeValerie := policy.RemoveFromProjectOptions{
|
| ... | ... |
@@ -71,11 +73,12 @@ func TestPolicyCommands(t *testing.T) {
|
| 71 | 71 |
if err != nil {
|
| 72 | 72 |
t.Fatalf("unexpected error: %v", err)
|
| 73 | 73 |
} |
| 74 |
- if viewers.Users.Has("valerie") {
|
|
| 75 |
- t.Errorf("unexpected valerie in users: %v", viewers.Users)
|
|
| 74 |
+ binding = authorizationinterfaces.NewLocalRoleBindingAdapter(viewers) |
|
| 75 |
+ if binding.Users().Has("valerie") {
|
|
| 76 |
+ t.Errorf("unexpected valerie in users: %v", binding.Users())
|
|
| 76 | 77 |
} |
| 77 |
- if !viewers.Groups.Has("my-group") {
|
|
| 78 |
- t.Errorf("expected my-group in groups: %v", viewers.Groups)
|
|
| 78 |
+ if !binding.Groups().Has("my-group") {
|
|
| 79 |
+ t.Errorf("expected my-group in groups: %v", binding.Groups())
|
|
| 79 | 80 |
} |
| 80 | 81 |
|
| 81 | 82 |
removeMyGroup := policy.RemoveFromProjectOptions{
|
| ... | ... |
@@ -92,11 +95,12 @@ func TestPolicyCommands(t *testing.T) {
|
| 92 | 92 |
if err != nil {
|
| 93 | 93 |
t.Fatalf("unexpected error: %v", err)
|
| 94 | 94 |
} |
| 95 |
- if viewers.Users.Has("valerie") {
|
|
| 96 |
- t.Errorf("unexpected valerie in users: %v", viewers.Users)
|
|
| 95 |
+ binding = authorizationinterfaces.NewLocalRoleBindingAdapter(viewers) |
|
| 96 |
+ if binding.Users().Has("valerie") {
|
|
| 97 |
+ t.Errorf("unexpected valerie in users: %v", binding.Users())
|
|
| 97 | 98 |
} |
| 98 |
- if viewers.Groups.Has("my-group") {
|
|
| 99 |
- t.Errorf("unexpected my-group in groups: %v", viewers.Groups)
|
|
| 99 |
+ if binding.Groups().Has("my-group") {
|
|
| 100 |
+ t.Errorf("unexpected my-group in groups: %v", binding.Groups())
|
|
| 100 | 101 |
} |
| 101 | 102 |
|
| 102 | 103 |
} |