Skip to content

Commit f6929fc

Browse files
author
Kubernetes Submit Queue
authored
Merge pull request kubernetes#50702 from enj/enj/r/inject_policy_hook
Automatic merge from submit-queue (batch tested with PRs 50694, 50702) Allow injection of policy in RBAC post start hook This change allows the RBAC PostStartHook logic to be reused with different policy data when bootstrapping the cluster. Thus any changes to the bootstrap logic are separated from the policy data. Signed-off-by: Monis Khan <[email protected]> ```release-note NONE ``` @kubernetes/sig-auth-pr-reviews
2 parents c743e68 + 751741d commit f6929fc

File tree

1 file changed

+119
-104
lines changed

1 file changed

+119
-104
lines changed

pkg/registry/rbac/rest/storage_rbac.go

Lines changed: 119 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -134,99 +134,54 @@ func (p RESTStorageProvider) storage(version schema.GroupVersion, apiResourceCon
134134
}
135135

136136
func (p RESTStorageProvider) PostStartHook() (string, genericapiserver.PostStartHookFunc, error) {
137-
return PostStartHookName, PostStartHook, nil
137+
policy := &PolicyData{
138+
ClusterRoles: append(bootstrappolicy.ClusterRoles(), bootstrappolicy.ControllerRoles()...),
139+
ClusterRoleBindings: append(bootstrappolicy.ClusterRoleBindings(), bootstrappolicy.ControllerRoleBindings()...),
140+
Roles: bootstrappolicy.NamespaceRoles(),
141+
RoleBindings: bootstrappolicy.NamespaceRoleBindings(),
142+
}
143+
return PostStartHookName, policy.EnsureRBACPolicy(), nil
138144
}
139145

