From e74efe41a03b105ed63a910789cf5dd3c7c1c792 Mon Sep 17 00:00:00 2001 From: deads2k Date: Mon, 9 Jan 2017 12:24:21 -0500 Subject: [PATCH] add rbac v1beta1 --- .../go2idl/go-to-protobuf/protobuf/cmd.go | 1 + hack/lib/init.sh | 1 + pkg/api/defaulting_test.go | 4 + pkg/apis/rbac/BUILD | 1 + pkg/apis/rbac/install/BUILD | 1 + pkg/apis/rbac/install/install.go | 4 +- pkg/apis/rbac/v1beta1/BUILD | 39 ++++ pkg/apis/rbac/v1beta1/defaults.go | 40 ++++ pkg/apis/rbac/v1beta1/doc.go | 23 ++ pkg/apis/rbac/v1beta1/helpers.go | 148 +++++++++++++ pkg/apis/rbac/v1beta1/register.go | 61 ++++++ pkg/apis/rbac/v1beta1/types.go | 202 ++++++++++++++++++ pkg/master/BUILD | 1 + pkg/master/master.go | 2 + pkg/registry/rbac/rest/storage_rbac.go | 12 +- test/e2e/BUILD | 1 + test/e2e/examples.go | 4 +- test/e2e/framework/BUILD | 3 +- test/e2e/framework/authorizer_util.go | 16 +- test/e2e/ingress.go | 4 +- test/e2e/kubectl.go | 4 +- test/e2e/node_problem_detector.go | 4 +- test/e2e/pre_stop.go | 4 +- test/integration/auth/rbac_test.go | 2 +- 24 files changed, 556 insertions(+), 26 deletions(-) create mode 100644 pkg/apis/rbac/v1beta1/BUILD create mode 100644 pkg/apis/rbac/v1beta1/defaults.go create mode 100644 pkg/apis/rbac/v1beta1/doc.go create mode 100644 pkg/apis/rbac/v1beta1/helpers.go create mode 100644 pkg/apis/rbac/v1beta1/register.go create mode 100644 pkg/apis/rbac/v1beta1/types.go diff --git a/cmd/libs/go2idl/go-to-protobuf/protobuf/cmd.go b/cmd/libs/go2idl/go-to-protobuf/protobuf/cmd.go index c04e8efe30..a4d8576d45 100644 --- a/cmd/libs/go2idl/go-to-protobuf/protobuf/cmd.go +++ b/cmd/libs/go2idl/go-to-protobuf/protobuf/cmd.go @@ -77,6 +77,7 @@ func New() *Generator { `k8s.io/kubernetes/pkg/apis/apps/v1beta1`, `k8s.io/kubernetes/pkg/apis/authentication/v1beta1`, `k8s.io/kubernetes/pkg/apis/rbac/v1alpha1`, + `k8s.io/kubernetes/pkg/apis/rbac/v1beta1`, `k8s.io/kubernetes/federation/apis/federation/v1beta1`, `k8s.io/kubernetes/pkg/apis/certificates/v1alpha1`, `k8s.io/kubernetes/pkg/apis/imagepolicy/v1alpha1`, diff --git a/hack/lib/init.sh b/hack/lib/init.sh index e4b2554566..c945770039 100644 --- a/hack/lib/init.sh +++ b/hack/lib/init.sh @@ -63,6 +63,7 @@ certificates.k8s.io/v1alpha1 \ extensions/v1beta1 \ imagepolicy.k8s.io/v1alpha1 \ policy/v1beta1 \ +rbac.authorization.k8s.io/v1beta1 \ rbac.authorization.k8s.io/v1alpha1 \ storage.k8s.io/v1beta1\ }" diff --git a/pkg/api/defaulting_test.go b/pkg/api/defaulting_test.go index d5e61c01b3..7da9cecf10 100644 --- a/pkg/api/defaulting_test.go +++ b/pkg/api/defaulting_test.go @@ -112,6 +112,10 @@ func TestDefaulting(t *testing.T) { {Group: "rbac.authorization.k8s.io", Version: "v1alpha1", Kind: "ClusterRoleBindingList"}: {}, {Group: "rbac.authorization.k8s.io", Version: "v1alpha1", Kind: "RoleBinding"}: {}, {Group: "rbac.authorization.k8s.io", Version: "v1alpha1", Kind: "RoleBindingList"}: {}, + {Group: "rbac.authorization.k8s.io", Version: "v1beta1", Kind: "ClusterRoleBinding"}: {}, + {Group: "rbac.authorization.k8s.io", Version: "v1beta1", Kind: "ClusterRoleBindingList"}: {}, + {Group: "rbac.authorization.k8s.io", Version: "v1beta1", Kind: "RoleBinding"}: {}, + {Group: "rbac.authorization.k8s.io", Version: "v1beta1", Kind: "RoleBindingList"}: {}, } f := fuzz.New().NilChance(.5).NumElements(1, 1).RandSource(rand.NewSource(1)) diff --git a/pkg/apis/rbac/BUILD b/pkg/apis/rbac/BUILD index ef449cf8ae..fa6563b423 100644 --- a/pkg/apis/rbac/BUILD +++ b/pkg/apis/rbac/BUILD @@ -40,6 +40,7 @@ filegroup( ":package-srcs", "//pkg/apis/rbac/install:all-srcs", "//pkg/apis/rbac/v1alpha1:all-srcs", + "//pkg/apis/rbac/v1beta1:all-srcs", "//pkg/apis/rbac/validation:all-srcs", ], tags = ["automanaged"], diff --git a/pkg/apis/rbac/install/BUILD b/pkg/apis/rbac/install/BUILD index 6846511ced..6d9ef7b087 100644 --- a/pkg/apis/rbac/install/BUILD +++ b/pkg/apis/rbac/install/BUILD @@ -15,6 +15,7 @@ go_library( "//pkg/apimachinery/announced:go_default_library", "//pkg/apis/rbac:go_default_library", "//pkg/apis/rbac/v1alpha1:go_default_library", + "//pkg/apis/rbac/v1beta1:go_default_library", "//vendor:k8s.io/apimachinery/pkg/util/sets", ], ) diff --git a/pkg/apis/rbac/install/install.go b/pkg/apis/rbac/install/install.go index 378fc48eeb..6399866a07 100644 --- a/pkg/apis/rbac/install/install.go +++ b/pkg/apis/rbac/install/install.go @@ -23,18 +23,20 @@ import ( "k8s.io/kubernetes/pkg/apimachinery/announced" "k8s.io/kubernetes/pkg/apis/rbac" "k8s.io/kubernetes/pkg/apis/rbac/v1alpha1" + "k8s.io/kubernetes/pkg/apis/rbac/v1beta1" ) func init() { if err := announced.NewGroupMetaFactory( &announced.GroupMetaFactoryArgs{ GroupName: rbac.GroupName, - VersionPreferenceOrder: []string{v1alpha1.SchemeGroupVersion.Version}, + VersionPreferenceOrder: []string{v1beta1.SchemeGroupVersion.Version, v1alpha1.SchemeGroupVersion.Version}, ImportPrefix: "k8s.io/kubernetes/pkg/apis/rbac", RootScopedKinds: sets.NewString("ClusterRole", "ClusterRoleBinding"), AddInternalObjectsToScheme: rbac.AddToScheme, }, announced.VersionToSchemeFunc{ + v1beta1.SchemeGroupVersion.Version: v1beta1.AddToScheme, v1alpha1.SchemeGroupVersion.Version: v1alpha1.AddToScheme, }, ).Announce().RegisterAndEnable(); err != nil { diff --git a/pkg/apis/rbac/v1beta1/BUILD b/pkg/apis/rbac/v1beta1/BUILD new file mode 100644 index 0000000000..8fcb73441d --- /dev/null +++ b/pkg/apis/rbac/v1beta1/BUILD @@ -0,0 +1,39 @@ +package(default_visibility = ["//visibility:public"]) + +licenses(["notice"]) + +load( + "@io_bazel_rules_go//go:def.bzl", + "go_library", +) + +go_library( + name = "go_default_library", + srcs = [ + "defaults.go", + "doc.go", + "helpers.go", + "register.go", + "types.go", + ], + tags = ["automanaged"], + deps = [ + "//pkg/api/v1:go_default_library", + "//pkg/apis/meta/v1:go_default_library", + "//pkg/runtime:go_default_library", + "//pkg/runtime/schema:go_default_library", + ], +) + +filegroup( + name = "package-srcs", + srcs = glob(["**"]), + tags = ["automanaged"], + visibility = ["//visibility:private"], +) + +filegroup( + name = "all-srcs", + srcs = [":package-srcs"], + tags = ["automanaged"], +) diff --git a/pkg/apis/rbac/v1beta1/defaults.go b/pkg/apis/rbac/v1beta1/defaults.go new file mode 100644 index 0000000000..76638eefc9 --- /dev/null +++ b/pkg/apis/rbac/v1beta1/defaults.go @@ -0,0 +1,40 @@ +/* +Copyright 2017 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 v1beta1 + +import ( + "k8s.io/apimachinery/pkg/runtime" +) + +func addDefaultingFuncs(scheme *runtime.Scheme) error { + RegisterDefaults(scheme) + return scheme.AddDefaultingFuncs( + SetDefaults_ClusterRoleBinding, + SetDefaults_RoleBinding, + ) +} + +func SetDefaults_ClusterRoleBinding(obj *ClusterRoleBinding) { + if len(obj.RoleRef.APIGroup) == 0 { + obj.RoleRef.APIGroup = GroupName + } +} +func SetDefaults_RoleBinding(obj *RoleBinding) { + if len(obj.RoleRef.APIGroup) == 0 { + obj.RoleRef.APIGroup = GroupName + } +} diff --git a/pkg/apis/rbac/v1beta1/doc.go b/pkg/apis/rbac/v1beta1/doc.go new file mode 100644 index 0000000000..3339c25693 --- /dev/null +++ b/pkg/apis/rbac/v1beta1/doc.go @@ -0,0 +1,23 @@ +/* +Copyright 2017 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. +*/ + +// +k8s:deepcopy-gen=package,register +// +k8s:conversion-gen=k8s.io/kubernetes/pkg/apis/rbac +// +k8s:openapi-gen=true +// +k8s:defaulter-gen=TypeMeta + +// +groupName=rbac.authorization.k8s.io +package v1beta1 // import "k8s.io/kubernetes/pkg/apis/rbac/v1beta1" diff --git a/pkg/apis/rbac/v1beta1/helpers.go b/pkg/apis/rbac/v1beta1/helpers.go new file mode 100644 index 0000000000..b769df150c --- /dev/null +++ b/pkg/apis/rbac/v1beta1/helpers.go @@ -0,0 +1,148 @@ +/* +Copyright 2017 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 v1beta1 + +import ( + "fmt" + + "k8s.io/kubernetes/pkg/api/v1" +) + +// +k8s:deepcopy-gen=false +// PolicyRuleBuilder let's us attach methods. A no-no for API types. +// We use it to construct rules in code. It's more compact than trying to write them +// out in a literal and allows us to perform some basic checking during construction +type PolicyRuleBuilder struct { + PolicyRule PolicyRule `protobuf:"bytes,1,opt,name=policyRule"` +} + +func NewRule(verbs ...string) *PolicyRuleBuilder { + return &PolicyRuleBuilder{ + PolicyRule: PolicyRule{Verbs: verbs}, + } +} + +func (r *PolicyRuleBuilder) Groups(groups ...string) *PolicyRuleBuilder { + r.PolicyRule.APIGroups = append(r.PolicyRule.APIGroups, groups...) + return r +} + +func (r *PolicyRuleBuilder) Resources(resources ...string) *PolicyRuleBuilder { + r.PolicyRule.Resources = append(r.PolicyRule.Resources, resources...) + return r +} + +func (r *PolicyRuleBuilder) Names(names ...string) *PolicyRuleBuilder { + r.PolicyRule.ResourceNames = append(r.PolicyRule.ResourceNames, names...) + return r +} + +func (r *PolicyRuleBuilder) URLs(urls ...string) *PolicyRuleBuilder { + r.PolicyRule.NonResourceURLs = append(r.PolicyRule.NonResourceURLs, urls...) + return r +} + +func (r *PolicyRuleBuilder) RuleOrDie() PolicyRule { + ret, err := r.Rule() + if err != nil { + panic(err) + } + return ret +} + +func (r *PolicyRuleBuilder) Rule() (PolicyRule, error) { + if len(r.PolicyRule.Verbs) == 0 { + return PolicyRule{}, fmt.Errorf("verbs are required: %#v", r.PolicyRule) + } + + switch { + case len(r.PolicyRule.NonResourceURLs) > 0: + if len(r.PolicyRule.APIGroups) != 0 || len(r.PolicyRule.Resources) != 0 || len(r.PolicyRule.ResourceNames) != 0 { + return PolicyRule{}, fmt.Errorf("non-resource rule may not have apiGroups, resources, or resourceNames: %#v", r.PolicyRule) + } + case len(r.PolicyRule.Resources) > 0: + if len(r.PolicyRule.NonResourceURLs) != 0 { + return PolicyRule{}, fmt.Errorf("resource rule may not have nonResourceURLs: %#v", r.PolicyRule) + } + if len(r.PolicyRule.APIGroups) == 0 { + // this a common bug + return PolicyRule{}, fmt.Errorf("resource rule must have apiGroups: %#v", r.PolicyRule) + } + default: + return PolicyRule{}, fmt.Errorf("a rule must have either nonResourceURLs or resources: %#v", r.PolicyRule) + } + + return r.PolicyRule, nil +} + +// +k8s:deepcopy-gen=false +// ClusterRoleBindingBuilder let's us attach methods. A no-no for API types. +// We use it to construct bindings in code. It's more compact than trying to write them +// out in a literal. +type ClusterRoleBindingBuilder struct { + ClusterRoleBinding ClusterRoleBinding `protobuf:"bytes,1,opt,name=clusterRoleBinding"` +} + +func NewClusterBinding(clusterRoleName string) *ClusterRoleBindingBuilder { + return &ClusterRoleBindingBuilder{ + ClusterRoleBinding: ClusterRoleBinding{ + ObjectMeta: v1.ObjectMeta{Name: clusterRoleName}, + RoleRef: RoleRef{ + APIGroup: GroupName, + Kind: "ClusterRole", + Name: clusterRoleName, + }, + }, + } +} + +func (r *ClusterRoleBindingBuilder) Groups(groups ...string) *ClusterRoleBindingBuilder { + for _, group := range groups { + r.ClusterRoleBinding.Subjects = append(r.ClusterRoleBinding.Subjects, Subject{Kind: GroupKind, Name: group}) + } + return r +} + +func (r *ClusterRoleBindingBuilder) Users(users ...string) *ClusterRoleBindingBuilder { + for _, user := range users { + r.ClusterRoleBinding.Subjects = append(r.ClusterRoleBinding.Subjects, Subject{Kind: UserKind, Name: user}) + } + return r +} + +func (r *ClusterRoleBindingBuilder) SAs(namespace string, serviceAccountNames ...string) *ClusterRoleBindingBuilder { + for _, saName := range serviceAccountNames { + r.ClusterRoleBinding.Subjects = append(r.ClusterRoleBinding.Subjects, Subject{Kind: ServiceAccountKind, Namespace: namespace, Name: saName}) + } + return r +} + +func (r *ClusterRoleBindingBuilder) BindingOrDie() ClusterRoleBinding { + ret, err := r.Binding() + if err != nil { + panic(err) + } + return ret +} + +func (r *ClusterRoleBindingBuilder) Binding() (ClusterRoleBinding, error) { + if len(r.ClusterRoleBinding.Subjects) == 0 { + return ClusterRoleBinding{}, fmt.Errorf("subjects are required: %#v", r.ClusterRoleBinding) + } + + return r.ClusterRoleBinding, nil +} diff --git a/pkg/apis/rbac/v1beta1/register.go b/pkg/apis/rbac/v1beta1/register.go new file mode 100644 index 0000000000..2009c3de5b --- /dev/null +++ b/pkg/apis/rbac/v1beta1/register.go @@ -0,0 +1,61 @@ +/* +Copyright 2017 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 v1beta1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/kubernetes/pkg/api/v1" +) + +const GroupName = "rbac.authorization.k8s.io" + +// SchemeGroupVersion is group version used to register these objects +var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1beta1"} + +// Resource takes an unqualified resource and returns a Group qualified GroupResource +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} + +var ( + SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes, addDefaultingFuncs) + AddToScheme = SchemeBuilder.AddToScheme +) + +// Adds the list of known types to api.Scheme. +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(SchemeGroupVersion, + &Role{}, + &RoleBinding{}, + &RoleBindingList{}, + &RoleList{}, + + &ClusterRole{}, + &ClusterRoleBinding{}, + &ClusterRoleBindingList{}, + &ClusterRoleList{}, + + &v1.ListOptions{}, + &v1.DeleteOptions{}, + &metav1.ExportOptions{}, + &metav1.GetOptions{}, + ) + metav1.AddToGroupVersion(scheme, SchemeGroupVersion) + return nil +} diff --git a/pkg/apis/rbac/v1beta1/types.go b/pkg/apis/rbac/v1beta1/types.go new file mode 100644 index 0000000000..8d0fd0321a --- /dev/null +++ b/pkg/apis/rbac/v1beta1/types.go @@ -0,0 +1,202 @@ +/* +Copyright 2017 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 v1beta1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// Authorization is calculated against +// 1. evaluation of ClusterRoleBindings - short circuit on match +// 2. evaluation of RoleBindings in the namespace requested - short circuit on match +// 3. deny by default + +const ( + APIGroupAll = "*" + ResourceAll = "*" + VerbAll = "*" + NonResourceAll = "*" + + GroupKind = "Group" + ServiceAccountKind = "ServiceAccount" + UserKind = "User" +) + +// Authorization is calculated against +// 1. evaluation of ClusterRoleBindings - short circuit on match +// 2. evaluation of RoleBindings in the namespace requested - short circuit on match +// 3. deny by default + +// PolicyRule holds information that describes a policy rule, but does not contain information +// about who the rule applies to or which namespace the rule applies to. +type PolicyRule struct { + // Verbs is a list of Verbs that apply to ALL the ResourceKinds and AttributeRestrictions contained in this rule. VerbAll represents all kinds. + Verbs []string `json:"verbs" protobuf:"bytes,1,rep,name=verbs"` + + // APIGroups is the name of the APIGroup that contains the resources. If multiple API groups are specified, any action requested against one of + // the enumerated resources in any API group will be allowed. + // +optional + APIGroups []string `json:"apiGroups,omitempty" protobuf:"bytes,2,rep,name=apiGroups"` + // Resources is a list of resources this rule applies to. ResourceAll represents all resources. + // +optional + Resources []string `json:"resources,omitempty" protobuf:"bytes,3,rep,name=resources"` + // ResourceNames is an optional white list of names that the rule applies to. An empty set means that everything is allowed. + // +optional + ResourceNames []string `json:"resourceNames,omitempty" protobuf:"bytes,4,rep,name=resourceNames"` + + // NonResourceURLs is a set of partial urls that a user should have access to. *s are allowed, but only as the full, final step in the path + // Since non-resource URLs are not namespaced, this field is only applicable for ClusterRoles referenced from a ClusterRoleBinding. + // Rules can either apply to API resources (such as "pods" or "secrets") or non-resource URL paths (such as "/api"), but not both. + // +optional + NonResourceURLs []string `json:"nonResourceURLs,omitempty" protobuf:"bytes,5,rep,name=nonResourceURLs"` +} + +// 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. +type Subject struct { + // 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. + Kind string `json:"kind" protobuf:"bytes,1,opt,name=kind"` + // APIVersion holds the API group and version of the referenced object. + // +optional + APIVersion string `json:"apiVersion,omitempty" protobuf:"bytes,2,opt.name=apiVersion"` + // Name of the object being referenced. + Name string `json:"name" protobuf:"bytes,3,opt,name=name"` + // Namespace of the referenced object. If the object kind is non-namespace, such as "User" or "Group", and this value is not empty + // the Authorizer should report an error. + // +optional + 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. +type Role struct { + metav1.TypeMeta `json:",inline"` + // Standard object's metadata. + // +optional + metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"` + + // Rules holds all the PolicyRules for this Role + Rules []PolicyRule `json:"rules" protobuf:"bytes,2,rep,name=rules"` +} + +// +genclient=true + +// RoleBinding references a role, but does not contain it. It can reference a Role in the same namespace or a ClusterRole in the global namespace. +// It adds who information via Subjects and namespace information by which namespace it exists in. RoleBindings in a given +// namespace only have effect in that namespace. +type RoleBinding struct { + metav1.TypeMeta `json:",inline"` + // Standard object's metadata. + // +optional + metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"` + + // Subjects holds references to the objects the role applies to. + Subjects []Subject `json:"subjects" protobuf:"bytes,2,rep,name=subjects"` + + // 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 RoleRef `json:"roleRef" protobuf:"bytes,3,opt,name=roleRef"` +} + +// RoleBindingList is a collection of RoleBindings +type RoleBindingList struct { + metav1.TypeMeta `json:",inline"` + // Standard object's metadata. + // +optional + metav1.ListMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"` + + // Items is a list of RoleBindings + Items []RoleBinding `json:"items" protobuf:"bytes,2,rep,name=items"` +} + +// RoleList is a collection of Roles +type RoleList struct { + metav1.TypeMeta `json:",inline"` + // Standard object's metadata. + // +optional + metav1.ListMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"` + + // Items is a list of Roles + Items []Role `json:"items" protobuf:"bytes,2,rep,name=items"` +} + +// +genclient=true +// +nonNamespaced=true + +// ClusterRole is a cluster level, logical grouping of PolicyRules that can be referenced as a unit by a RoleBinding or ClusterRoleBinding. +type ClusterRole struct { + metav1.TypeMeta `json:",inline"` + // Standard object's metadata. + // +optional + metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"` + + // Rules holds all the PolicyRules for this ClusterRole + Rules []PolicyRule `json:"rules" protobuf:"bytes,2,rep,name=rules"` +} + +// +genclient=true +// +nonNamespaced=true + +// ClusterRoleBinding references a ClusterRole, but not contain it. It can reference a ClusterRole in the global namespace, +// and adds who information via Subject. +type ClusterRoleBinding struct { + metav1.TypeMeta `json:",inline"` + // Standard object's metadata. + // +optional + metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"` + + // Subjects holds references to the objects the role applies to. + Subjects []Subject `json:"subjects" protobuf:"bytes,2,rep,name=subjects"` + + // RoleRef can only reference a ClusterRole in the global namespace. + // If the RoleRef cannot be resolved, the Authorizer must return an error. + RoleRef RoleRef `json:"roleRef" protobuf:"bytes,3,opt,name=roleRef"` +} + +// ClusterRoleBindingList is a collection of ClusterRoleBindings +type ClusterRoleBindingList struct { + metav1.TypeMeta `json:",inline"` + // Standard object's metadata. + // +optional + metav1.ListMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"` + + // Items is a list of ClusterRoleBindings + Items []ClusterRoleBinding `json:"items" protobuf:"bytes,2,rep,name=items"` +} + +// ClusterRoleList is a collection of ClusterRoles +type ClusterRoleList struct { + metav1.TypeMeta `json:",inline"` + // Standard object's metadata. + // +optional + metav1.ListMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"` + + // Items is a list of ClusterRoles + Items []ClusterRole `json:"items" protobuf:"bytes,2,rep,name=items"` +} diff --git a/pkg/master/BUILD b/pkg/master/BUILD index 8d979e54a5..6d1d41d1e0 100644 --- a/pkg/master/BUILD +++ b/pkg/master/BUILD @@ -44,6 +44,7 @@ go_library( "//pkg/apis/policy/v1beta1:go_default_library", "//pkg/apis/rbac/install:go_default_library", "//pkg/apis/rbac/v1alpha1:go_default_library", + "//pkg/apis/rbac/v1beta1:go_default_library", "//pkg/apis/storage/install:go_default_library", "//pkg/apis/storage/v1beta1:go_default_library", "//pkg/client/clientset_generated/clientset/typed/core/v1:go_default_library", diff --git a/pkg/master/master.go b/pkg/master/master.go index fb93d2cee5..90e3cb86af 100644 --- a/pkg/master/master.go +++ b/pkg/master/master.go @@ -39,6 +39,7 @@ import ( extensionsapiv1beta1 "k8s.io/kubernetes/pkg/apis/extensions/v1beta1" policyapiv1beta1 "k8s.io/kubernetes/pkg/apis/policy/v1beta1" rbacapi "k8s.io/kubernetes/pkg/apis/rbac/v1alpha1" + rbacv1beta1 "k8s.io/kubernetes/pkg/apis/rbac/v1beta1" storageapiv1beta1 "k8s.io/kubernetes/pkg/apis/storage/v1beta1" corev1client "k8s.io/kubernetes/pkg/client/clientset_generated/clientset/typed/core/v1" coreclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/core/internalversion" @@ -393,6 +394,7 @@ func DefaultAPIResourceConfigSource() *genericapiserver.ResourceConfig { autoscalingapiv1.SchemeGroupVersion, appsapi.SchemeGroupVersion, policyapiv1beta1.SchemeGroupVersion, + rbacv1beta1.SchemeGroupVersion, rbacapi.SchemeGroupVersion, storageapiv1beta1.SchemeGroupVersion, certificatesapiv1alpha1.SchemeGroupVersion, diff --git a/pkg/registry/rbac/rest/storage_rbac.go b/pkg/registry/rbac/rest/storage_rbac.go index 5cfc90aab2..3ca1dec78e 100644 --- a/pkg/registry/rbac/rest/storage_rbac.go +++ b/pkg/registry/rbac/rest/storage_rbac.go @@ -23,12 +23,14 @@ import ( "github.com/golang/glog" + "k8s.io/apimachinery/pkg/runtime/schema" utilruntime "k8s.io/apimachinery/pkg/util/runtime" "k8s.io/apimachinery/pkg/util/wait" "k8s.io/apiserver/pkg/authorization/authorizer" "k8s.io/kubernetes/pkg/api" "k8s.io/kubernetes/pkg/apis/rbac" rbacapiv1alpha1 "k8s.io/kubernetes/pkg/apis/rbac/v1alpha1" + rbacapiv1beta1 "k8s.io/kubernetes/pkg/apis/rbac/v1beta1" rbacclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/rbac/internalversion" "k8s.io/kubernetes/pkg/genericapiserver" "k8s.io/kubernetes/pkg/genericapiserver/api/rest" @@ -59,16 +61,18 @@ func (p RESTStorageProvider) NewRESTStorage(apiResourceConfigSource genericapise apiGroupInfo := genericapiserver.NewDefaultAPIGroupInfo(rbac.GroupName) if apiResourceConfigSource.AnyResourcesForVersionEnabled(rbacapiv1alpha1.SchemeGroupVersion) { - apiGroupInfo.VersionedResourcesStorageMap[rbacapiv1alpha1.SchemeGroupVersion.Version] = p.v1alpha1Storage(apiResourceConfigSource, restOptionsGetter) + apiGroupInfo.VersionedResourcesStorageMap[rbacapiv1alpha1.SchemeGroupVersion.Version] = p.storage(rbacapiv1alpha1.SchemeGroupVersion, apiResourceConfigSource, restOptionsGetter) apiGroupInfo.GroupMeta.GroupVersion = rbacapiv1alpha1.SchemeGroupVersion } + if apiResourceConfigSource.AnyResourcesForVersionEnabled(rbacapiv1beta1.SchemeGroupVersion) { + apiGroupInfo.VersionedResourcesStorageMap[rbacapiv1beta1.SchemeGroupVersion.Version] = p.storage(rbacapiv1beta1.SchemeGroupVersion, apiResourceConfigSource, restOptionsGetter) + apiGroupInfo.GroupMeta.GroupVersion = rbacapiv1beta1.SchemeGroupVersion + } return apiGroupInfo, true } -func (p RESTStorageProvider) v1alpha1Storage(apiResourceConfigSource genericapiserver.APIResourceConfigSource, restOptionsGetter generic.RESTOptionsGetter) map[string]rest.Storage { - version := rbacapiv1alpha1.SchemeGroupVersion - +func (p RESTStorageProvider) storage(version schema.GroupVersion, apiResourceConfigSource genericapiserver.APIResourceConfigSource, restOptionsGetter generic.RESTOptionsGetter) map[string]rest.Storage { once := new(sync.Once) var ( authorizationRuleResolver rbacregistryvalidation.AuthorizationRuleResolver diff --git a/test/e2e/BUILD b/test/e2e/BUILD index 6dfbc020a3..3f53f39794 100644 --- a/test/e2e/BUILD +++ b/test/e2e/BUILD @@ -126,6 +126,7 @@ go_library( "//pkg/apis/extensions:go_default_library", "//pkg/apis/extensions/v1beta1:go_default_library", "//pkg/apis/rbac/v1alpha1:go_default_library", + "//pkg/apis/rbac/v1beta1:go_default_library", "//pkg/apis/storage/util:go_default_library", "//pkg/apis/storage/v1beta1:go_default_library", "//pkg/apis/storage/v1beta1/util:go_default_library", diff --git a/test/e2e/examples.go b/test/e2e/examples.go index d7ef5e2923..36de2ab84e 100644 --- a/test/e2e/examples.go +++ b/test/e2e/examples.go @@ -33,7 +33,7 @@ import ( "k8s.io/apimachinery/pkg/util/wait" "k8s.io/apiserver/pkg/authentication/serviceaccount" "k8s.io/kubernetes/pkg/api/v1" - rbacv1alpha1 "k8s.io/kubernetes/pkg/apis/rbac/v1alpha1" + rbacv1beta1 "k8s.io/kubernetes/pkg/apis/rbac/v1beta1" "k8s.io/kubernetes/pkg/client/clientset_generated/clientset" "k8s.io/kubernetes/test/e2e/framework" "k8s.io/kubernetes/test/e2e/generated" @@ -72,7 +72,7 @@ var _ = framework.KubeDescribe("[Feature:Example]", func() { // this test wants powerful permissions. Since the namespace names are unique, we can leave this // lying around so we don't have to race any caches framework.BindClusterRoleInNamespace(c.Rbac(), "edit", f.Namespace.Name, - rbacv1alpha1.Subject{Kind: rbacv1alpha1.ServiceAccountKind, Namespace: f.Namespace.Name, Name: "default"}) + rbacv1beta1.Subject{Kind: rbacv1beta1.ServiceAccountKind, Namespace: f.Namespace.Name, Name: "default"}) err := framework.WaitForAuthorizationUpdate(c.Authorization(), serviceaccount.MakeUsername(f.Namespace.Name, "default"), diff --git a/test/e2e/framework/BUILD b/test/e2e/framework/BUILD index 1affc515a8..908a36f911 100644 --- a/test/e2e/framework/BUILD +++ b/test/e2e/framework/BUILD @@ -45,11 +45,10 @@ go_library( "//pkg/apis/componentconfig:go_default_library", "//pkg/apis/extensions:go_default_library", "//pkg/apis/extensions/v1beta1:go_default_library", - "//pkg/apis/rbac/v1alpha1:go_default_library", + "//pkg/apis/rbac/v1beta1:go_default_library", "//pkg/client/clientset_generated/clientset:go_default_library", "//pkg/client/clientset_generated/clientset/typed/authorization/v1beta1:go_default_library", "//pkg/client/clientset_generated/clientset/typed/core/v1:go_default_library", - "//pkg/client/clientset_generated/clientset/typed/rbac/v1alpha1:go_default_library", "//pkg/client/clientset_generated/internalclientset:go_default_library", "//pkg/client/conditions:go_default_library", "//pkg/client/restclient:go_default_library", diff --git a/test/e2e/framework/authorizer_util.go b/test/e2e/framework/authorizer_util.go index eda203f8f6..2d348ece4e 100644 --- a/test/e2e/framework/authorizer_util.go +++ b/test/e2e/framework/authorizer_util.go @@ -25,9 +25,9 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/util/wait" authorizationv1beta1 "k8s.io/kubernetes/pkg/apis/authorization/v1beta1" - rbacv1alpha1 "k8s.io/kubernetes/pkg/apis/rbac/v1alpha1" + rbacv1beta1 "k8s.io/kubernetes/pkg/apis/rbac/v1beta1" v1beta1authorization "k8s.io/kubernetes/pkg/client/clientset_generated/clientset/typed/authorization/v1beta1" - v1alpha1rbac "k8s.io/kubernetes/pkg/client/clientset_generated/clientset/typed/rbac/v1alpha1" + v1beta1rbac "k8s.io/kubernetes/pkg/client/clientset_generated/clientset/typed/rbac/v1beta1" ) const ( @@ -70,13 +70,13 @@ func WaitForAuthorizationUpdate(c v1beta1authorization.SubjectAccessReviewsGette } // BindClusterRole binds the cluster role at the cluster scope -func BindClusterRole(c v1alpha1rbac.ClusterRoleBindingsGetter, clusterRole, ns string, subjects ...rbacv1alpha1.Subject) { +func BindClusterRole(c v1beta1rbac.ClusterRoleBindingsGetter, clusterRole, ns string, subjects ...rbacv1beta1.Subject) { // Since the namespace names are unique, we can leave this lying around so we don't have to race any caches - _, err := c.ClusterRoleBindings().Create(&rbacv1alpha1.ClusterRoleBinding{ + _, err := c.ClusterRoleBindings().Create(&rbacv1beta1.ClusterRoleBinding{ ObjectMeta: metav1.ObjectMeta{ Name: ns + "--" + clusterRole, }, - RoleRef: rbacv1alpha1.RoleRef{ + RoleRef: rbacv1beta1.RoleRef{ APIGroup: "rbac.authorization.k8s.io", Kind: "ClusterRole", Name: clusterRole, @@ -91,13 +91,13 @@ func BindClusterRole(c v1alpha1rbac.ClusterRoleBindingsGetter, clusterRole, ns s } // BindClusterRoleInNamespace binds the cluster role at the namespace scope -func BindClusterRoleInNamespace(c v1alpha1rbac.RoleBindingsGetter, clusterRole, ns string, subjects ...rbacv1alpha1.Subject) { +func BindClusterRoleInNamespace(c v1beta1rbac.RoleBindingsGetter, clusterRole, ns string, subjects ...rbacv1beta1.Subject) { // Since the namespace names are unique, we can leave this lying around so we don't have to race any caches - _, err := c.RoleBindings(ns).Create(&rbacv1alpha1.RoleBinding{ + _, err := c.RoleBindings(ns).Create(&rbacv1beta1.RoleBinding{ ObjectMeta: metav1.ObjectMeta{ Name: ns + "--" + clusterRole, }, - RoleRef: rbacv1alpha1.RoleRef{ + RoleRef: rbacv1beta1.RoleRef{ APIGroup: "rbac.authorization.k8s.io", Kind: "ClusterRole", Name: clusterRole, diff --git a/test/e2e/ingress.go b/test/e2e/ingress.go index 1e16de204c..c379d75c90 100644 --- a/test/e2e/ingress.go +++ b/test/e2e/ingress.go @@ -23,7 +23,7 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apiserver/pkg/authentication/serviceaccount" - rbacv1alpha1 "k8s.io/kubernetes/pkg/apis/rbac/v1alpha1" + rbacv1beta1 "k8s.io/kubernetes/pkg/apis/rbac/v1beta1" "k8s.io/kubernetes/test/e2e/framework" . "github.com/onsi/ginkgo" @@ -69,7 +69,7 @@ var _ = framework.KubeDescribe("Loadbalancing: L7", func() { // this test wants powerful permissions. Since the namespace names are unique, we can leave this // lying around so we don't have to race any caches framework.BindClusterRole(jig.client.Rbac(), "cluster-admin", f.Namespace.Name, - rbacv1alpha1.Subject{Kind: rbacv1alpha1.ServiceAccountKind, Namespace: f.Namespace.Name, Name: "default"}) + rbacv1beta1.Subject{Kind: rbacv1beta1.ServiceAccountKind, Namespace: f.Namespace.Name, Name: "default"}) err := framework.WaitForAuthorizationUpdate(jig.client.Authorization(), serviceaccount.MakeUsername(f.Namespace.Name, "default"), diff --git a/test/e2e/kubectl.go b/test/e2e/kubectl.go index 1c59db7bca..858a852104 100644 --- a/test/e2e/kubectl.go +++ b/test/e2e/kubectl.go @@ -52,7 +52,7 @@ import ( "k8s.io/kubernetes/pkg/api/annotations" "k8s.io/kubernetes/pkg/api/resource" "k8s.io/kubernetes/pkg/api/v1" - rbacv1alpha1 "k8s.io/kubernetes/pkg/apis/rbac/v1alpha1" + rbacv1beta1 "k8s.io/kubernetes/pkg/apis/rbac/v1beta1" "k8s.io/kubernetes/pkg/client/clientset_generated/clientset" "k8s.io/kubernetes/pkg/controller" "k8s.io/kubernetes/pkg/kubectl/cmd/util" @@ -581,7 +581,7 @@ var _ = framework.KubeDescribe("Kubectl client", func() { By("adding rbac permissions") // grant the view permission widely to allow inspection of the `invalid` namespace. framework.BindClusterRole(f.ClientSet.Rbac(), "view", f.Namespace.Name, - rbacv1alpha1.Subject{Kind: rbacv1alpha1.ServiceAccountKind, Namespace: f.Namespace.Name, Name: "default"}) + rbacv1beta1.Subject{Kind: rbacv1beta1.ServiceAccountKind, Namespace: f.Namespace.Name, Name: "default"}) err := framework.WaitForAuthorizationUpdate(f.ClientSet.Authorization(), serviceaccount.MakeUsername(f.Namespace.Name, "default"), diff --git a/test/e2e/node_problem_detector.go b/test/e2e/node_problem_detector.go index 838126b7a0..2337ae43e2 100644 --- a/test/e2e/node_problem_detector.go +++ b/test/e2e/node_problem_detector.go @@ -28,7 +28,7 @@ import ( "k8s.io/apimachinery/pkg/types" "k8s.io/apiserver/pkg/authentication/serviceaccount" "k8s.io/kubernetes/pkg/api/v1" - rbacv1alpha1 "k8s.io/kubernetes/pkg/apis/rbac/v1alpha1" + rbacv1beta1 "k8s.io/kubernetes/pkg/apis/rbac/v1beta1" "k8s.io/kubernetes/pkg/client/clientset_generated/clientset" coreclientset "k8s.io/kubernetes/pkg/client/clientset_generated/clientset/typed/core/v1" "k8s.io/kubernetes/pkg/fields" @@ -64,7 +64,7 @@ var _ = framework.KubeDescribe("NodeProblemDetector", func() { // this test wants extra permissions. Since the namespace names are unique, we can leave this // lying around so we don't have to race any caches framework.BindClusterRole(f.ClientSet.Rbac(), "cluster-admin", f.Namespace.Name, - rbacv1alpha1.Subject{Kind: rbacv1alpha1.ServiceAccountKind, Namespace: f.Namespace.Name, Name: "default"}) + rbacv1beta1.Subject{Kind: rbacv1beta1.ServiceAccountKind, Namespace: f.Namespace.Name, Name: "default"}) err := framework.WaitForAuthorizationUpdate(f.ClientSet.Authorization(), serviceaccount.MakeUsername(f.Namespace.Name, "default"), diff --git a/test/e2e/pre_stop.go b/test/e2e/pre_stop.go index b28abee043..cdd7d05ab6 100644 --- a/test/e2e/pre_stop.go +++ b/test/e2e/pre_stop.go @@ -27,7 +27,7 @@ import ( "k8s.io/apimachinery/pkg/util/wait" "k8s.io/apiserver/pkg/authentication/serviceaccount" "k8s.io/kubernetes/pkg/api/v1" - rbacv1alpha1 "k8s.io/kubernetes/pkg/apis/rbac/v1alpha1" + rbacv1beta1 "k8s.io/kubernetes/pkg/apis/rbac/v1beta1" "k8s.io/kubernetes/pkg/client/clientset_generated/clientset" "k8s.io/kubernetes/test/e2e/framework" @@ -181,7 +181,7 @@ var _ = framework.KubeDescribe("PreStop", func() { // this test wants extra permissions. Since the namespace names are unique, we can leave this // lying around so we don't have to race any caches framework.BindClusterRole(f.ClientSet.Rbac(), "cluster-admin", f.Namespace.Name, - rbacv1alpha1.Subject{Kind: rbacv1alpha1.ServiceAccountKind, Namespace: f.Namespace.Name, Name: "default"}) + rbacv1beta1.Subject{Kind: rbacv1beta1.ServiceAccountKind, Namespace: f.Namespace.Name, Name: "default"}) err := framework.WaitForAuthorizationUpdate(f.ClientSet.Authorization(), serviceaccount.MakeUsername(f.Namespace.Name, "default"), diff --git a/test/integration/auth/rbac_test.go b/test/integration/auth/rbac_test.go index 066919b551..c8cf52d7cb 100644 --- a/test/integration/auth/rbac_test.go +++ b/test/integration/auth/rbac_test.go @@ -170,7 +170,7 @@ func (s statusCode) String() string { var ( writeJobsRoleBinding = ` { - "apiVersion": "rbac.authorization.k8s.io/v1alpha1", + "apiVersion": "rbac.authorization.k8s.io/v1beta1", "kind": "RoleBinding", "metadata": { "name": "pi"%s