mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-23 19:56:01 +00:00
Merge pull request #42259 from deads2k/rbac-07-reconcile-binding
Automatic merge from submit-queue Add RBAC roles for bootstrap controllers Supercedes https://github.com/kubernetes/kubernetes/pull/42221 When locking down controllers to individual RBAC roles we need to make sure that the bootstrap controllers have the right permissions. This adds the roles and bindings at the correct namespace scopes for the bootstrap-signer and token-cleaner controllers. @liggitt ptal @jbeda @luxas you got a good way to test this? It must not be covered in normal e2e or we'd've seen the issue before.
This commit is contained in:
commit
01bfbb5fa0
@ -282,6 +282,22 @@ func NewRoleBinding(roleName, namespace string) *RoleBindingBuilder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewRoleBindingForClusterRole(roleName, namespace string) *RoleBindingBuilder {
|
||||||
|
return &RoleBindingBuilder{
|
||||||
|
RoleBinding: RoleBinding{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: roleName,
|
||||||
|
Namespace: namespace,
|
||||||
|
},
|
||||||
|
RoleRef: RoleRef{
|
||||||
|
APIGroup: GroupName,
|
||||||
|
Kind: "ClusterRole",
|
||||||
|
Name: roleName,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Groups adds the specified groups as the subjects of the RoleBinding.
|
// Groups adds the specified groups as the subjects of the RoleBinding.
|
||||||
func (r *RoleBindingBuilder) Groups(groups ...string) *RoleBindingBuilder {
|
func (r *RoleBindingBuilder) Groups(groups ...string) *RoleBindingBuilder {
|
||||||
for _, group := range groups {
|
for _, group := range groups {
|
||||||
|
@ -11,8 +11,8 @@ load(
|
|||||||
go_test(
|
go_test(
|
||||||
name = "go_default_test",
|
name = "go_default_test",
|
||||||
srcs = [
|
srcs = [
|
||||||
"reconcile_clusterrolebindings_test.go",
|
|
||||||
"reconcile_role_test.go",
|
"reconcile_role_test.go",
|
||||||
|
"reconcile_rolebindings_test.go",
|
||||||
],
|
],
|
||||||
library = ":go_default_library",
|
library = ":go_default_library",
|
||||||
tags = ["automanaged"],
|
tags = ["automanaged"],
|
||||||
@ -26,9 +26,12 @@ go_test(
|
|||||||
go_library(
|
go_library(
|
||||||
name = "go_default_library",
|
name = "go_default_library",
|
||||||
srcs = [
|
srcs = [
|
||||||
"reconcile_clusterrolebindings.go",
|
"clusterrole_interfaces.go",
|
||||||
|
"clusterrolebinding_interfaces.go",
|
||||||
"reconcile_role.go",
|
"reconcile_role.go",
|
||||||
|
"reconcile_rolebindings.go",
|
||||||
"role_interfaces.go",
|
"role_interfaces.go",
|
||||||
|
"rolebinding_interfaces.go",
|
||||||
],
|
],
|
||||||
tags = ["automanaged"],
|
tags = ["automanaged"],
|
||||||
deps = [
|
deps = [
|
||||||
@ -38,6 +41,7 @@ go_library(
|
|||||||
"//pkg/registry/rbac/validation:go_default_library",
|
"//pkg/registry/rbac/validation:go_default_library",
|
||||||
"//vendor:k8s.io/apimachinery/pkg/api/errors",
|
"//vendor:k8s.io/apimachinery/pkg/api/errors",
|
||||||
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
|
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
|
||||||
|
"//vendor:k8s.io/apimachinery/pkg/types",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
88
pkg/registry/rbac/reconciliation/clusterrole_interfaces.go
Normal file
88
pkg/registry/rbac/reconciliation/clusterrole_interfaces.go
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
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 reconciliation
|
||||||
|
|
||||||
|
import (
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/kubernetes/pkg/apis/rbac"
|
||||||
|
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/rbac/internalversion"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ClusterRoleRuleOwner struct {
|
||||||
|
ClusterRole *rbac.ClusterRole
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o ClusterRoleRuleOwner) GetNamespace() string {
|
||||||
|
return o.ClusterRole.Namespace
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o ClusterRoleRuleOwner) GetName() string {
|
||||||
|
return o.ClusterRole.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o ClusterRoleRuleOwner) GetLabels() map[string]string {
|
||||||
|
return o.ClusterRole.Labels
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o ClusterRoleRuleOwner) SetLabels(in map[string]string) {
|
||||||
|
o.ClusterRole.Labels = in
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o ClusterRoleRuleOwner) GetAnnotations() map[string]string {
|
||||||
|
return o.ClusterRole.Annotations
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o ClusterRoleRuleOwner) SetAnnotations(in map[string]string) {
|
||||||
|
o.ClusterRole.Annotations = in
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o ClusterRoleRuleOwner) GetRules() []rbac.PolicyRule {
|
||||||
|
return o.ClusterRole.Rules
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o ClusterRoleRuleOwner) SetRules(in []rbac.PolicyRule) {
|
||||||
|
o.ClusterRole.Rules = in
|
||||||
|
}
|
||||||
|
|
||||||
|
type ClusterRoleModifier struct {
|
||||||
|
Client internalversion.ClusterRoleInterface
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c ClusterRoleModifier) Get(namespace, name string) (RuleOwner, error) {
|
||||||
|
ret, err := c.Client.Get(name, metav1.GetOptions{})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return ClusterRoleRuleOwner{ClusterRole: ret}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c ClusterRoleModifier) Create(in RuleOwner) (RuleOwner, error) {
|
||||||
|
ret, err := c.Client.Create(in.(ClusterRoleRuleOwner).ClusterRole)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return ClusterRoleRuleOwner{ClusterRole: ret}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c ClusterRoleModifier) Update(in RuleOwner) (RuleOwner, error) {
|
||||||
|
ret, err := c.Client.Update(in.(ClusterRoleRuleOwner).ClusterRole)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return ClusterRoleRuleOwner{ClusterRole: ret}, err
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,101 @@
|
|||||||
|
/*
|
||||||
|
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 reconciliation
|
||||||
|
|
||||||
|
import (
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/types"
|
||||||
|
"k8s.io/kubernetes/pkg/apis/rbac"
|
||||||
|
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/rbac/internalversion"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ClusterRoleBindingAdapter struct {
|
||||||
|
ClusterRoleBinding *rbac.ClusterRoleBinding
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o ClusterRoleBindingAdapter) GetNamespace() string {
|
||||||
|
return o.ClusterRoleBinding.Namespace
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o ClusterRoleBindingAdapter) GetName() string {
|
||||||
|
return o.ClusterRoleBinding.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o ClusterRoleBindingAdapter) GetUID() types.UID {
|
||||||
|
return o.ClusterRoleBinding.UID
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o ClusterRoleBindingAdapter) GetLabels() map[string]string {
|
||||||
|
return o.ClusterRoleBinding.Labels
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o ClusterRoleBindingAdapter) SetLabels(in map[string]string) {
|
||||||
|
o.ClusterRoleBinding.Labels = in
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o ClusterRoleBindingAdapter) GetAnnotations() map[string]string {
|
||||||
|
return o.ClusterRoleBinding.Annotations
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o ClusterRoleBindingAdapter) SetAnnotations(in map[string]string) {
|
||||||
|
o.ClusterRoleBinding.Annotations = in
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o ClusterRoleBindingAdapter) GetRoleRef() rbac.RoleRef {
|
||||||
|
return o.ClusterRoleBinding.RoleRef
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o ClusterRoleBindingAdapter) GetSubjects() []rbac.Subject {
|
||||||
|
return o.ClusterRoleBinding.Subjects
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o ClusterRoleBindingAdapter) SetSubjects(in []rbac.Subject) {
|
||||||
|
o.ClusterRoleBinding.Subjects = in
|
||||||
|
}
|
||||||
|
|
||||||
|
type ClusterRoleBindingClientAdapter struct {
|
||||||
|
Client internalversion.ClusterRoleBindingInterface
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c ClusterRoleBindingClientAdapter) Get(namespace, name string) (RoleBinding, error) {
|
||||||
|
ret, err := c.Client.Get(name, metav1.GetOptions{})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return ClusterRoleBindingAdapter{ClusterRoleBinding: ret}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c ClusterRoleBindingClientAdapter) Create(in RoleBinding) (RoleBinding, error) {
|
||||||
|
ret, err := c.Client.Create(in.(ClusterRoleBindingAdapter).ClusterRoleBinding)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return ClusterRoleBindingAdapter{ClusterRoleBinding: ret}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c ClusterRoleBindingClientAdapter) Update(in RoleBinding) (RoleBinding, error) {
|
||||||
|
ret, err := c.Client.Update(in.(ClusterRoleBindingAdapter).ClusterRoleBinding)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return ClusterRoleBindingAdapter{ClusterRoleBinding: ret}, err
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c ClusterRoleBindingClientAdapter) Delete(namespace, name string, uid types.UID) error {
|
||||||
|
return c.Client.Delete(name, &metav1.DeleteOptions{Preconditions: &metav1.Preconditions{UID: &uid}})
|
||||||
|
}
|
@ -21,10 +21,8 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/api/errors"
|
"k8s.io/apimachinery/pkg/api/errors"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
"k8s.io/kubernetes/pkg/apis/rbac"
|
"k8s.io/kubernetes/pkg/apis/rbac"
|
||||||
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/rbac/internalversion"
|
|
||||||
"k8s.io/kubernetes/pkg/registry/rbac/validation"
|
"k8s.io/kubernetes/pkg/registry/rbac/validation"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -54,7 +52,7 @@ type RuleOwner interface {
|
|||||||
SetRules([]rbac.PolicyRule)
|
SetRules([]rbac.PolicyRule)
|
||||||
}
|
}
|
||||||
|
|
||||||
type ReconcileClusterRoleOptions struct {
|
type ReconcileRoleOptions struct {
|
||||||
// Role is the expected role that will be reconciled
|
// Role is the expected role that will be reconciled
|
||||||
Role RuleOwner
|
Role RuleOwner
|
||||||
// Confirm indicates writes should be performed. When false, results are returned as a dry-run.
|
// Confirm indicates writes should be performed. When false, results are returned as a dry-run.
|
||||||
@ -85,11 +83,11 @@ type ReconcileClusterRoleResult struct {
|
|||||||
Protected bool
|
Protected bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *ReconcileClusterRoleOptions) Run() (*ReconcileClusterRoleResult, error) {
|
func (o *ReconcileRoleOptions) Run() (*ReconcileClusterRoleResult, error) {
|
||||||
return o.run(0)
|
return o.run(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *ReconcileClusterRoleOptions) run(attempts int) (*ReconcileClusterRoleResult, error) {
|
func (o *ReconcileRoleOptions) run(attempts int) (*ReconcileClusterRoleResult, error) {
|
||||||
// This keeps us from retrying forever if a role keeps appearing and disappearing as we reconcile.
|
// This keeps us from retrying forever if a role keeps appearing and disappearing as we reconcile.
|
||||||
// Conflict errors on update are handled at a higher level.
|
// Conflict errors on update are handled at a higher level.
|
||||||
if attempts > 2 {
|
if attempts > 2 {
|
||||||
@ -215,68 +213,3 @@ func merge(maps ...map[string]string) map[string]string {
|
|||||||
}
|
}
|
||||||
return output
|
return output
|
||||||
}
|
}
|
||||||
|
|
||||||
type ClusterRoleRuleOwner struct {
|
|
||||||
ClusterRole *rbac.ClusterRole
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o ClusterRoleRuleOwner) GetNamespace() string {
|
|
||||||
return o.ClusterRole.Namespace
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o ClusterRoleRuleOwner) GetName() string {
|
|
||||||
return o.ClusterRole.Name
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o ClusterRoleRuleOwner) GetLabels() map[string]string {
|
|
||||||
return o.ClusterRole.Labels
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o ClusterRoleRuleOwner) SetLabels(in map[string]string) {
|
|
||||||
o.ClusterRole.Labels = in
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o ClusterRoleRuleOwner) GetAnnotations() map[string]string {
|
|
||||||
return o.ClusterRole.Annotations
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o ClusterRoleRuleOwner) SetAnnotations(in map[string]string) {
|
|
||||||
o.ClusterRole.Annotations = in
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o ClusterRoleRuleOwner) GetRules() []rbac.PolicyRule {
|
|
||||||
return o.ClusterRole.Rules
|
|
||||||
}
|
|
||||||
|
|
||||||
func (o ClusterRoleRuleOwner) SetRules(in []rbac.PolicyRule) {
|
|
||||||
o.ClusterRole.Rules = in
|
|
||||||
}
|
|
||||||
|
|
||||||
type ClusterRoleModifier struct {
|
|
||||||
Client internalversion.ClusterRoleInterface
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c ClusterRoleModifier) Get(namespace, name string) (RuleOwner, error) {
|
|
||||||
ret, err := c.Client.Get(name, metav1.GetOptions{})
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return ClusterRoleRuleOwner{ClusterRole: ret}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c ClusterRoleModifier) Create(in RuleOwner) (RuleOwner, error) {
|
|
||||||
ret, err := c.Client.Create(in.(ClusterRoleRuleOwner).ClusterRole)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return ClusterRoleRuleOwner{ClusterRole: ret}, err
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c ClusterRoleModifier) Update(in RuleOwner) (RuleOwner, error) {
|
|
||||||
ret, err := c.Client.Create(in.(ClusterRoleRuleOwner).ClusterRole)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return ClusterRoleRuleOwner{ClusterRole: ret}, err
|
|
||||||
|
|
||||||
}
|
|
||||||
|
@ -21,29 +21,48 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
"k8s.io/apimachinery/pkg/api/errors"
|
"k8s.io/apimachinery/pkg/api/errors"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
"k8s.io/apimachinery/pkg/types"
|
||||||
"k8s.io/kubernetes/pkg/api"
|
"k8s.io/kubernetes/pkg/api"
|
||||||
"k8s.io/kubernetes/pkg/apis/rbac"
|
"k8s.io/kubernetes/pkg/apis/rbac"
|
||||||
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/rbac/internalversion"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// ReconcileClusterRoleBindingOptions holds options for running a role binding reconciliation
|
type RoleBindingModifier interface {
|
||||||
type ReconcileClusterRoleBindingOptions struct {
|
Get(namespace, name string) (RoleBinding, error)
|
||||||
|
Delete(namespace, name string, uid types.UID) error
|
||||||
|
Create(RoleBinding) (RoleBinding, error)
|
||||||
|
Update(RoleBinding) (RoleBinding, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type RoleBinding interface {
|
||||||
|
GetNamespace() string
|
||||||
|
GetName() string
|
||||||
|
GetUID() types.UID
|
||||||
|
GetLabels() map[string]string
|
||||||
|
SetLabels(map[string]string)
|
||||||
|
GetAnnotations() map[string]string
|
||||||
|
SetAnnotations(map[string]string)
|
||||||
|
GetRoleRef() rbac.RoleRef
|
||||||
|
GetSubjects() []rbac.Subject
|
||||||
|
SetSubjects([]rbac.Subject)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReconcileRoleBindingOptions holds options for running a role binding reconciliation
|
||||||
|
type ReconcileRoleBindingOptions struct {
|
||||||
// RoleBinding is the expected rolebinding that will be reconciled
|
// RoleBinding is the expected rolebinding that will be reconciled
|
||||||
RoleBinding *rbac.ClusterRoleBinding
|
RoleBinding RoleBinding
|
||||||
// Confirm indicates writes should be performed. When false, results are returned as a dry-run.
|
// Confirm indicates writes should be performed. When false, results are returned as a dry-run.
|
||||||
Confirm bool
|
Confirm bool
|
||||||
// RemoveExtraSubjects indicates reconciliation should remove extra subjects from an existing role binding
|
// RemoveExtraSubjects indicates reconciliation should remove extra subjects from an existing role binding
|
||||||
RemoveExtraSubjects bool
|
RemoveExtraSubjects bool
|
||||||
// Client is used to look up existing rolebindings, and create/update the rolebinding when Confirm=true
|
// Client is used to look up existing rolebindings, and create/update the rolebinding when Confirm=true
|
||||||
Client internalversion.ClusterRoleBindingInterface
|
Client RoleBindingModifier
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReconcileClusterRoleBindingResult holds the result of a reconciliation operation.
|
// ReconcileClusterRoleBindingResult holds the result of a reconciliation operation.
|
||||||
type ReconcileClusterRoleBindingResult struct {
|
type ReconcileClusterRoleBindingResult struct {
|
||||||
// RoleBinding is the reconciled rolebinding from the reconciliation operation.
|
// RoleBinding is the reconciled rolebinding from the reconciliation operation.
|
||||||
// If the reconcile was performed as a dry-run, or the existing rolebinding was protected, the reconciled rolebinding is not persisted.
|
// If the reconcile was performed as a dry-run, or the existing rolebinding was protected, the reconciled rolebinding is not persisted.
|
||||||
RoleBinding *rbac.ClusterRoleBinding
|
RoleBinding RoleBinding
|
||||||
|
|
||||||
// MissingSubjects contains expected subjects that were missing from the currently persisted rolebinding
|
// MissingSubjects contains expected subjects that were missing from the currently persisted rolebinding
|
||||||
MissingSubjects []rbac.Subject
|
MissingSubjects []rbac.Subject
|
||||||
@ -60,11 +79,11 @@ type ReconcileClusterRoleBindingResult struct {
|
|||||||
Protected bool
|
Protected bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *ReconcileClusterRoleBindingOptions) Run() (*ReconcileClusterRoleBindingResult, error) {
|
func (o *ReconcileRoleBindingOptions) Run() (*ReconcileClusterRoleBindingResult, error) {
|
||||||
return o.run(0)
|
return o.run(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *ReconcileClusterRoleBindingOptions) run(attempts int) (*ReconcileClusterRoleBindingResult, error) {
|
func (o *ReconcileRoleBindingOptions) run(attempts int) (*ReconcileClusterRoleBindingResult, error) {
|
||||||
// This keeps us from retrying forever if a rolebinding keeps appearing and disappearing as we reconcile.
|
// This keeps us from retrying forever if a rolebinding keeps appearing and disappearing as we reconcile.
|
||||||
// Conflict errors on update are handled at a higher level.
|
// Conflict errors on update are handled at a higher level.
|
||||||
if attempts > 3 {
|
if attempts > 3 {
|
||||||
@ -73,12 +92,12 @@ func (o *ReconcileClusterRoleBindingOptions) run(attempts int) (*ReconcileCluste
|
|||||||
|
|
||||||
var result *ReconcileClusterRoleBindingResult
|
var result *ReconcileClusterRoleBindingResult
|
||||||
|
|
||||||
existingBinding, err := o.Client.Get(o.RoleBinding.Name, metav1.GetOptions{})
|
existingBinding, err := o.Client.Get(o.RoleBinding.GetNamespace(), o.RoleBinding.GetName())
|
||||||
switch {
|
switch {
|
||||||
case errors.IsNotFound(err):
|
case errors.IsNotFound(err):
|
||||||
result = &ReconcileClusterRoleBindingResult{
|
result = &ReconcileClusterRoleBindingResult{
|
||||||
RoleBinding: o.RoleBinding,
|
RoleBinding: o.RoleBinding,
|
||||||
MissingSubjects: o.RoleBinding.Subjects,
|
MissingSubjects: o.RoleBinding.GetSubjects(),
|
||||||
Operation: ReconcileCreate,
|
Operation: ReconcileCreate,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -104,10 +123,7 @@ func (o *ReconcileClusterRoleBindingOptions) run(attempts int) (*ReconcileCluste
|
|||||||
switch result.Operation {
|
switch result.Operation {
|
||||||
case ReconcileRecreate:
|
case ReconcileRecreate:
|
||||||
// Try deleting
|
// Try deleting
|
||||||
err := o.Client.Delete(
|
err := o.Client.Delete(existingBinding.GetNamespace(), existingBinding.GetName(), existingBinding.GetUID())
|
||||||
existingBinding.Name,
|
|
||||||
&metav1.DeleteOptions{Preconditions: &metav1.Preconditions{UID: &existingBinding.UID}},
|
|
||||||
)
|
|
||||||
switch {
|
switch {
|
||||||
case err == nil, errors.IsNotFound(err):
|
case err == nil, errors.IsNotFound(err):
|
||||||
// object no longer exists, as desired
|
// object no longer exists, as desired
|
||||||
@ -155,13 +171,13 @@ func (o *ReconcileClusterRoleBindingOptions) run(attempts int) (*ReconcileCluste
|
|||||||
|
|
||||||
// computeReconciledRoleBinding returns the rolebinding that must be created and/or updated to make the
|
// computeReconciledRoleBinding returns the rolebinding that must be created and/or updated to make the
|
||||||
// existing rolebinding's subjects, roleref, labels, and annotations match the expected rolebinding
|
// existing rolebinding's subjects, roleref, labels, and annotations match the expected rolebinding
|
||||||
func computeReconciledRoleBinding(existing, expected *rbac.ClusterRoleBinding, removeExtraSubjects bool) (*ReconcileClusterRoleBindingResult, error) {
|
func computeReconciledRoleBinding(existing, expected RoleBinding, removeExtraSubjects bool) (*ReconcileClusterRoleBindingResult, error) {
|
||||||
result := &ReconcileClusterRoleBindingResult{Operation: ReconcileNone}
|
result := &ReconcileClusterRoleBindingResult{Operation: ReconcileNone}
|
||||||
|
|
||||||
result.Protected = (existing.Annotations[rbac.AutoUpdateAnnotationKey] == "false")
|
result.Protected = (existing.GetAnnotations()[rbac.AutoUpdateAnnotationKey] == "false")
|
||||||
|
|
||||||
// Reset the binding completely if the roleRef is different
|
// Reset the binding completely if the roleRef is different
|
||||||
if expected.RoleRef != existing.RoleRef {
|
if expected.GetRoleRef() != existing.GetRoleRef() {
|
||||||
result.RoleBinding = expected
|
result.RoleBinding = expected
|
||||||
result.Operation = ReconcileRecreate
|
result.Operation = ReconcileRecreate
|
||||||
return result, nil
|
return result, nil
|
||||||
@ -172,30 +188,30 @@ func computeReconciledRoleBinding(existing, expected *rbac.ClusterRoleBinding, r
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
result.RoleBinding = changedObj.(*rbac.ClusterRoleBinding)
|
result.RoleBinding = changedObj.(RoleBinding)
|
||||||
|
|
||||||
// Merge expected annotations and labels
|
// Merge expected annotations and labels
|
||||||
result.RoleBinding.Annotations = merge(expected.Annotations, result.RoleBinding.Annotations)
|
result.RoleBinding.SetAnnotations(merge(expected.GetAnnotations(), result.RoleBinding.GetAnnotations()))
|
||||||
if !reflect.DeepEqual(result.RoleBinding.Annotations, existing.Annotations) {
|
if !reflect.DeepEqual(result.RoleBinding.GetAnnotations(), existing.GetAnnotations()) {
|
||||||
result.Operation = ReconcileUpdate
|
result.Operation = ReconcileUpdate
|
||||||
}
|
}
|
||||||
result.RoleBinding.Labels = merge(expected.Labels, result.RoleBinding.Labels)
|
result.RoleBinding.SetLabels(merge(expected.GetLabels(), result.RoleBinding.GetLabels()))
|
||||||
if !reflect.DeepEqual(result.RoleBinding.Labels, existing.Labels) {
|
if !reflect.DeepEqual(result.RoleBinding.GetLabels(), existing.GetLabels()) {
|
||||||
result.Operation = ReconcileUpdate
|
result.Operation = ReconcileUpdate
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute extra and missing subjects
|
// Compute extra and missing subjects
|
||||||
result.MissingSubjects, result.ExtraSubjects = diffSubjectLists(expected.Subjects, existing.Subjects)
|
result.MissingSubjects, result.ExtraSubjects = diffSubjectLists(expected.GetSubjects(), existing.GetSubjects())
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case !removeExtraSubjects && len(result.MissingSubjects) > 0:
|
case !removeExtraSubjects && len(result.MissingSubjects) > 0:
|
||||||
// add missing subjects in the union case
|
// add missing subjects in the union case
|
||||||
result.RoleBinding.Subjects = append(result.RoleBinding.Subjects, result.MissingSubjects...)
|
result.RoleBinding.SetSubjects(append(result.RoleBinding.GetSubjects(), result.MissingSubjects...))
|
||||||
result.Operation = ReconcileUpdate
|
result.Operation = ReconcileUpdate
|
||||||
|
|
||||||
case removeExtraSubjects && (len(result.MissingSubjects) > 0 || len(result.ExtraSubjects) > 0):
|
case removeExtraSubjects && (len(result.MissingSubjects) > 0 || len(result.ExtraSubjects) > 0):
|
||||||
// stomp to expected subjects in the non-union case
|
// stomp to expected subjects in the non-union case
|
||||||
result.RoleBinding.Subjects = expected.Subjects
|
result.RoleBinding.SetSubjects(expected.GetSubjects())
|
||||||
result.Operation = ReconcileUpdate
|
result.Operation = ReconcileUpdate
|
||||||
}
|
}
|
||||||
|
|
@ -161,13 +161,15 @@ func TestComputeUpdate(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for k, tc := range tests {
|
for k, tc := range tests {
|
||||||
result, err := computeReconciledRoleBinding(tc.ActualBinding, tc.ExpectedBinding, tc.RemoveExtraSubjects)
|
actualRoleBinding := ClusterRoleBindingAdapter{ClusterRoleBinding: tc.ActualBinding}
|
||||||
|
expectedRoleBinding := ClusterRoleBindingAdapter{ClusterRoleBinding: tc.ExpectedBinding}
|
||||||
|
result, err := computeReconciledRoleBinding(actualRoleBinding, expectedRoleBinding, tc.RemoveExtraSubjects)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("%s: %v", k, err)
|
t.Errorf("%s: %v", k, err)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
updateNeeded := result.Operation != ReconcileNone
|
updateNeeded := result.Operation != ReconcileNone
|
||||||
updatedBinding := result.RoleBinding
|
updatedBinding := result.RoleBinding.(ClusterRoleBindingAdapter).ClusterRoleBinding
|
||||||
if updateNeeded != tc.ExpectedUpdateNeeded {
|
if updateNeeded != tc.ExpectedUpdateNeeded {
|
||||||
t.Errorf("%s: Expected\n\t%v\ngot\n\t%v (%v)", k, tc.ExpectedUpdateNeeded, updateNeeded, result.Operation)
|
t.Errorf("%s: Expected\n\t%v\ngot\n\t%v (%v)", k, tc.ExpectedUpdateNeeded, updateNeeded, result.Operation)
|
||||||
continue
|
continue
|
@ -79,7 +79,7 @@ func (c RoleModifier) Create(in RuleOwner) (RuleOwner, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c RoleModifier) Update(in RuleOwner) (RuleOwner, error) {
|
func (c RoleModifier) Update(in RuleOwner) (RuleOwner, error) {
|
||||||
ret, err := c.Client.Roles(in.GetNamespace()).Create(in.(RoleRuleOwner).Role)
|
ret, err := c.Client.Roles(in.GetNamespace()).Update(in.(RoleRuleOwner).Role)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
101
pkg/registry/rbac/reconciliation/rolebinding_interfaces.go
Normal file
101
pkg/registry/rbac/reconciliation/rolebinding_interfaces.go
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
/*
|
||||||
|
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 reconciliation
|
||||||
|
|
||||||
|
import (
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/apimachinery/pkg/types"
|
||||||
|
"k8s.io/kubernetes/pkg/apis/rbac"
|
||||||
|
"k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/rbac/internalversion"
|
||||||
|
)
|
||||||
|
|
||||||
|
type RoleBindingAdapter struct {
|
||||||
|
RoleBinding *rbac.RoleBinding
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o RoleBindingAdapter) GetNamespace() string {
|
||||||
|
return o.RoleBinding.Namespace
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o RoleBindingAdapter) GetName() string {
|
||||||
|
return o.RoleBinding.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o RoleBindingAdapter) GetUID() types.UID {
|
||||||
|
return o.RoleBinding.UID
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o RoleBindingAdapter) GetLabels() map[string]string {
|
||||||
|
return o.RoleBinding.Labels
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o RoleBindingAdapter) SetLabels(in map[string]string) {
|
||||||
|
o.RoleBinding.Labels = in
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o RoleBindingAdapter) GetAnnotations() map[string]string {
|
||||||
|
return o.RoleBinding.Annotations
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o RoleBindingAdapter) SetAnnotations(in map[string]string) {
|
||||||
|
o.RoleBinding.Annotations = in
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o RoleBindingAdapter) GetRoleRef() rbac.RoleRef {
|
||||||
|
return o.RoleBinding.RoleRef
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o RoleBindingAdapter) GetSubjects() []rbac.Subject {
|
||||||
|
return o.RoleBinding.Subjects
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o RoleBindingAdapter) SetSubjects(in []rbac.Subject) {
|
||||||
|
o.RoleBinding.Subjects = in
|
||||||
|
}
|
||||||
|
|
||||||
|
type RoleBindingClientAdapter struct {
|
||||||
|
Client internalversion.RoleBindingsGetter
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c RoleBindingClientAdapter) Get(namespace, name string) (RoleBinding, error) {
|
||||||
|
ret, err := c.Client.RoleBindings(namespace).Get(name, metav1.GetOptions{})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return RoleBindingAdapter{RoleBinding: ret}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c RoleBindingClientAdapter) Create(in RoleBinding) (RoleBinding, error) {
|
||||||
|
ret, err := c.Client.RoleBindings(in.GetNamespace()).Create(in.(RoleBindingAdapter).RoleBinding)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return RoleBindingAdapter{RoleBinding: ret}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c RoleBindingClientAdapter) Update(in RoleBinding) (RoleBinding, error) {
|
||||||
|
ret, err := c.Client.RoleBindings(in.GetNamespace()).Update(in.(RoleBindingAdapter).RoleBinding)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return RoleBindingAdapter{RoleBinding: ret}, err
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c RoleBindingClientAdapter) Delete(namespace, name string, uid types.UID) error {
|
||||||
|
return c.Client.RoleBindings(namespace).Delete(name, &metav1.DeleteOptions{Preconditions: &metav1.Preconditions{UID: &uid}})
|
||||||
|
}
|
@ -147,7 +147,7 @@ func PostStartHook(hookContext genericapiserver.PostStartHookContext) error {
|
|||||||
|
|
||||||
// ensure bootstrap roles are created or reconciled
|
// ensure bootstrap roles are created or reconciled
|
||||||
for _, clusterRole := range append(bootstrappolicy.ClusterRoles(), bootstrappolicy.ControllerRoles()...) {
|
for _, clusterRole := range append(bootstrappolicy.ClusterRoles(), bootstrappolicy.ControllerRoles()...) {
|
||||||
opts := reconciliation.ReconcileClusterRoleOptions{
|
opts := reconciliation.ReconcileRoleOptions{
|
||||||
Role: reconciliation.ClusterRoleRuleOwner{ClusterRole: &clusterRole},
|
Role: reconciliation.ClusterRoleRuleOwner{ClusterRole: &clusterRole},
|
||||||
Client: reconciliation.ClusterRoleModifier{Client: clientset.ClusterRoles()},
|
Client: reconciliation.ClusterRoleModifier{Client: clientset.ClusterRoles()},
|
||||||
Confirm: true,
|
Confirm: true,
|
||||||
@ -175,9 +175,9 @@ func PostStartHook(hookContext genericapiserver.PostStartHookContext) error {
|
|||||||
|
|
||||||
// ensure bootstrap rolebindings are created or reconciled
|
// ensure bootstrap rolebindings are created or reconciled
|
||||||
for _, clusterRoleBinding := range append(bootstrappolicy.ClusterRoleBindings(), bootstrappolicy.ControllerRoleBindings()...) {
|
for _, clusterRoleBinding := range append(bootstrappolicy.ClusterRoleBindings(), bootstrappolicy.ControllerRoleBindings()...) {
|
||||||
opts := reconciliation.ReconcileClusterRoleBindingOptions{
|
opts := reconciliation.ReconcileRoleBindingOptions{
|
||||||
RoleBinding: &clusterRoleBinding,
|
RoleBinding: reconciliation.ClusterRoleBindingAdapter{ClusterRoleBinding: &clusterRoleBinding},
|
||||||
Client: clientset.ClusterRoleBindings(),
|
Client: reconciliation.ClusterRoleBindingClientAdapter{Client: clientset.ClusterRoleBindings()},
|
||||||
Confirm: true,
|
Confirm: true,
|
||||||
}
|
}
|
||||||
err := retry.RetryOnConflict(retry.DefaultBackoff, func() error {
|
err := retry.RetryOnConflict(retry.DefaultBackoff, func() error {
|
||||||
@ -206,7 +206,7 @@ func PostStartHook(hookContext genericapiserver.PostStartHookContext) error {
|
|||||||
// ensure bootstrap namespaced roles are created or reconciled
|
// ensure bootstrap namespaced roles are created or reconciled
|
||||||
for namespace, roles := range bootstrappolicy.NamespaceRoles() {
|
for namespace, roles := range bootstrappolicy.NamespaceRoles() {
|
||||||
for _, role := range roles {
|
for _, role := range roles {
|
||||||
opts := reconciliation.ReconcileClusterRoleOptions{
|
opts := reconciliation.ReconcileRoleOptions{
|
||||||
Role: reconciliation.RoleRuleOwner{Role: &role},
|
Role: reconciliation.RoleRuleOwner{Role: &role},
|
||||||
Client: reconciliation.RoleModifier{Client: clientset},
|
Client: reconciliation.RoleModifier{Client: clientset},
|
||||||
Confirm: true,
|
Confirm: true,
|
||||||
@ -233,6 +233,38 @@ func PostStartHook(hookContext genericapiserver.PostStartHookContext) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ensure bootstrap namespaced rolebindings are created or reconciled
|
||||||
|
for namespace, roleBindings := range bootstrappolicy.NamespaceRoleBindings() {
|
||||||
|
for _, roleBinding := range roleBindings {
|
||||||
|
opts := reconciliation.ReconcileRoleBindingOptions{
|
||||||
|
RoleBinding: reconciliation.RoleBindingAdapter{RoleBinding: &roleBinding},
|
||||||
|
Client: reconciliation.RoleBindingClientAdapter{Client: clientset},
|
||||||
|
Confirm: true,
|
||||||
|
}
|
||||||
|
err := retry.RetryOnConflict(retry.DefaultBackoff, func() error {
|
||||||
|
result, err := opts.Run()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
switch {
|
||||||
|
case result.Protected && result.Operation != reconciliation.ReconcileNone:
|
||||||
|
glog.Warningf("skipped reconcile-protected rolebinding.%s/%s in %v with missing subjects: %v", rbac.GroupName, roleBinding.Name, namespace, result.MissingSubjects)
|
||||||
|
case result.Operation == reconciliation.ReconcileUpdate:
|
||||||
|
glog.Infof("updated rolebinding.%s/%s in %v with additional subjects: %v", rbac.GroupName, roleBinding.Name, namespace, result.MissingSubjects)
|
||||||
|
case result.Operation == reconciliation.ReconcileCreate:
|
||||||
|
glog.Infof("created rolebinding.%s/%s in %v", rbac.GroupName, roleBinding.Name, namespace)
|
||||||
|
case result.Operation == reconciliation.ReconcileRecreate:
|
||||||
|
glog.Infof("recreated rolebinding.%s/%s in %v", rbac.GroupName, roleBinding.Name, namespace)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
// don't fail on failures, try to create as many as you can
|
||||||
|
utilruntime.HandleError(fmt.Errorf("unable to reconcile rolebinding.%s/%s in %v: %v", rbac.GroupName, roleBinding.Name, namespace, err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true, nil
|
return true, nil
|
||||||
})
|
})
|
||||||
// if we're never able to make it through intialization, kill the API server
|
// if we're never able to make it through intialization, kill the API server
|
||||||
|
@ -28,6 +28,9 @@ import (
|
|||||||
var (
|
var (
|
||||||
// namespaceRoles is a map of namespace to slice of roles to create
|
// namespaceRoles is a map of namespace to slice of roles to create
|
||||||
namespaceRoles = map[string][]rbac.Role{}
|
namespaceRoles = map[string][]rbac.Role{}
|
||||||
|
|
||||||
|
// namespaceRoleBindings is a map of namespace to slice of roleBindings to create
|
||||||
|
namespaceRoleBindings = map[string][]rbac.RoleBinding{}
|
||||||
)
|
)
|
||||||
|
|
||||||
func addNamespaceRole(namespace string, role rbac.Role) {
|
func addNamespaceRole(namespace string, role rbac.Role) {
|
||||||
@ -48,6 +51,24 @@ func addNamespaceRole(namespace string, role rbac.Role) {
|
|||||||
namespaceRoles[namespace] = existingRoles
|
namespaceRoles[namespace] = existingRoles
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func addNamespaceRoleBinding(namespace string, roleBinding rbac.RoleBinding) {
|
||||||
|
if !strings.HasPrefix(namespace, "kube-") {
|
||||||
|
glog.Fatalf(`roles can only be bootstrapped into reserved namespaces starting with "kube-", not %q`, namespace)
|
||||||
|
}
|
||||||
|
|
||||||
|
existingRoleBindings := namespaceRoleBindings[namespace]
|
||||||
|
for _, existingRoleBinding := range existingRoleBindings {
|
||||||
|
if roleBinding.Name == existingRoleBinding.Name {
|
||||||
|
glog.Fatalf("rolebinding %q was already registered in %q", roleBinding.Name, namespace)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
roleBinding.Namespace = namespace
|
||||||
|
addDefaultMetadata(&roleBinding)
|
||||||
|
existingRoleBindings = append(existingRoleBindings, roleBinding)
|
||||||
|
namespaceRoleBindings[namespace] = existingRoleBindings
|
||||||
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
addNamespaceRole(metav1.NamespaceSystem, rbac.Role{
|
addNamespaceRole(metav1.NamespaceSystem, rbac.Role{
|
||||||
// role for finding authentication config info for starting a server
|
// role for finding authentication config info for starting a server
|
||||||
@ -57,9 +78,46 @@ func init() {
|
|||||||
rbac.NewRule("get").Groups(legacyGroup).Resources("configmaps").Names("extension-apiserver-authentication").RuleOrDie(),
|
rbac.NewRule("get").Groups(legacyGroup).Resources("configmaps").Names("extension-apiserver-authentication").RuleOrDie(),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
addNamespaceRole(metav1.NamespaceSystem, rbac.Role{
|
||||||
|
// role for the bootstrap signer to be able to inspect kube-system secrets
|
||||||
|
ObjectMeta: metav1.ObjectMeta{Name: saRolePrefix + "bootstrap-signer"},
|
||||||
|
Rules: []rbac.PolicyRule{
|
||||||
|
rbac.NewRule("get", "list", "watch").Groups(legacyGroup).Resources("secrets").RuleOrDie(),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
addNamespaceRole(metav1.NamespaceSystem, rbac.Role{
|
||||||
|
// role for the token-cleaner to be able to remove secrets, but only in kube-system
|
||||||
|
ObjectMeta: metav1.ObjectMeta{Name: saRolePrefix + "token-cleaner"},
|
||||||
|
Rules: []rbac.PolicyRule{
|
||||||
|
rbac.NewRule("get", "list", "watch", "delete").Groups(legacyGroup).Resources("secrets").RuleOrDie(),
|
||||||
|
eventsRule(),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
addNamespaceRoleBinding(metav1.NamespaceSystem,
|
||||||
|
rbac.NewRoleBinding(saRolePrefix+"bootstrap-signer", metav1.NamespaceSystem).SAs(metav1.NamespaceSystem, "bootstrap-signer").BindingOrDie())
|
||||||
|
addNamespaceRoleBinding(metav1.NamespaceSystem,
|
||||||
|
rbac.NewRoleBinding(saRolePrefix+"token-cleaner", metav1.NamespaceSystem).SAs(metav1.NamespaceSystem, "token-cleaner").BindingOrDie())
|
||||||
|
|
||||||
|
addNamespaceRole(metav1.NamespacePublic, rbac.Role{
|
||||||
|
// role for the bootstrap signer to be able to write its configmap
|
||||||
|
ObjectMeta: metav1.ObjectMeta{Name: saRolePrefix + "bootstrap-signer"},
|
||||||
|
Rules: []rbac.PolicyRule{
|
||||||
|
rbac.NewRule("get", "list", "watch").Groups(legacyGroup).Resources("configmaps").RuleOrDie(),
|
||||||
|
rbac.NewRule("update").Groups(legacyGroup).Resources("configmaps").Names("cluster-info").RuleOrDie(),
|
||||||
|
eventsRule(),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
addNamespaceRoleBinding(metav1.NamespacePublic,
|
||||||
|
rbac.NewRoleBinding(saRolePrefix+"bootstrap-signer", metav1.NamespacePublic).SAs(metav1.NamespaceSystem, "bootstrap-signer").BindingOrDie())
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NamespaceRoles returns a map of namespace to slice of roles to create
|
// NamespaceRoles returns a map of namespace to slice of roles to create
|
||||||
func NamespaceRoles() map[string][]rbac.Role {
|
func NamespaceRoles() map[string][]rbac.Role {
|
||||||
return namespaceRoles
|
return namespaceRoles
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// NamespaceRoleBindings returns a map of namespace to slice of roles to create
|
||||||
|
func NamespaceRoleBindings() map[string][]rbac.RoleBinding {
|
||||||
|
return namespaceRoleBindings
|
||||||
|
}
|
||||||
|
@ -187,6 +187,28 @@ func TestBootstrapNamespaceRoles(t *testing.T) {
|
|||||||
testObjects(t, list, "namespace-roles.yaml")
|
testObjects(t, list, "namespace-roles.yaml")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestBootstrapNamespaceRoleBindings(t *testing.T) {
|
||||||
|
list := &api.List{}
|
||||||
|
names := sets.NewString()
|
||||||
|
roleBindings := map[string]runtime.Object{}
|
||||||
|
|
||||||
|
namespaceRoleBindings := bootstrappolicy.NamespaceRoleBindings()
|
||||||
|
for _, namespace := range sets.StringKeySet(namespaceRoleBindings).List() {
|
||||||
|
bootstrapRoleBindings := namespaceRoleBindings[namespace]
|
||||||
|
for i := range bootstrapRoleBindings {
|
||||||
|
roleBinding := bootstrapRoleBindings[i]
|
||||||
|
names.Insert(roleBinding.Name)
|
||||||
|
roleBindings[roleBinding.Name] = &roleBinding
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, name := range names.List() {
|
||||||
|
list.Items = append(list.Items, roleBindings[name])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
testObjects(t, list, "namespace-role-bindings.yaml")
|
||||||
|
}
|
||||||
|
|
||||||
func TestBootstrapClusterRoles(t *testing.T) {
|
func TestBootstrapClusterRoles(t *testing.T) {
|
||||||
list := &api.List{}
|
list := &api.List{}
|
||||||
names := sets.NewString()
|
names := sets.NewString()
|
||||||
|
58
plugin/pkg/auth/authorizer/rbac/bootstrappolicy/testdata/namespace-role-bindings.yaml
vendored
Normal file
58
plugin/pkg/auth/authorizer/rbac/bootstrappolicy/testdata/namespace-role-bindings.yaml
vendored
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
apiVersion: v1
|
||||||
|
items:
|
||||||
|
- apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||||
|
kind: RoleBinding
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
rbac.authorization.kubernetes.io/autoupdate: "true"
|
||||||
|
creationTimestamp: null
|
||||||
|
labels:
|
||||||
|
kubernetes.io/bootstrapping: rbac-defaults
|
||||||
|
name: system:controller:bootstrap-signer
|
||||||
|
namespace: kube-public
|
||||||
|
roleRef:
|
||||||
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
kind: Role
|
||||||
|
name: system:controller:bootstrap-signer
|
||||||
|
subjects:
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: bootstrap-signer
|
||||||
|
namespace: kube-system
|
||||||
|
- apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||||
|
kind: RoleBinding
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
rbac.authorization.kubernetes.io/autoupdate: "true"
|
||||||
|
creationTimestamp: null
|
||||||
|
labels:
|
||||||
|
kubernetes.io/bootstrapping: rbac-defaults
|
||||||
|
name: system:controller:bootstrap-signer
|
||||||
|
namespace: kube-system
|
||||||
|
roleRef:
|
||||||
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
kind: Role
|
||||||
|
name: system:controller:bootstrap-signer
|
||||||
|
subjects:
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: bootstrap-signer
|
||||||
|
namespace: kube-system
|
||||||
|
- apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||||
|
kind: RoleBinding
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
rbac.authorization.kubernetes.io/autoupdate: "true"
|
||||||
|
creationTimestamp: null
|
||||||
|
labels:
|
||||||
|
kubernetes.io/bootstrapping: rbac-defaults
|
||||||
|
name: system:controller:token-cleaner
|
||||||
|
namespace: kube-system
|
||||||
|
roleRef:
|
||||||
|
apiGroup: rbac.authorization.k8s.io
|
||||||
|
kind: Role
|
||||||
|
name: system:controller:token-cleaner
|
||||||
|
subjects:
|
||||||
|
- kind: ServiceAccount
|
||||||
|
name: token-cleaner
|
||||||
|
namespace: kube-system
|
||||||
|
kind: List
|
||||||
|
metadata: {}
|
@ -1,5 +1,40 @@
|
|||||||
apiVersion: v1
|
apiVersion: v1
|
||||||
items:
|
items:
|
||||||
|
- apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||||
|
kind: Role
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
rbac.authorization.kubernetes.io/autoupdate: "true"
|
||||||
|
creationTimestamp: null
|
||||||
|
labels:
|
||||||
|
kubernetes.io/bootstrapping: rbac-defaults
|
||||||
|
name: system:controller:bootstrap-signer
|
||||||
|
namespace: kube-public
|
||||||
|
rules:
|
||||||
|
- apiGroups:
|
||||||
|
- ""
|
||||||
|
resources:
|
||||||
|
- configmaps
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
|
- list
|
||||||
|
- watch
|
||||||
|
- apiGroups:
|
||||||
|
- ""
|
||||||
|
resourceNames:
|
||||||
|
- cluster-info
|
||||||
|
resources:
|
||||||
|
- configmaps
|
||||||
|
verbs:
|
||||||
|
- update
|
||||||
|
- apiGroups:
|
||||||
|
- ""
|
||||||
|
resources:
|
||||||
|
- events
|
||||||
|
verbs:
|
||||||
|
- create
|
||||||
|
- patch
|
||||||
|
- update
|
||||||
- apiVersion: rbac.authorization.k8s.io/v1beta1
|
- apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||||
kind: Role
|
kind: Role
|
||||||
metadata:
|
metadata:
|
||||||
@ -19,5 +54,52 @@ items:
|
|||||||
- configmaps
|
- configmaps
|
||||||
verbs:
|
verbs:
|
||||||
- get
|
- get
|
||||||
|
- apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||||
|
kind: Role
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
rbac.authorization.kubernetes.io/autoupdate: "true"
|
||||||
|
creationTimestamp: null
|
||||||
|
labels:
|
||||||
|
kubernetes.io/bootstrapping: rbac-defaults
|
||||||
|
name: system:controller:bootstrap-signer
|
||||||
|
namespace: kube-system
|
||||||
|
rules:
|
||||||
|
- apiGroups:
|
||||||
|
- ""
|
||||||
|
resources:
|
||||||
|
- secrets
|
||||||
|
verbs:
|
||||||
|
- get
|
||||||
|
- list
|
||||||
|
- watch
|
||||||
|
- apiVersion: rbac.authorization.k8s.io/v1beta1
|
||||||
|
kind: Role
|
||||||
|
metadata:
|
||||||
|
annotations:
|
||||||
|
rbac.authorization.kubernetes.io/autoupdate: "true"
|
||||||
|
creationTimestamp: null
|
||||||
|
labels:
|
||||||
|
kubernetes.io/bootstrapping: rbac-defaults
|
||||||
|
name: system:controller:token-cleaner
|
||||||
|
namespace: kube-system
|
||||||
|
rules:
|
||||||
|
- apiGroups:
|
||||||
|
- ""
|
||||||
|
resources:
|
||||||
|
- secrets
|
||||||
|
verbs:
|
||||||
|
- delete
|
||||||
|
- get
|
||||||
|
- list
|
||||||
|
- watch
|
||||||
|
- apiGroups:
|
||||||
|
- ""
|
||||||
|
resources:
|
||||||
|
- events
|
||||||
|
verbs:
|
||||||
|
- create
|
||||||
|
- patch
|
||||||
|
- update
|
||||||
kind: List
|
kind: List
|
||||||
metadata: {}
|
metadata: {}
|
||||||
|
@ -279,6 +279,22 @@ func NewRoleBinding(roleName, namespace string) *RoleBindingBuilder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewRoleBindingForClusterRole(roleName, namespace string) *RoleBindingBuilder {
|
||||||
|
return &RoleBindingBuilder{
|
||||||
|
RoleBinding: RoleBinding{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: roleName,
|
||||||
|
Namespace: namespace,
|
||||||
|
},
|
||||||
|
RoleRef: RoleRef{
|
||||||
|
APIGroup: GroupName,
|
||||||
|
Kind: "ClusterRole",
|
||||||
|
Name: roleName,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Groups adds the specified groups as the subjects of the RoleBinding.
|
// Groups adds the specified groups as the subjects of the RoleBinding.
|
||||||
func (r *RoleBindingBuilder) Groups(groups ...string) *RoleBindingBuilder {
|
func (r *RoleBindingBuilder) Groups(groups ...string) *RoleBindingBuilder {
|
||||||
for _, group := range groups {
|
for _, group := range groups {
|
||||||
|
Loading…
Reference in New Issue
Block a user