140-
func PostStartHook(hookContext genericapiserver.PostStartHookContext) error {
141-
// intializing roles is really important. On some e2e runs, we've seen cases where etcd is down when the server
142-
// starts, the roles don't initialize, and nothing works.
143-
err := wait.Poll(1*time.Second, 30*time.Second, func() (done bool, err error) {
144-
145-
coreclientset, err := coreclient.NewForConfig(hookContext.LoopbackClientConfig)
146-
if err != nil {
147-
utilruntime.HandleError(fmt.Errorf("unable to initialize client: %v", err))
148-
return false, nil
149-
}
146+
type PolicyData struct {
147+
ClusterRoles []rbac.ClusterRole
148+
ClusterRoleBindings []rbac.ClusterRoleBinding
149+
Roles map[string][]rbac.Role
150+
RoleBindings map[string][]rbac.RoleBinding
151+
}
150152

151-
clientset, err := rbacclient.NewForConfig(hookContext.LoopbackClientConfig)
152-
if err != nil {
153-
utilruntime.HandleError(fmt.Errorf("unable to initialize client: %v", err))
154-
return false, nil
155-
}
156-
// Make sure etcd is responding before we start reconciling
157-
if _, err := clientset.ClusterRoles().List(metav1.ListOptions{}); err != nil {
158-
utilruntime.HandleError(fmt.Errorf("unable to initialize clusterroles: %v", err))
159-
return false, nil
160-
}
161-
if _, err := clientset.ClusterRoleBindings().List(metav1.ListOptions{}); err != nil {
162-
utilruntime.HandleError(fmt.Errorf("unable to initialize clusterrolebindings: %v", err))
163-
return false, nil
164-
}
153+
func (p *PolicyData) EnsureRBACPolicy() genericapiserver.PostStartHookFunc {
154+
return func(hookContext genericapiserver.PostStartHookContext) error {
155+
// intializing roles is really important. On some e2e runs, we've seen cases where etcd is down when the server
156+
// starts, the roles don't initialize, and nothing works.
157+
err := wait.Poll(1*time.Second, 30*time.Second, func() (done bool, err error) {
165158

166-
// ensure bootstrap roles are created or reconciled
167-
for _, clusterRole := range append(bootstrappolicy.ClusterRoles(), bootstrappolicy.ControllerRoles()...) {
168-
opts := reconciliation.ReconcileRoleOptions{
169-
Role: reconciliation.ClusterRoleRuleOwner{ClusterRole: &clusterRole},
170-
Client: reconciliation.ClusterRoleModifier{Client: clientset.ClusterRoles()},
171-
Confirm: true,
172-
}
173-
err := retry.RetryOnConflict(retry.DefaultBackoff, func() error {
174-
result, err := opts.Run()
175-
if err != nil {
176-
return err
177-
}
178-
switch {
179-
case result.Protected && result.Operation != reconciliation.ReconcileNone:
180-
glog.Warningf("skipped reconcile-protected clusterrole.%s/%s with missing permissions: %v", rbac.GroupName, clusterRole.Name, result.MissingRules)
181-
case result.Operation == reconciliation.ReconcileUpdate:
182-
glog.Infof("updated clusterrole.%s/%s with additional permissions: %v", rbac.GroupName, clusterRole.Name, result.MissingRules)
183-
case result.Operation == reconciliation.ReconcileCreate:
184-
glog.Infof("created clusterrole.%s/%s", rbac.GroupName, clusterRole.Name)
185-
}
186-
return nil
187-
})
159+
coreclientset, err := coreclient.NewForConfig(hookContext.LoopbackClientConfig)
188160
if err != nil {
189-
// don't fail on failures, try to create as many as you can
190-
utilruntime.HandleError(fmt.Errorf("unable to reconcile clusterrole.%s/%s: %v", rbac.GroupName, clusterRole.Name, err))
161+
utilruntime.HandleError(fmt.Errorf("unable to initialize client: %v", err))
162+
return false, nil
191163
}
192-
}
193164

194-
// ensure bootstrap rolebindings are created or reconciled
195-
for _, clusterRoleBinding := range append(bootstrappolicy.ClusterRoleBindings(), bootstrappolicy.ControllerRoleBindings()...) {
196-
opts := reconciliation.ReconcileRoleBindingOptions{
197-
RoleBinding: reconciliation.ClusterRoleBindingAdapter{ClusterRoleBinding: &clusterRoleBinding},
198-
Client: reconciliation.ClusterRoleBindingClientAdapter{Client: clientset.ClusterRoleBindings()},
199-
Confirm: true,
200-
}
201-
err := retry.RetryOnConflict(retry.DefaultBackoff, func() error {
202-
result, err := opts.Run()
203-
if err != nil {
204-
return err
205-
}
206-
switch {
207-
case result.Protected && result.Operation != reconciliation.ReconcileNone:
208-
glog.Warningf("skipped reconcile-protected clusterrolebinding.%s/%s with missing subjects: %v", rbac.GroupName, clusterRoleBinding.Name, result.MissingSubjects)
209-
case result.Operation == reconciliation.ReconcileUpdate:
210-
glog.Infof("updated clusterrolebinding.%s/%s with additional subjects: %v", rbac.GroupName, clusterRoleBinding.Name, result.MissingSubjects)
211-
case result.Operation == reconciliation.ReconcileCreate:
212-
glog.Infof("created clusterrolebinding.%s/%s", rbac.GroupName, clusterRoleBinding.Name)
213-
case result.Operation == reconciliation.ReconcileRecreate:
214-
glog.Infof("recreated clusterrolebinding.%s/%s", rbac.GroupName, clusterRoleBinding.Name)
215-
}
216-
return nil
217-
})
165+
clientset, err := rbacclient.NewForConfig(hookContext.LoopbackClientConfig)
218166
if err != nil {
219-
// don't fail on failures, try to create as many as you can
220-
utilruntime.HandleError(fmt.Errorf("unable to reconcile clusterrolebinding.%s/%s: %v", rbac.GroupName, clusterRoleBinding.Name, err))
167+
utilruntime.HandleError(fmt.Errorf("unable to initialize client: %v", err))
168+
return false, nil
169+
}
170+
// Make sure etcd is responding before we start reconciling
171+
if _, err := clientset.ClusterRoles().List(metav1.ListOptions{}); err != nil {
172+
utilruntime.HandleError(fmt.Errorf("unable to initialize clusterroles: %v", err))
173+
return false, nil
174+
}
175+
if _, err := clientset.ClusterRoleBindings().List(metav1.ListOptions{}); err != nil {
176+
utilruntime.HandleError(fmt.Errorf("unable to initialize clusterrolebindings: %v", err))
177+
return false, nil
221178
}
222-
}
223179

224-
// ensure bootstrap namespaced roles are created or reconciled
225-
for namespace, roles := range bootstrappolicy.NamespaceRoles() {
226-
for _, role := range roles {
180+
// ensure bootstrap roles are created or reconciled
181+
for _, clusterRole := range p.ClusterRoles {
227182
opts := reconciliation.ReconcileRoleOptions{
228-
Role: reconciliation.RoleRuleOwner{Role: &role},
229-
Client: reconciliation.RoleModifier{Client: clientset, NamespaceClient: coreclientset.Namespaces()},
183+
Role: reconciliation.ClusterRoleRuleOwner{ClusterRole: &clusterRole},
184+
Client: reconciliation.ClusterRoleModifier{Client: clientset.ClusterRoles()},
230185
Confirm: true,
231186
}
232187
err := retry.RetryOnConflict(retry.DefaultBackoff, func() error {
@@ -236,27 +191,25 @@ func PostStartHook(hookContext genericapiserver.PostStartHookContext) error {
236191
}
237192
switch {
238193
case result.Protected && result.Operation != reconciliation.ReconcileNone:
239-
glog.Warningf("skipped reconcile-protected role.%s/%s in %v with missing permissions: %v", rbac.GroupName, role.Name, namespace, result.MissingRules)
194+
glog.Warningf("skipped reconcile-protected clusterrole.%s/%s with missing permissions: %v", rbac.GroupName, clusterRole.Name, result.MissingRules)
240195
case result.Operation == reconciliation.ReconcileUpdate:
241-
glog.Infof("updated role.%s/%s in %v with additional permissions: %v", rbac.GroupName, role.Name, namespace, result.MissingRules)
196+
glog.Infof("updated clusterrole.%s/%s with additional permissions: %v", rbac.GroupName, clusterRole.Name, result.MissingRules)
242197
case result.Operation == reconciliation.ReconcileCreate:
243-
glog.Infof("created role.%s/%s in %v ", rbac.GroupName, role.Name, namespace)
198+
glog.Infof("created clusterrole.%s/%s", rbac.GroupName, clusterRole.Name)
244199
}
245200
return nil
246201
})
247202
if err != nil {
248203
// don't fail on failures, try to create as many as you can
249-
utilruntime.HandleError(fmt.Errorf("unable to reconcile role.%s/%s in %v: %v", rbac.GroupName, role.Name, namespace, err))
204+
utilruntime.HandleError(fmt.Errorf("unable to reconcile clusterrole.%s/%s: %v", rbac.GroupName, clusterRole.Name, err))
250205
}
251206
}
252-
}
253207

254-
// ensure bootstrap namespaced rolebindings are created or reconciled
255-
for namespace, roleBindings := range bootstrappolicy.NamespaceRoleBindings() {
256-
for _, roleBinding := range roleBindings {
208+
// ensure bootstrap rolebindings are created or reconciled
209+
for _, clusterRoleBinding := range p.ClusterRoleBindings {
257210
opts := reconciliation.ReconcileRoleBindingOptions{
258-
RoleBinding: reconciliation.RoleBindingAdapter{RoleBinding: &roleBinding},
259-
Client: reconciliation.RoleBindingClientAdapter{Client: clientset, NamespaceClient: coreclientset.Namespaces()},
211+
RoleBinding: reconciliation.ClusterRoleBindingAdapter{ClusterRoleBinding: &clusterRoleBinding},
212+
Client: reconciliation.ClusterRoleBindingClientAdapter{Client: clientset.ClusterRoleBindings()},
260213
Confirm: true,
261214
}
262215
err := retry.RetryOnConflict(retry.DefaultBackoff, func() error {
@@ -266,31 +219,93 @@ func PostStartHook(hookContext genericapiserver.PostStartHookContext) error {
266219
}
267220
switch {
268221
case result.Protected && result.Operation != reconciliation.ReconcileNone:
269-
glog.Warningf("skipped reconcile-protected rolebinding.%s/%s in %v with missing subjects: %v", rbac.GroupName, roleBinding.Name, namespace, result.MissingSubjects)
222+
glog.Warningf("skipped reconcile-protected clusterrolebinding.%s/%s with missing subjects: %v", rbac.GroupName, clusterRoleBinding.Name, result.MissingSubjects)
270223
case result.Operation == reconciliation.ReconcileUpdate:
271-
glog.Infof("updated rolebinding.%s/%s in %v with additional subjects: %v", rbac.GroupName, roleBinding.Name, namespace, result.MissingSubjects)
224+
glog.Infof("updated clusterrolebinding.%s/%s with additional subjects: %v", rbac.GroupName, clusterRoleBinding.Name, result.MissingSubjects)
272225
case result.Operation == reconciliation.ReconcileCreate:
273-
glog.Infof("created rolebinding.%s/%s in %v", rbac.GroupName, roleBinding.Name, namespace)
226+
glog.Infof("created clusterrolebinding.%s/%s", rbac.GroupName, clusterRoleBinding.Name)
274227
case result.Operation == reconciliation.ReconcileRecreate:
275-
glog.Infof("recreated rolebinding.%s/%s in %v", rbac.GroupName, roleBinding.Name, namespace)
228+
glog.Infof("recreated clusterrolebinding.%s/%s", rbac.GroupName, clusterRoleBinding.Name)
276229
}
277230
return nil
278231
})
279232
if err != nil {
280233
// don't fail on failures, try to create as many as you can
281-
utilruntime.HandleError(fmt.Errorf("unable to reconcile rolebinding.%s/%s in %v: %v", rbac.GroupName, roleBinding.Name, namespace, err))
234+
utilruntime.HandleError(fmt.Errorf("unable to reconcile clusterrolebinding.%s/%s: %v", rbac.GroupName, clusterRoleBinding.Name, err))
235+
}
236+
}
237+
238+
// ensure bootstrap namespaced roles are created or reconciled
239+
for namespace, roles := range p.Roles {
240+
for _, role := range roles {
241+
opts := reconciliation.ReconcileRoleOptions{
242+
Role: reconciliation.RoleRuleOwner{Role: &role},
243+
Client: reconciliation.RoleModifier{Client: clientset, NamespaceClient: coreclientset.Namespaces()},
244+
Confirm: true,
245+
}
246+
err := retry.RetryOnConflict(retry.DefaultBackoff, func() error {
247+
result, err := opts.Run()
248+
if err != nil {
249+
return err
250+
}
251+
switch {
252+
case result.Protected && result.Operation != reconciliation.ReconcileNone:
253+
glog.Warningf("skipped reconcile-protected role.%s/%s in %v with missing permissions: %v", rbac.GroupName, role.Name, namespace, result.MissingRules)
254+
case result.Operation == reconciliation.ReconcileUpdate:
255+
glog.Infof("updated role.%s/%s in %v with additional permissions: %v", rbac.GroupName, role.Name, namespace, result.MissingRules)
256+
case result.Operation == reconciliation.ReconcileCreate:
257+
glog.Infof("created role.%s/%s in %v ", rbac.GroupName, role.Name, namespace)
258+
}
259+
return nil
260+
})
261+
if err != nil {
262+
// don't fail on failures, try to create as many as you can
263+
utilruntime.HandleError(fmt.Errorf("unable to reconcile role.%s/%s in %v: %v", rbac.GroupName, role.Name, namespace, err))
264+
}
282265
}
283266
}
267+
268+
// ensure bootstrap namespaced rolebindings are created or reconciled
269+
for namespace, roleBindings := range p.RoleBindings {
270+
for _, roleBinding := range roleBindings {
271+
opts := reconciliation.ReconcileRoleBindingOptions{
272+
RoleBinding: reconciliation.RoleBindingAdapter{RoleBinding: &roleBinding},
273+
Client: reconciliation.RoleBindingClientAdapter{Client: clientset, NamespaceClient: coreclientset.Namespaces()},
274+
Confirm: true,
275+
}
276+
err := retry.RetryOnConflict(retry.DefaultBackoff, func() error {
277+
result, err := opts.Run()
278+
if err != nil {
279+
return err
280+
}
281+
switch {
282+
case result.Protected && result.Operation != reconciliation.ReconcileNone:
283+
glog.Warningf("skipped reconcile-protected rolebinding.%s/%s in %v with missing subjects: %v", rbac.GroupName, roleBinding.Name, namespace, result.MissingSubjects)
284+
case result.Operation == reconciliation.ReconcileUpdate:
285+
glog.Infof("updated rolebinding.%s/%s in %v with additional subjects: %v", rbac.GroupName, roleBinding.Name, namespace, result.MissingSubjects)
286+
case result.Operation == reconciliation.ReconcileCreate:
287+
glog.Infof("created rolebinding.%s/%s in %v", rbac.GroupName, roleBinding.Name, namespace)
288+
case result.Operation == reconciliation.ReconcileRecreate:
289+
glog.Infof("recreated rolebinding.%s/%s in %v", rbac.GroupName, roleBinding.Name, namespace)
290+
}
291+
return nil
292+
})
293+
if err != nil {
294+
// don't fail on failures, try to create as many as you can
295+
utilruntime.HandleError(fmt.Errorf("unable to reconcile rolebinding.%s/%s in %v: %v", rbac.GroupName, roleBinding.Name, namespace, err))
296+
}
297+
}
298+
}
299+
300+
return true, nil
301+
})
302+
// if we're never able to make it through intialization, kill the API server
303+
if err != nil {
304+
return fmt.Errorf("unable to initialize roles: %v", err)
284305
}
285306

286-
return true, nil
287-
})
288-
// if we're never able to make it through intialization, kill the API server
289-
if err != nil {
290-
return fmt.Errorf("unable to initialize roles: %v", err)
307+
return nil
291308
}
292-
293-
return nil
294309
}
295310

296311
func (p RESTStorageProvider) GroupName() string {

0 commit comments

Comments
 (0)