diff --git a/pkg/registry/rbac/rest/storage_rbac.go b/pkg/registry/rbac/rest/storage_rbac.go index f38e38c0984..200bdd55c3c 100644 --- a/pkg/registry/rbac/rest/storage_rbac.go +++ b/pkg/registry/rbac/rest/storage_rbac.go @@ -134,99 +134,54 @@ func (p RESTStorageProvider) storage(version schema.GroupVersion, apiResourceCon } func (p RESTStorageProvider) PostStartHook() (string, genericapiserver.PostStartHookFunc, error) { - return PostStartHookName, PostStartHook, nil + policy := &PolicyData{ + ClusterRoles: append(bootstrappolicy.ClusterRoles(), bootstrappolicy.ControllerRoles()...), + ClusterRoleBindings: append(bootstrappolicy.ClusterRoleBindings(), bootstrappolicy.ControllerRoleBindings()...), + Roles: bootstrappolicy.NamespaceRoles(), + RoleBindings: bootstrappolicy.NamespaceRoleBindings(), + } + return PostStartHookName, policy.EnsureRBACPolicy(), nil } -func PostStartHook(hookContext genericapiserver.PostStartHookContext) error { - // intializing roles is really important. On some e2e runs, we've seen cases where etcd is down when the server - // starts, the roles don't initialize, and nothing works. - err := wait.Poll(1*time.Second, 30*time.Second, func() (done bool, err error) { +type PolicyData struct { + ClusterRoles []rbac.ClusterRole + ClusterRoleBindings []rbac.ClusterRoleBinding + Roles map[string][]rbac.Role + RoleBindings map[string][]rbac.RoleBinding +} - coreclientset, err := coreclient.NewForConfig(hookContext.LoopbackClientConfig) - if err != nil { - utilruntime.HandleError(fmt.Errorf("unable to initialize client: %v", err)) - return false, nil - } +func (p *PolicyData) EnsureRBACPolicy() genericapiserver.PostStartHookFunc { + return func(hookContext genericapiserver.PostStartHookContext) error { + // intializing roles is really important. On some e2e runs, we've seen cases where etcd is down when the server + // starts, the roles don't initialize, and nothing works. + err := wait.Poll(1*time.Second, 30*time.Second, func() (done bool, err error) { - clientset, err := rbacclient.NewForConfig(hookContext.LoopbackClientConfig) - if err != nil { - utilruntime.HandleError(fmt.Errorf("unable to initialize client: %v", err)) - return false, nil - } - // Make sure etcd is responding before we start reconciling - if _, err := clientset.ClusterRoles().List(metav1.ListOptions{}); err != nil { - utilruntime.HandleError(fmt.Errorf("unable to initialize clusterroles: %v", err)) - return false, nil - } - if _, err := clientset.ClusterRoleBindings().List(metav1.ListOptions{}); err != nil { - utilruntime.HandleError(fmt.Errorf("unable to initialize clusterrolebindings: %v", err)) - return false, nil - } - - // ensure bootstrap roles are created or reconciled - for _, clusterRole := range append(bootstrappolicy.ClusterRoles(), bootstrappolicy.ControllerRoles()...) { - opts := reconciliation.ReconcileRoleOptions{ - Role: reconciliation.ClusterRoleRuleOwner{ClusterRole: &clusterRole}, - Client: reconciliation.ClusterRoleModifier{Client: clientset.ClusterRoles()}, - 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 clusterrole.%s/%s with missing permissions: %v", rbac.GroupName, clusterRole.Name, result.MissingRules) - case result.Operation == reconciliation.ReconcileUpdate: - glog.Infof("updated clusterrole.%s/%s with additional permissions: %v", rbac.GroupName, clusterRole.Name, result.MissingRules) - case result.Operation == reconciliation.ReconcileCreate: - glog.Infof("created clusterrole.%s/%s", rbac.GroupName, clusterRole.Name) - } - return nil - }) + coreclientset, err := coreclient.NewForConfig(hookContext.LoopbackClientConfig) if err != nil { - // don't fail on failures, try to create as many as you can - utilruntime.HandleError(fmt.Errorf("unable to reconcile clusterrole.%s/%s: %v", rbac.GroupName, clusterRole.Name, err)) + utilruntime.HandleError(fmt.Errorf("unable to initialize client: %v", err)) + return false, nil } - } - // ensure bootstrap rolebindings are created or reconciled - for _, clusterRoleBinding := range append(bootstrappolicy.ClusterRoleBindings(), bootstrappolicy.ControllerRoleBindings()...) { - opts := reconciliation.ReconcileRoleBindingOptions{ - RoleBinding: reconciliation.ClusterRoleBindingAdapter{ClusterRoleBinding: &clusterRoleBinding}, - Client: reconciliation.ClusterRoleBindingClientAdapter{Client: clientset.ClusterRoleBindings()}, - 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 clusterrolebinding.%s/%s with missing subjects: %v", rbac.GroupName, clusterRoleBinding.Name, result.MissingSubjects) - case result.Operation == reconciliation.ReconcileUpdate: - glog.Infof("updated clusterrolebinding.%s/%s with additional subjects: %v", rbac.GroupName, clusterRoleBinding.Name, result.MissingSubjects) - case result.Operation == reconciliation.ReconcileCreate: - glog.Infof("created clusterrolebinding.%s/%s", rbac.GroupName, clusterRoleBinding.Name) - case result.Operation == reconciliation.ReconcileRecreate: - glog.Infof("recreated clusterrolebinding.%s/%s", rbac.GroupName, clusterRoleBinding.Name) - } - return nil - }) + clientset, err := rbacclient.NewForConfig(hookContext.LoopbackClientConfig) if err != nil { - // don't fail on failures, try to create as many as you can - utilruntime.HandleError(fmt.Errorf("unable to reconcile clusterrolebinding.%s/%s: %v", rbac.GroupName, clusterRoleBinding.Name, err)) + utilruntime.HandleError(fmt.Errorf("unable to initialize client: %v", err)) + return false, nil + } + // Make sure etcd is responding before we start reconciling + if _, err := clientset.ClusterRoles().List(metav1.ListOptions{}); err != nil { + utilruntime.HandleError(fmt.Errorf("unable to initialize clusterroles: %v", err)) + return false, nil + } + if _, err := clientset.ClusterRoleBindings().List(metav1.ListOptions{}); err != nil { + utilruntime.HandleError(fmt.Errorf("unable to initialize clusterrolebindings: %v", err)) + return false, nil } - } - // ensure bootstrap namespaced roles are created or reconciled - for namespace, roles := range bootstrappolicy.NamespaceRoles() { - for _, role := range roles { + // ensure bootstrap roles are created or reconciled + for _, clusterRole := range p.ClusterRoles { opts := reconciliation.ReconcileRoleOptions{ - Role: reconciliation.RoleRuleOwner{Role: &role}, - Client: reconciliation.RoleModifier{Client: clientset, NamespaceClient: coreclientset.Namespaces()}, + Role: reconciliation.ClusterRoleRuleOwner{ClusterRole: &clusterRole}, + Client: reconciliation.ClusterRoleModifier{Client: clientset.ClusterRoles()}, Confirm: true, } err := retry.RetryOnConflict(retry.DefaultBackoff, func() error { @@ -236,27 +191,25 @@ func PostStartHook(hookContext genericapiserver.PostStartHookContext) error { } switch { case result.Protected && result.Operation != reconciliation.ReconcileNone: - glog.Warningf("skipped reconcile-protected role.%s/%s in %v with missing permissions: %v", rbac.GroupName, role.Name, namespace, result.MissingRules) + glog.Warningf("skipped reconcile-protected clusterrole.%s/%s with missing permissions: %v", rbac.GroupName, clusterRole.Name, result.MissingRules) case result.Operation == reconciliation.ReconcileUpdate: - glog.Infof("updated role.%s/%s in %v with additional permissions: %v", rbac.GroupName, role.Name, namespace, result.MissingRules) + glog.Infof("updated clusterrole.%s/%s with additional permissions: %v", rbac.GroupName, clusterRole.Name, result.MissingRules) case result.Operation == reconciliation.ReconcileCreate: - glog.Infof("created role.%s/%s in %v ", rbac.GroupName, role.Name, namespace) + glog.Infof("created clusterrole.%s/%s", rbac.GroupName, clusterRole.Name) } 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 role.%s/%s in %v: %v", rbac.GroupName, role.Name, namespace, err)) + utilruntime.HandleError(fmt.Errorf("unable to reconcile clusterrole.%s/%s: %v", rbac.GroupName, clusterRole.Name, err)) } } - } - // ensure bootstrap namespaced rolebindings are created or reconciled - for namespace, roleBindings := range bootstrappolicy.NamespaceRoleBindings() { - for _, roleBinding := range roleBindings { + // ensure bootstrap rolebindings are created or reconciled + for _, clusterRoleBinding := range p.ClusterRoleBindings { opts := reconciliation.ReconcileRoleBindingOptions{ - RoleBinding: reconciliation.RoleBindingAdapter{RoleBinding: &roleBinding}, - Client: reconciliation.RoleBindingClientAdapter{Client: clientset, NamespaceClient: coreclientset.Namespaces()}, + RoleBinding: reconciliation.ClusterRoleBindingAdapter{ClusterRoleBinding: &clusterRoleBinding}, + Client: reconciliation.ClusterRoleBindingClientAdapter{Client: clientset.ClusterRoleBindings()}, Confirm: true, } err := retry.RetryOnConflict(retry.DefaultBackoff, func() error { @@ -266,31 +219,93 @@ func PostStartHook(hookContext genericapiserver.PostStartHookContext) error { } 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) + glog.Warningf("skipped reconcile-protected clusterrolebinding.%s/%s with missing subjects: %v", rbac.GroupName, clusterRoleBinding.Name, 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) + glog.Infof("updated clusterrolebinding.%s/%s with additional subjects: %v", rbac.GroupName, clusterRoleBinding.Name, result.MissingSubjects) case result.Operation == reconciliation.ReconcileCreate: - glog.Infof("created rolebinding.%s/%s in %v", rbac.GroupName, roleBinding.Name, namespace) + glog.Infof("created clusterrolebinding.%s/%s", rbac.GroupName, clusterRoleBinding.Name) case result.Operation == reconciliation.ReconcileRecreate: - glog.Infof("recreated rolebinding.%s/%s in %v", rbac.GroupName, roleBinding.Name, namespace) + glog.Infof("recreated clusterrolebinding.%s/%s", rbac.GroupName, clusterRoleBinding.Name) } 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)) + utilruntime.HandleError(fmt.Errorf("unable to reconcile clusterrolebinding.%s/%s: %v", rbac.GroupName, clusterRoleBinding.Name, err)) } } + + // ensure bootstrap namespaced roles are created or reconciled + for namespace, roles := range p.Roles { + for _, role := range roles { + opts := reconciliation.ReconcileRoleOptions{ + Role: reconciliation.RoleRuleOwner{Role: &role}, + Client: reconciliation.RoleModifier{Client: clientset, NamespaceClient: coreclientset.Namespaces()}, + 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 role.%s/%s in %v with missing permissions: %v", rbac.GroupName, role.Name, namespace, result.MissingRules) + case result.Operation == reconciliation.ReconcileUpdate: + glog.Infof("updated role.%s/%s in %v with additional permissions: %v", rbac.GroupName, role.Name, namespace, result.MissingRules) + case result.Operation == reconciliation.ReconcileCreate: + glog.Infof("created role.%s/%s in %v ", rbac.GroupName, role.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 role.%s/%s in %v: %v", rbac.GroupName, role.Name, namespace, err)) + } + } + } + + // ensure bootstrap namespaced rolebindings are created or reconciled + for namespace, roleBindings := range p.RoleBindings { + for _, roleBinding := range roleBindings { + opts := reconciliation.ReconcileRoleBindingOptions{ + RoleBinding: reconciliation.RoleBindingAdapter{RoleBinding: &roleBinding}, + Client: reconciliation.RoleBindingClientAdapter{Client: clientset, NamespaceClient: coreclientset.Namespaces()}, + 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 + }) + // if we're never able to make it through intialization, kill the API server + if err != nil { + return fmt.Errorf("unable to initialize roles: %v", err) } - return true, nil - }) - // if we're never able to make it through intialization, kill the API server - if err != nil { - return fmt.Errorf("unable to initialize roles: %v", err) + return nil } - - return nil } func (p RESTStorageProvider) GroupName() string {