Commit ae839ffc authored by Kubernetes Submit Queue's avatar Kubernetes Submit Queue Committed by GitHub

Merge pull request #31543 from deads2k/rbac-06-change-role-ref

Automatic merge from submit-queue Change rbac roleref to reflect the information we want @liggitt @ericchiang This is a version of https://github.com/kubernetes/kubernetes/pull/31359 which updates the `RoleRef` to be (I think) the type that we want, with a group, resource, and name. This is **not** backwards compatible with any existing data. I'm ok with doing this since rbac was considered alpha, but its something to consider. If we want this instead, I'll close the previous pull (or update it with this content).
parents af325ee7 7f6cb437
......@@ -2713,7 +2713,7 @@
"description": "Subjects holds references to the objects the role applies to."
},
"roleRef": {
"$ref": "v1.ObjectReference",
"$ref": "v1alpha1.RoleRef",
"description": "RoleRef can only reference a ClusterRole in the global namespace. If the RoleRef cannot be resolved, the Authorizer must return an error."
}
}
......@@ -2852,37 +2852,26 @@
}
}
},
"v1.ObjectReference": {
"id": "v1.ObjectReference",
"description": "ObjectReference contains enough information to let you inspect or modify the referred object.",
"v1alpha1.RoleRef": {
"id": "v1alpha1.RoleRef",
"description": "RoleRef contains information that points to the role being used",
"required": [
"apiGroup",
"kind",
"name"
],
"properties": {
"kind": {
"apiGroup": {
"type": "string",
"description": "Kind of the referent. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#types-kinds"
"description": "APIGroup is the group for the resource being referenced"
},
"namespace": {
"kind": {
"type": "string",
"description": "Namespace of the referent. More info: http://releases.k8s.io/HEAD/docs/user-guide/namespaces.md"
"description": "Kind is the type of resource being referenced"
},
"name": {
"type": "string",
"description": "Name of the referent. More info: http://releases.k8s.io/HEAD/docs/user-guide/identifiers.md#names"
},
"uid": {
"type": "string",
"description": "UID of the referent. More info: http://releases.k8s.io/HEAD/docs/user-guide/identifiers.md#uids"
},
"apiVersion": {
"type": "string",
"description": "API version of the referent."
},
"resourceVersion": {
"type": "string",
"description": "Specific resourceVersion to which this reference is made, if any. More info: http://releases.k8s.io/HEAD/docs/devel/api-conventions.md#concurrency-control-and-consistency"
},
"fieldPath": {
"type": "string",
"description": "If referring to a piece of an object instead of an entire object, this string should contain a valid JSON/Go field access statement, such as desiredState.manifest.containers[2]. For example, if the object reference is to a container within a pod, this would take on a value like: \"spec.containers{name}\" (where \"name\" refers to the name of the container that triggered the event) or if no container name is specified \"spec.containers[2]\" (container with index 2 in this pod). This syntax is chosen only to have some well-defined way of referencing a part of an object."
"description": "Name is the name of resource being referenced"
}
}
},
......@@ -3183,7 +3172,7 @@
"description": "Subjects holds references to the objects the role applies to."
},
"roleRef": {
"$ref": "v1.ObjectReference",
"$ref": "v1alpha1.RoleRef",
"description": "RoleRef can reference a Role in the current namespace or a ClusterRole in the global namespace. If the RoleRef cannot be resolved, the Authorizer must return an error."
}
}
......
......@@ -30,6 +30,7 @@ import (
"k8s.io/kubernetes/pkg/apis/autoscaling"
"k8s.io/kubernetes/pkg/apis/batch"
"k8s.io/kubernetes/pkg/apis/extensions"
"k8s.io/kubernetes/pkg/apis/rbac"
"k8s.io/kubernetes/pkg/fields"
"k8s.io/kubernetes/pkg/labels"
"k8s.io/kubernetes/pkg/runtime"
......@@ -498,6 +499,14 @@ func FuzzerFor(t *testing.T, version unversioned.GroupVersion, src rand.Source)
}
}
},
func(r *rbac.RoleRef, c fuzz.Continue) {
c.FuzzNoCustom(r) // fuzz self without calling this function again
// match defaulter
if len(r.APIGroup) == 0 {
r.APIGroup = rbac.GroupName
}
},
func(r *runtime.RawExtension, c fuzz.Continue) {
// Pick an arbitrary type and fuzz it
types := []runtime.Object{&api.Pod{}, &extensions.Deployment{}, &api.Service{}}
......
/*
Copyright 2016 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package rbac
import (
"k8s.io/kubernetes/pkg/api/unversioned"
)
func RoleRefGroupKind(roleRef RoleRef) unversioned.GroupKind {
return unversioned.GroupKind{Group: roleRef.APIGroup, Kind: roleRef.Kind}
}
......@@ -80,6 +80,16 @@ type Subject struct {
Namespace string
}
// RoleRef contains information that points to the role being used
type RoleRef struct {
// APIGroup is the group for the resource being referenced
APIGroup string
// Kind is the type of resource being referenced
Kind string
// Name is the name of resource being referenced
Name string
}
// +genclient=true
// Role is a namespaced, logical grouping of PolicyRules that can be referenced as a unit by a RoleBinding.
......@@ -106,7 +116,7 @@ type RoleBinding struct {
// RoleRef can reference a Role in the current namespace or a ClusterRole in the global namespace.
// If the RoleRef cannot be resolved, the Authorizer must return an error.
RoleRef api.ObjectReference
RoleRef RoleRef
}
// RoleBindingList is a collection of RoleBindings
......@@ -157,7 +167,7 @@ type ClusterRoleBinding struct {
// RoleRef can only reference a ClusterRole in the global namespace.
// If the RoleRef cannot be resolved, the Authorizer must return an error.
RoleRef api.ObjectReference
RoleRef RoleRef
}
// ClusterRoleBindingList is a collection of ClusterRoleBindings
......
/*
Copyright 2016 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1alpha1
import (
"k8s.io/kubernetes/pkg/runtime"
)
func addDefaultingFuncs(scheme *runtime.Scheme) error {
return scheme.AddDefaultingFuncs(
func(obj *ClusterRoleBinding) {
if len(obj.RoleRef.APIGroup) == 0 {
obj.RoleRef.APIGroup = GroupName
}
},
func(obj *RoleBinding) {
if len(obj.RoleRef.APIGroup) == 0 {
obj.RoleRef.APIGroup = GroupName
}
},
)
}
......@@ -50,7 +50,7 @@ message ClusterRoleBinding {
// RoleRef can only reference a ClusterRole in the global namespace.
// If the RoleRef cannot be resolved, the Authorizer must return an error.
optional k8s.io.kubernetes.pkg.api.v1.ObjectReference roleRef = 3;
optional RoleRef roleRef = 3;
}
// ClusterRoleBindingList is a collection of ClusterRoleBindings
......@@ -119,7 +119,7 @@ message RoleBinding {
// RoleRef can reference a Role in the current namespace or a ClusterRole in the global namespace.
// If the RoleRef cannot be resolved, the Authorizer must return an error.
optional k8s.io.kubernetes.pkg.api.v1.ObjectReference roleRef = 3;
optional RoleRef roleRef = 3;
}
// RoleBindingList is a collection of RoleBindings
......@@ -140,6 +140,18 @@ message RoleList {
repeated Role items = 2;
}
// RoleRef contains information that points to the role being used
message RoleRef {
// APIGroup is the group for the resource being referenced
optional string apiGroup = 1;
// Kind is the type of resource being referenced
optional string kind = 2;
// Name is the name of resource being referenced
optional string name = 3;
}
// Subject contains a reference to the object or user identities a role binding applies to. This can either hold a direct API object reference,
// or a value for non-objects such as user and group names.
message Subject {
......
......@@ -19,16 +19,17 @@ package v1alpha1
import (
"k8s.io/kubernetes/pkg/api/unversioned"
"k8s.io/kubernetes/pkg/api/v1"
"k8s.io/kubernetes/pkg/apis/rbac"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/watch/versioned"
)
const GroupName = "rbac.authorization.k8s.io"
// SchemeGroupVersion is group version used to register these objects
var SchemeGroupVersion = unversioned.GroupVersion{Group: rbac.GroupName, Version: "v1alpha1"}
var SchemeGroupVersion = unversioned.GroupVersion{Group: GroupName, Version: "v1alpha1"}
var (
SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes)
SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes, addDefaultingFuncs)
AddToScheme = SchemeBuilder.AddToScheme
)
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -66,6 +66,16 @@ type Subject struct {
Namespace string `json:"namespace,omitempty" protobuf:"bytes,4,opt,name=namespace"`
}
// RoleRef contains information that points to the role being used
type RoleRef struct {
// APIGroup is the group for the resource being referenced
APIGroup string `json:"apiGroup" protobuf:"bytes,1,opt,name=apiGroup"`
// Kind is the type of resource being referenced
Kind string `json:"kind" protobuf:"bytes,2,opt,name=kind"`
// Name is the name of resource being referenced
Name string `json:"name" protobuf:"bytes,3,opt,name=name"`
}
// +genclient=true
// Role is a namespaced, logical grouping of PolicyRules that can be referenced as a unit by a RoleBinding.
......@@ -93,7 +103,7 @@ type RoleBinding struct {
// RoleRef can reference a Role in the current namespace or a ClusterRole in the global namespace.
// If the RoleRef cannot be resolved, the Authorizer must return an error.
RoleRef v1.ObjectReference `json:"roleRef" protobuf:"bytes,3,opt,name=roleRef"`
RoleRef RoleRef `json:"roleRef" protobuf:"bytes,3,opt,name=roleRef"`
}
// RoleBindingList is a collection of RoleBindings
......@@ -144,7 +154,7 @@ type ClusterRoleBinding struct {
// RoleRef can only reference a ClusterRole in the global namespace.
// If the RoleRef cannot be resolved, the Authorizer must return an error.
RoleRef v1.ObjectReference `json:"roleRef" protobuf:"bytes,3,opt,name=roleRef"`
RoleRef RoleRef `json:"roleRef" protobuf:"bytes,3,opt,name=roleRef"`
}
// ClusterRoleBindingList is a collection of ClusterRoleBindings
......
......@@ -123,6 +123,17 @@ func (RoleList) SwaggerDoc() map[string]string {
return map_RoleList
}
var map_RoleRef = map[string]string{
"": "RoleRef contains information that points to the role being used",
"apiGroup": "APIGroup is the group for the resource being referenced",
"kind": "Kind is the type of resource being referenced",
"name": "Name is the name of resource being referenced",
}
func (RoleRef) SwaggerDoc() map[string]string {
return map_RoleRef
}
var map_Subject = map[string]string{
"": "Subject contains a reference to the object or user identities a role binding applies to. This can either hold a direct API object reference, or a value for non-objects such as user and group names.",
"kind": "Kind of object being referenced. Values defined by this API group are \"User\", \"Group\", and \"ServiceAccount\". If the Authorizer does not recognized the kind value, the Authorizer should report an error.",
......
......@@ -53,6 +53,8 @@ func RegisterConversions(scheme *runtime.Scheme) error {
Convert_rbac_RoleBindingList_To_v1alpha1_RoleBindingList,
Convert_v1alpha1_RoleList_To_rbac_RoleList,
Convert_rbac_RoleList_To_v1alpha1_RoleList,
Convert_v1alpha1_RoleRef_To_rbac_RoleRef,
Convert_rbac_RoleRef_To_v1alpha1_RoleRef,
Convert_v1alpha1_Subject_To_rbac_Subject,
Convert_rbac_Subject_To_v1alpha1_Subject,
)
......@@ -129,8 +131,7 @@ func autoConvert_v1alpha1_ClusterRoleBinding_To_rbac_ClusterRoleBinding(in *Clus
} else {
out.Subjects = nil
}
// TODO: Inefficient conversion - can we improve it?
if err := s.Convert(&in.RoleRef, &out.RoleRef, 0); err != nil {
if err := Convert_v1alpha1_RoleRef_To_rbac_RoleRef(&in.RoleRef, &out.RoleRef, s); err != nil {
return err
}
return nil
......@@ -159,8 +160,7 @@ func autoConvert_rbac_ClusterRoleBinding_To_v1alpha1_ClusterRoleBinding(in *rbac
} else {
out.Subjects = nil
}
// TODO: Inefficient conversion - can we improve it?
if err := s.Convert(&in.RoleRef, &out.RoleRef, 0); err != nil {
if err := Convert_rbac_RoleRef_To_v1alpha1_RoleRef(&in.RoleRef, &out.RoleRef, s); err != nil {
return err
}
return nil
......@@ -373,8 +373,7 @@ func autoConvert_v1alpha1_RoleBinding_To_rbac_RoleBinding(in *RoleBinding, out *
} else {
out.Subjects = nil
}
// TODO: Inefficient conversion - can we improve it?
if err := s.Convert(&in.RoleRef, &out.RoleRef, 0); err != nil {
if err := Convert_v1alpha1_RoleRef_To_rbac_RoleRef(&in.RoleRef, &out.RoleRef, s); err != nil {
return err
}
return nil
......@@ -403,8 +402,7 @@ func autoConvert_rbac_RoleBinding_To_v1alpha1_RoleBinding(in *rbac.RoleBinding,
} else {
out.Subjects = nil
}
// TODO: Inefficient conversion - can we improve it?
if err := s.Convert(&in.RoleRef, &out.RoleRef, 0); err != nil {
if err := Convert_rbac_RoleRef_To_v1alpha1_RoleRef(&in.RoleRef, &out.RoleRef, s); err != nil {
return err
}
return nil
......@@ -514,6 +512,28 @@ func Convert_rbac_RoleList_To_v1alpha1_RoleList(in *rbac.RoleList, out *RoleList
return autoConvert_rbac_RoleList_To_v1alpha1_RoleList(in, out, s)
}
func autoConvert_v1alpha1_RoleRef_To_rbac_RoleRef(in *RoleRef, out *rbac.RoleRef, s conversion.Scope) error {
out.APIGroup = in.APIGroup
out.Kind = in.Kind
out.Name = in.Name
return nil
}
func Convert_v1alpha1_RoleRef_To_rbac_RoleRef(in *RoleRef, out *rbac.RoleRef, s conversion.Scope) error {
return autoConvert_v1alpha1_RoleRef_To_rbac_RoleRef(in, out, s)
}
func autoConvert_rbac_RoleRef_To_v1alpha1_RoleRef(in *rbac.RoleRef, out *RoleRef, s conversion.Scope) error {
out.APIGroup = in.APIGroup
out.Kind = in.Kind
out.Name = in.Name
return nil
}
func Convert_rbac_RoleRef_To_v1alpha1_RoleRef(in *rbac.RoleRef, out *RoleRef, s conversion.Scope) error {
return autoConvert_rbac_RoleRef_To_v1alpha1_RoleRef(in, out, s)
}
func autoConvert_v1alpha1_Subject_To_rbac_Subject(in *Subject, out *rbac.Subject, s conversion.Scope) error {
out.Kind = in.Kind
out.APIVersion = in.APIVersion
......
......@@ -44,6 +44,7 @@ func RegisterDeepCopies(scheme *runtime.Scheme) error {
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1alpha1_RoleBinding, InType: reflect.TypeOf(&RoleBinding{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1alpha1_RoleBindingList, InType: reflect.TypeOf(&RoleBindingList{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1alpha1_RoleList, InType: reflect.TypeOf(&RoleList{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1alpha1_RoleRef, InType: reflect.TypeOf(&RoleRef{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1alpha1_Subject, InType: reflect.TypeOf(&Subject{})},
)
}
......@@ -268,6 +269,17 @@ func DeepCopy_v1alpha1_RoleList(in interface{}, out interface{}, c *conversion.C
}
}
func DeepCopy_v1alpha1_RoleRef(in interface{}, out interface{}, c *conversion.Cloner) error {
{
in := in.(*RoleRef)
out := out.(*RoleRef)
out.APIGroup = in.APIGroup
out.Kind = in.Kind
out.Name = in.Name
return nil
}
}
func DeepCopy_v1alpha1_Subject(in interface{}, out interface{}, c *conversion.Cloner) error {
{
in := in.(*Subject)
......
......@@ -32,7 +32,7 @@ import (
type AuthorizationRuleResolver interface {
// GetRoleReferenceRules attempts to resolve the role reference of a RoleBinding or ClusterRoleBinding. The passed namespace should be the namepsace
// of the role binding, the empty string if a cluster role binding.
GetRoleReferenceRules(ctx api.Context, roleRef api.ObjectReference, namespace string) ([]rbac.PolicyRule, error)
GetRoleReferenceRules(ctx api.Context, roleRef rbac.RoleRef, namespace string) ([]rbac.PolicyRule, error)
// GetEffectivePolicyRules returns the list of rules that apply to a given user in a given namespace and error. If an error is returned, the slice of
// PolicyRules may not be complete, but it contains all retrievable rules. This is done because policy rules are purely additive and policy determinations
......@@ -101,31 +101,24 @@ type ClusterRoleBindingLister interface {
}
// GetRoleReferenceRules attempts resolve the RoleBinding or ClusterRoleBinding.
func (r *DefaultRuleResolver) GetRoleReferenceRules(ctx api.Context, roleRef api.ObjectReference, bindingNamespace string) ([]rbac.PolicyRule, error) {
switch roleRef.Kind {
case "Role":
// Roles can only be referenced by RoleBindings within the same namespace.
if len(bindingNamespace) == 0 {
return nil, fmt.Errorf("cluster role binding references role %q in namespace %q", roleRef.Name, roleRef.Namespace)
} else {
if bindingNamespace != roleRef.Namespace {
return nil, fmt.Errorf("role binding in namespace %q references role %q in namespace %q", bindingNamespace, roleRef.Name, roleRef.Namespace)
}
}
role, err := r.roleGetter.GetRole(api.WithNamespace(ctx, roleRef.Namespace), roleRef.Name)
func (r *DefaultRuleResolver) GetRoleReferenceRules(ctx api.Context, roleRef rbac.RoleRef, bindingNamespace string) ([]rbac.PolicyRule, error) {
switch kind := rbac.RoleRefGroupKind(roleRef); kind {
case rbac.Kind("Role"):
role, err := r.roleGetter.GetRole(api.WithNamespace(ctx, bindingNamespace), roleRef.Name)
if err != nil {
return nil, err
}
return role.Rules, nil
case "ClusterRole":
case rbac.Kind("ClusterRole"):
clusterRole, err := r.clusterRoleGetter.GetClusterRole(api.WithNamespace(ctx, ""), roleRef.Name)
if err != nil {
return nil, err
}
return clusterRole.Rules, nil
default:
return nil, fmt.Errorf("unsupported role reference kind: %q", roleRef.Kind)
return nil, fmt.Errorf("unsupported role reference kind: %q", kind)
}
}
......
......@@ -96,7 +96,7 @@ func TestDefaultRuleResolver(t *testing.T) {
{Kind: rbac.UserKind, Name: "foobar"},
{Kind: rbac.GroupKind, Name: "group1"},
},
RoleRef: api.ObjectReference{Kind: "Role", Namespace: "namespace1", Name: "readthings"},
RoleRef: rbac.RoleRef{APIGroup: rbac.GroupName, Kind: "Role", Name: "readthings"},
},
},
clusterRoleBindings: []rbac.ClusterRoleBinding{
......@@ -105,7 +105,7 @@ func TestDefaultRuleResolver(t *testing.T) {
{Kind: rbac.UserKind, Name: "admin"},
{Kind: rbac.GroupKind, Name: "admin"},
},
RoleRef: api.ObjectReference{Kind: "ClusterRole", Name: "cluster-admin"},
RoleRef: rbac.RoleRef{APIGroup: rbac.GroupName, Kind: "ClusterRole", Name: "cluster-admin"},
},
},
}
......
......@@ -103,11 +103,17 @@ func ValidateRoleBinding(roleBinding *rbac.RoleBinding) field.ErrorList {
allErrs := field.ErrorList{}
allErrs = append(allErrs, validation.ValidateObjectMeta(&roleBinding.ObjectMeta, true, minimalNameRequirements, field.NewPath("metadata"))...)
// roleRef namespace is empty when referring to global policy.
if len(roleBinding.RoleRef.Namespace) > 0 {
for _, msg := range validation.ValidateNamespaceName(roleBinding.RoleRef.Namespace, false) {
allErrs = append(allErrs, field.Invalid(field.NewPath("roleRef", "namespace"), roleBinding.RoleRef.Namespace, msg))
}
// TODO allow multiple API groups. For now, restrict to one, but I can envision other experimental roles in other groups taking
// advantage of the binding infrastructure
if roleBinding.RoleRef.APIGroup != rbac.GroupName {
allErrs = append(allErrs, field.NotSupported(field.NewPath("roleRef", "apiGroup"), roleBinding.RoleRef.APIGroup, []string{rbac.GroupName}))
}
switch roleBinding.RoleRef.Kind {
case "Role", "ClusterRole":
default:
allErrs = append(allErrs, field.NotSupported(field.NewPath("roleRef", "kind"), roleBinding.RoleRef.Kind, []string{"Role", "ClusterRole"}))
}
if len(roleBinding.RoleRef.Name) == 0 {
......@@ -141,11 +147,17 @@ func ValidateClusterRoleBinding(roleBinding *rbac.ClusterRoleBinding) field.Erro
allErrs := field.ErrorList{}
allErrs = append(allErrs, validation.ValidateObjectMeta(&roleBinding.ObjectMeta, false, minimalNameRequirements, field.NewPath("metadata"))...)
// roleRef namespace is empty when referring to global policy.
if len(roleBinding.RoleRef.Namespace) > 0 {
for _, msg := range validation.ValidateNamespaceName(roleBinding.RoleRef.Namespace, false) {
allErrs = append(allErrs, field.Invalid(field.NewPath("roleRef", "namespace"), roleBinding.RoleRef.Namespace, msg))
}
// TODO allow multiple API groups. For now, restrict to one, but I can envision other experimental roles in other groups taking
// advantage of the binding infrastructure
if roleBinding.RoleRef.APIGroup != rbac.GroupName {
allErrs = append(allErrs, field.NotSupported(field.NewPath("roleRef", "apiGroup"), roleBinding.RoleRef.APIGroup, []string{rbac.GroupName}))
}
switch roleBinding.RoleRef.Kind {
case "ClusterRole":
default:
allErrs = append(allErrs, field.NotSupported(field.NewPath("roleRef", "kind"), roleBinding.RoleRef.Kind, []string{"ClusterRole"}))
}
if len(roleBinding.RoleRef.Name) == 0 {
......
......@@ -24,11 +24,126 @@ import (
"k8s.io/kubernetes/pkg/util/validation/field"
)
func TestValidateClusterRoleBinding(t *testing.T) {
errs := ValidateClusterRoleBinding(
&rbac.ClusterRoleBinding{
ObjectMeta: api.ObjectMeta{Name: "master"},
RoleRef: rbac.RoleRef{APIGroup: rbac.GroupName, Kind: "ClusterRole", Name: "valid"},
Subjects: []rbac.Subject{
{Name: "validsaname", Namespace: "foo", Kind: rbac.ServiceAccountKind},
{Name: "valid@username", Kind: rbac.UserKind},
{Name: "valid@groupname", Kind: rbac.GroupKind},
},
},
)
if len(errs) != 0 {
t.Errorf("expected success: %v", errs)
}
errorCases := map[string]struct {
A rbac.ClusterRoleBinding
T field.ErrorType
F string
}{
"bad group": {
A: rbac.ClusterRoleBinding{
ObjectMeta: api.ObjectMeta{Name: "default"},
RoleRef: rbac.RoleRef{APIGroup: "rbac.GroupName", Kind: "ClusterRole", Name: "valid"},
},
T: field.ErrorTypeNotSupported,
F: "roleRef.apiGroup",
},
"bad kind": {
A: rbac.ClusterRoleBinding{
ObjectMeta: api.ObjectMeta{Name: "default"},
RoleRef: rbac.RoleRef{APIGroup: rbac.GroupName, Kind: "Type", Name: "valid"},
},
T: field.ErrorTypeNotSupported,
F: "roleRef.kind",
},
"reference role": {
A: rbac.ClusterRoleBinding{
ObjectMeta: api.ObjectMeta{Name: "default"},
RoleRef: rbac.RoleRef{APIGroup: rbac.GroupName, Kind: "Role", Name: "valid"},
},
T: field.ErrorTypeNotSupported,
F: "roleRef.kind",
},
"zero-length name": {
A: rbac.ClusterRoleBinding{
ObjectMeta: api.ObjectMeta{},
RoleRef: rbac.RoleRef{APIGroup: rbac.GroupName, Kind: "ClusterRole", Name: "valid"},
},
T: field.ErrorTypeRequired,
F: "metadata.name",
},
"bad role": {
A: rbac.ClusterRoleBinding{
ObjectMeta: api.ObjectMeta{Name: "default"},
RoleRef: rbac.RoleRef{APIGroup: rbac.GroupName, Kind: "ClusterRole"},
},
T: field.ErrorTypeRequired,
F: "roleRef.name",
},
"bad subject kind": {
A: rbac.ClusterRoleBinding{
ObjectMeta: api.ObjectMeta{Name: "master"},
RoleRef: rbac.RoleRef{APIGroup: rbac.GroupName, Kind: "ClusterRole", Name: "valid"},
Subjects: []rbac.Subject{{Name: "subject"}},
},
T: field.ErrorTypeNotSupported,
F: "subjects[0].kind",
},
"bad subject name": {
A: rbac.ClusterRoleBinding{
ObjectMeta: api.ObjectMeta{Name: "master"},
RoleRef: rbac.RoleRef{APIGroup: rbac.GroupName, Kind: "ClusterRole", Name: "valid"},
Subjects: []rbac.Subject{{Namespace: "foo", Name: "subject:bad", Kind: rbac.ServiceAccountKind}},
},
T: field.ErrorTypeInvalid,
F: "subjects[0].name",
},
"missing SA namespace": {
A: rbac.ClusterRoleBinding{
ObjectMeta: api.ObjectMeta{Name: "master"},
RoleRef: rbac.RoleRef{APIGroup: rbac.GroupName, Kind: "ClusterRole", Name: "valid"},
Subjects: []rbac.Subject{{Name: "good", Kind: rbac.ServiceAccountKind}},
},
T: field.ErrorTypeRequired,
F: "subjects[0].namespace",
},
"missing subject name": {
A: rbac.ClusterRoleBinding{
ObjectMeta: api.ObjectMeta{Name: "master"},
RoleRef: rbac.RoleRef{APIGroup: rbac.GroupName, Kind: "ClusterRole", Name: "valid"},
Subjects: []rbac.Subject{{Namespace: "foo", Kind: rbac.ServiceAccountKind}},
},
T: field.ErrorTypeRequired,
F: "subjects[0].name",
},
}
for k, v := range errorCases {
errs := ValidateClusterRoleBinding(&v.A)
if len(errs) == 0 {
t.Errorf("expected failure %s for %v", k, v.A)
continue
}
for i := range errs {
if errs[i].Type != v.T {
t.Errorf("%s: expected errors to have type %s: %v", k, v.T, errs[i])
}
if errs[i].Field != v.F {
t.Errorf("%s: expected errors to have field %s: %v", k, v.F, errs[i])
}
}
}
}
func TestValidateRoleBinding(t *testing.T) {
errs := ValidateRoleBinding(
&rbac.RoleBinding{
ObjectMeta: api.ObjectMeta{Namespace: api.NamespaceDefault, Name: "master"},
RoleRef: api.ObjectReference{Namespace: "master", Name: "valid"},
RoleRef: rbac.RoleRef{APIGroup: rbac.GroupName, Kind: "Role", Name: "valid"},
Subjects: []rbac.Subject{
{Name: "validsaname", Kind: rbac.ServiceAccountKind},
{Name: "valid@username", Kind: rbac.UserKind},
......@@ -45,10 +160,26 @@ func TestValidateRoleBinding(t *testing.T) {
T field.ErrorType
F string
}{
"bad group": {
A: rbac.RoleBinding{
ObjectMeta: api.ObjectMeta{Namespace: api.NamespaceDefault, Name: "default"},
RoleRef: rbac.RoleRef{APIGroup: "rbac.GroupName", Kind: "ClusterRole", Name: "valid"},
},
T: field.ErrorTypeNotSupported,
F: "roleRef.apiGroup",
},
"bad kind": {
A: rbac.RoleBinding{
ObjectMeta: api.ObjectMeta{Namespace: api.NamespaceDefault, Name: "default"},
RoleRef: rbac.RoleRef{APIGroup: rbac.GroupName, Kind: "Type", Name: "valid"},
},
T: field.ErrorTypeNotSupported,
F: "roleRef.kind",
},
"zero-length namespace": {
A: rbac.RoleBinding{
ObjectMeta: api.ObjectMeta{Name: "default"},
RoleRef: api.ObjectReference{Namespace: "master", Name: "valid"},
RoleRef: rbac.RoleRef{APIGroup: rbac.GroupName, Kind: "Role", Name: "valid"},
},
T: field.ErrorTypeRequired,
F: "metadata.namespace",
......@@ -56,23 +187,15 @@ func TestValidateRoleBinding(t *testing.T) {
"zero-length name": {
A: rbac.RoleBinding{
ObjectMeta: api.ObjectMeta{Namespace: api.NamespaceDefault},
RoleRef: api.ObjectReference{Namespace: "master", Name: "valid"},
RoleRef: rbac.RoleRef{APIGroup: rbac.GroupName, Kind: "Role", Name: "valid"},
},
T: field.ErrorTypeRequired,
F: "metadata.name",
},
"invalid ref": {
A: rbac.RoleBinding{
ObjectMeta: api.ObjectMeta{Namespace: api.NamespaceDefault, Name: "name"},
RoleRef: api.ObjectReference{Namespace: "-192083", Name: "valid"},
},
T: field.ErrorTypeInvalid,
F: "roleRef.namespace",
},
"bad role": {
A: rbac.RoleBinding{
ObjectMeta: api.ObjectMeta{Namespace: api.NamespaceDefault, Name: "default"},
RoleRef: api.ObjectReference{Namespace: "default"},
RoleRef: rbac.RoleRef{APIGroup: rbac.GroupName, Kind: "Role"},
},
T: field.ErrorTypeRequired,
F: "roleRef.name",
......@@ -80,7 +203,7 @@ func TestValidateRoleBinding(t *testing.T) {
"bad subject kind": {
A: rbac.RoleBinding{
ObjectMeta: api.ObjectMeta{Namespace: api.NamespaceDefault, Name: "master"},
RoleRef: api.ObjectReference{Namespace: "master", Name: "valid"},
RoleRef: rbac.RoleRef{APIGroup: rbac.GroupName, Kind: "Role", Name: "valid"},
Subjects: []rbac.Subject{{Name: "subject"}},
},
T: field.ErrorTypeNotSupported,
......@@ -89,7 +212,7 @@ func TestValidateRoleBinding(t *testing.T) {
"bad subject name": {
A: rbac.RoleBinding{
ObjectMeta: api.ObjectMeta{Namespace: api.NamespaceDefault, Name: "master"},
RoleRef: api.ObjectReference{Namespace: "master", Name: "valid"},
RoleRef: rbac.RoleRef{APIGroup: rbac.GroupName, Kind: "Role", Name: "valid"},
Subjects: []rbac.Subject{{Name: "subject:bad", Kind: rbac.ServiceAccountKind}},
},
T: field.ErrorTypeInvalid,
......@@ -98,7 +221,7 @@ func TestValidateRoleBinding(t *testing.T) {
"missing subject name": {
A: rbac.RoleBinding{
ObjectMeta: api.ObjectMeta{Namespace: api.NamespaceDefault, Name: "master"},
RoleRef: api.ObjectReference{Namespace: "master", Name: "valid"},
RoleRef: rbac.RoleRef{APIGroup: rbac.GroupName, Kind: "Role", Name: "valid"},
Subjects: []rbac.Subject{{Kind: rbac.ServiceAccountKind}},
},
T: field.ErrorTypeRequired,
......@@ -125,13 +248,13 @@ func TestValidateRoleBinding(t *testing.T) {
func TestValidateRoleBindingUpdate(t *testing.T) {
old := &rbac.RoleBinding{
ObjectMeta: api.ObjectMeta{Namespace: api.NamespaceDefault, Name: "master", ResourceVersion: "1"},
RoleRef: api.ObjectReference{Namespace: "master", Name: "valid"},
RoleRef: rbac.RoleRef{APIGroup: rbac.GroupName, Kind: "Role", Name: "valid"},
}
errs := ValidateRoleBindingUpdate(
&rbac.RoleBinding{
ObjectMeta: api.ObjectMeta{Namespace: api.NamespaceDefault, Name: "master", ResourceVersion: "1"},
RoleRef: api.ObjectReference{Namespace: "master", Name: "valid"},
RoleRef: rbac.RoleRef{APIGroup: rbac.GroupName, Kind: "Role", Name: "valid"},
},
old,
)
......@@ -147,7 +270,7 @@ func TestValidateRoleBindingUpdate(t *testing.T) {
"changedRef": {
A: rbac.RoleBinding{
ObjectMeta: api.ObjectMeta{Namespace: api.NamespaceDefault, Name: "master", ResourceVersion: "1"},
RoleRef: api.ObjectReference{Namespace: "master", Name: "changed"},
RoleRef: rbac.RoleRef{APIGroup: rbac.GroupName, Kind: "Role", Name: "changed"},
},
T: field.ErrorTypeInvalid,
F: "roleRef",
......
......@@ -44,6 +44,7 @@ func RegisterDeepCopies(scheme *runtime.Scheme) error {
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_rbac_RoleBinding, InType: reflect.TypeOf(&RoleBinding{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_rbac_RoleBindingList, InType: reflect.TypeOf(&RoleBindingList{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_rbac_RoleList, InType: reflect.TypeOf(&RoleList{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_rbac_RoleRef, InType: reflect.TypeOf(&RoleRef{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_rbac_Subject, InType: reflect.TypeOf(&Subject{})},
)
}
......@@ -272,6 +273,17 @@ func DeepCopy_rbac_RoleList(in interface{}, out interface{}, c *conversion.Clone
}
}
func DeepCopy_rbac_RoleRef(in interface{}, out interface{}, c *conversion.Cloner) error {
{
in := in.(*RoleRef)
out := out.(*RoleRef)
out.APIGroup = in.APIGroup
out.Kind = in.Kind
out.Name = in.Name
return nil
}
}
func DeepCopy_rbac_Subject(in interface{}, out interface{}, c *conversion.Cloner) error {
{
in := in.(*Subject)
......
......@@ -53,9 +53,10 @@ const (
func newClusterRoleBinding(roleName string, subjects ...string) rbac.ClusterRoleBinding {
r := rbac.ClusterRoleBinding{
ObjectMeta: api.ObjectMeta{},
RoleRef: api.ObjectReference{
Kind: "ClusterRole", // ClusterRoleBindings can only refer to ClusterRole
Name: roleName,
RoleRef: rbac.RoleRef{
APIGroup: rbac.GroupName,
Kind: "ClusterRole", // ClusterRoleBindings can only refer to ClusterRole
Name: roleName,
},
}
......@@ -72,9 +73,9 @@ func newRoleBinding(namespace, roleName string, bindType uint16, subjects ...str
switch bindType {
case bindToRole:
r.RoleRef = api.ObjectReference{Kind: "Role", Namespace: namespace, Name: roleName}
r.RoleRef = rbac.RoleRef{APIGroup: rbac.GroupName, Kind: "Role", Name: roleName}
case bindToClusterRole:
r.RoleRef = api.ObjectReference{Kind: "ClusterRole", Name: roleName}
r.RoleRef = rbac.RoleRef{APIGroup: rbac.GroupName, Kind: "ClusterRole", Name: roleName}
}
r.Subjects = make([]rbac.Subject, len(subjects))
......
......@@ -303,7 +303,7 @@ func TestRBAC(t *testing.T) {
Subjects: []v1alpha1.Subject{
{Kind: "User", Name: "pod-reader"},
},
RoleRef: v1.ObjectReference{Kind: "ClusterRole", Name: "read-pods"},
RoleRef: v1alpha1.RoleRef{Kind: "ClusterRole", Name: "read-pods"},
},
},
},
......@@ -335,14 +335,14 @@ func TestRBAC(t *testing.T) {
{
ObjectMeta: v1.ObjectMeta{Name: "write-jobs"},
Subjects: []v1alpha1.Subject{{Kind: "User", Name: "job-writer"}},
RoleRef: v1.ObjectReference{Kind: "ClusterRole", Name: "write-jobs"},
RoleRef: v1alpha1.RoleRef{Kind: "ClusterRole", Name: "write-jobs"},
},
},
roleBindings: []v1alpha1.RoleBinding{
{
ObjectMeta: v1.ObjectMeta{Name: "write-jobs", Namespace: "job-namespace"},
Subjects: []v1alpha1.Subject{{Kind: "User", Name: "job-writer-namespace"}},
RoleRef: v1.ObjectReference{Kind: "ClusterRole", Name: "write-jobs"},
RoleRef: v1alpha1.RoleRef{Kind: "ClusterRole", Name: "write-jobs"},
},
},
},
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment