storage_rbac.go 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382
  1. /*
  2. Copyright 2016 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package rest
  14. import (
  15. "fmt"
  16. "time"
  17. "k8s.io/klog"
  18. rbacapiv1 "k8s.io/api/rbac/v1"
  19. rbacapiv1alpha1 "k8s.io/api/rbac/v1alpha1"
  20. rbacapiv1beta1 "k8s.io/api/rbac/v1beta1"
  21. apierrors "k8s.io/apimachinery/pkg/api/errors"
  22. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  23. "k8s.io/apimachinery/pkg/runtime/schema"
  24. utilruntime "k8s.io/apimachinery/pkg/util/runtime"
  25. "k8s.io/apimachinery/pkg/util/wait"
  26. "k8s.io/apiserver/pkg/authorization/authorizer"
  27. "k8s.io/apiserver/pkg/registry/generic"
  28. "k8s.io/apiserver/pkg/registry/rest"
  29. genericapiserver "k8s.io/apiserver/pkg/server"
  30. serverstorage "k8s.io/apiserver/pkg/server/storage"
  31. corev1client "k8s.io/client-go/kubernetes/typed/core/v1"
  32. rbacv1client "k8s.io/client-go/kubernetes/typed/rbac/v1"
  33. "k8s.io/client-go/util/retry"
  34. "k8s.io/kubernetes/pkg/api/legacyscheme"
  35. "k8s.io/kubernetes/pkg/apis/rbac"
  36. "k8s.io/kubernetes/pkg/registry/rbac/clusterrole"
  37. clusterrolepolicybased "k8s.io/kubernetes/pkg/registry/rbac/clusterrole/policybased"
  38. clusterrolestore "k8s.io/kubernetes/pkg/registry/rbac/clusterrole/storage"
  39. "k8s.io/kubernetes/pkg/registry/rbac/clusterrolebinding"
  40. clusterrolebindingpolicybased "k8s.io/kubernetes/pkg/registry/rbac/clusterrolebinding/policybased"
  41. clusterrolebindingstore "k8s.io/kubernetes/pkg/registry/rbac/clusterrolebinding/storage"
  42. "k8s.io/kubernetes/pkg/registry/rbac/reconciliation"
  43. "k8s.io/kubernetes/pkg/registry/rbac/role"
  44. rolepolicybased "k8s.io/kubernetes/pkg/registry/rbac/role/policybased"
  45. rolestore "k8s.io/kubernetes/pkg/registry/rbac/role/storage"
  46. "k8s.io/kubernetes/pkg/registry/rbac/rolebinding"
  47. rolebindingpolicybased "k8s.io/kubernetes/pkg/registry/rbac/rolebinding/policybased"
  48. rolebindingstore "k8s.io/kubernetes/pkg/registry/rbac/rolebinding/storage"
  49. rbacregistryvalidation "k8s.io/kubernetes/pkg/registry/rbac/validation"
  50. "k8s.io/kubernetes/plugin/pkg/auth/authorizer/rbac/bootstrappolicy"
  51. )
  52. const PostStartHookName = "rbac/bootstrap-roles"
  53. type RESTStorageProvider struct {
  54. Authorizer authorizer.Authorizer
  55. }
  56. var _ genericapiserver.PostStartHookProvider = RESTStorageProvider{}
  57. func (p RESTStorageProvider) NewRESTStorage(apiResourceConfigSource serverstorage.APIResourceConfigSource, restOptionsGetter generic.RESTOptionsGetter) (genericapiserver.APIGroupInfo, bool) {
  58. apiGroupInfo := genericapiserver.NewDefaultAPIGroupInfo(rbac.GroupName, legacyscheme.Scheme, legacyscheme.ParameterCodec, legacyscheme.Codecs)
  59. // If you add a version here, be sure to add an entry in `k8s.io/kubernetes/cmd/kube-apiserver/app/aggregator.go with specific priorities.
  60. // TODO refactor the plumbing to provide the information in the APIGroupInfo
  61. if apiResourceConfigSource.VersionEnabled(rbacapiv1alpha1.SchemeGroupVersion) {
  62. apiGroupInfo.VersionedResourcesStorageMap[rbacapiv1alpha1.SchemeGroupVersion.Version] = p.storage(rbacapiv1alpha1.SchemeGroupVersion, apiResourceConfigSource, restOptionsGetter)
  63. }
  64. if apiResourceConfigSource.VersionEnabled(rbacapiv1beta1.SchemeGroupVersion) {
  65. apiGroupInfo.VersionedResourcesStorageMap[rbacapiv1beta1.SchemeGroupVersion.Version] = p.storage(rbacapiv1beta1.SchemeGroupVersion, apiResourceConfigSource, restOptionsGetter)
  66. }
  67. if apiResourceConfigSource.VersionEnabled(rbacapiv1.SchemeGroupVersion) {
  68. apiGroupInfo.VersionedResourcesStorageMap[rbacapiv1.SchemeGroupVersion.Version] = p.storage(rbacapiv1.SchemeGroupVersion, apiResourceConfigSource, restOptionsGetter)
  69. }
  70. return apiGroupInfo, true
  71. }
  72. func (p RESTStorageProvider) storage(version schema.GroupVersion, apiResourceConfigSource serverstorage.APIResourceConfigSource, restOptionsGetter generic.RESTOptionsGetter) map[string]rest.Storage {
  73. storage := map[string]rest.Storage{}
  74. rolesStorage := rolestore.NewREST(restOptionsGetter)
  75. roleBindingsStorage := rolebindingstore.NewREST(restOptionsGetter)
  76. clusterRolesStorage := clusterrolestore.NewREST(restOptionsGetter)
  77. clusterRoleBindingsStorage := clusterrolebindingstore.NewREST(restOptionsGetter)
  78. authorizationRuleResolver := rbacregistryvalidation.NewDefaultRuleResolver(
  79. role.AuthorizerAdapter{Registry: role.NewRegistry(rolesStorage)},
  80. rolebinding.AuthorizerAdapter{Registry: rolebinding.NewRegistry(roleBindingsStorage)},
  81. clusterrole.AuthorizerAdapter{Registry: clusterrole.NewRegistry(clusterRolesStorage)},
  82. clusterrolebinding.AuthorizerAdapter{Registry: clusterrolebinding.NewRegistry(clusterRoleBindingsStorage)},
  83. )
  84. // roles
  85. storage["roles"] = rolepolicybased.NewStorage(rolesStorage, p.Authorizer, authorizationRuleResolver)
  86. // rolebindings
  87. storage["rolebindings"] = rolebindingpolicybased.NewStorage(roleBindingsStorage, p.Authorizer, authorizationRuleResolver)
  88. // clusterroles
  89. storage["clusterroles"] = clusterrolepolicybased.NewStorage(clusterRolesStorage, p.Authorizer, authorizationRuleResolver)
  90. // clusterrolebindings
  91. storage["clusterrolebindings"] = clusterrolebindingpolicybased.NewStorage(clusterRoleBindingsStorage, p.Authorizer, authorizationRuleResolver)
  92. return storage
  93. }
  94. func (p RESTStorageProvider) PostStartHook() (string, genericapiserver.PostStartHookFunc, error) {
  95. policy := &PolicyData{
  96. ClusterRoles: append(bootstrappolicy.ClusterRoles(), bootstrappolicy.ControllerRoles()...),
  97. ClusterRoleBindings: append(bootstrappolicy.ClusterRoleBindings(), bootstrappolicy.ControllerRoleBindings()...),
  98. Roles: bootstrappolicy.NamespaceRoles(),
  99. RoleBindings: bootstrappolicy.NamespaceRoleBindings(),
  100. ClusterRolesToAggregate: bootstrappolicy.ClusterRolesToAggregate(),
  101. ClusterRoleBindingsToSplit: bootstrappolicy.ClusterRoleBindingsToSplit(),
  102. }
  103. return PostStartHookName, policy.EnsureRBACPolicy(), nil
  104. }
  105. type PolicyData struct {
  106. ClusterRoles []rbacapiv1.ClusterRole
  107. ClusterRoleBindings []rbacapiv1.ClusterRoleBinding
  108. Roles map[string][]rbacapiv1.Role
  109. RoleBindings map[string][]rbacapiv1.RoleBinding
  110. // ClusterRolesToAggregate maps from previous clusterrole name to the new clusterrole name
  111. ClusterRolesToAggregate map[string]string
  112. // ClusterRoleBindingsToSplit maps from previous ClusterRoleBinding Name to a template for the new ClusterRoleBinding
  113. ClusterRoleBindingsToSplit map[string]rbacapiv1.ClusterRoleBinding
  114. }
  115. func (p *PolicyData) EnsureRBACPolicy() genericapiserver.PostStartHookFunc {
  116. return func(hookContext genericapiserver.PostStartHookContext) error {
  117. // intializing roles is really important. On some e2e runs, we've seen cases where etcd is down when the server
  118. // starts, the roles don't initialize, and nothing works.
  119. err := wait.Poll(1*time.Second, 30*time.Second, func() (done bool, err error) {
  120. coreclientset, err := corev1client.NewForConfig(hookContext.LoopbackClientConfig)
  121. if err != nil {
  122. utilruntime.HandleError(fmt.Errorf("unable to initialize client: %v", err))
  123. return false, nil
  124. }
  125. clientset, err := rbacv1client.NewForConfig(hookContext.LoopbackClientConfig)
  126. if err != nil {
  127. utilruntime.HandleError(fmt.Errorf("unable to initialize client: %v", err))
  128. return false, nil
  129. }
  130. // Make sure etcd is responding before we start reconciling
  131. if _, err := clientset.ClusterRoles().List(metav1.ListOptions{}); err != nil {
  132. utilruntime.HandleError(fmt.Errorf("unable to initialize clusterroles: %v", err))
  133. return false, nil
  134. }
  135. if _, err := clientset.ClusterRoleBindings().List(metav1.ListOptions{}); err != nil {
  136. utilruntime.HandleError(fmt.Errorf("unable to initialize clusterrolebindings: %v", err))
  137. return false, nil
  138. }
  139. // if the new cluster roles to aggregate do not yet exist, then we need to copy the old roles if they don't exist
  140. // in new locations
  141. if err := primeAggregatedClusterRoles(p.ClusterRolesToAggregate, clientset); err != nil {
  142. utilruntime.HandleError(fmt.Errorf("unable to prime aggregated clusterroles: %v", err))
  143. return false, nil
  144. }
  145. if err := primeSplitClusterRoleBindings(p.ClusterRoleBindingsToSplit, clientset); err != nil {
  146. utilruntime.HandleError(fmt.Errorf("unable to prime split ClusterRoleBindings: %v", err))
  147. return false, nil
  148. }
  149. // ensure bootstrap roles are created or reconciled
  150. for _, clusterRole := range p.ClusterRoles {
  151. opts := reconciliation.ReconcileRoleOptions{
  152. Role: reconciliation.ClusterRoleRuleOwner{ClusterRole: &clusterRole},
  153. Client: reconciliation.ClusterRoleModifier{Client: clientset.ClusterRoles()},
  154. Confirm: true,
  155. }
  156. err := retry.RetryOnConflict(retry.DefaultBackoff, func() error {
  157. result, err := opts.Run()
  158. if err != nil {
  159. return err
  160. }
  161. switch {
  162. case result.Protected && result.Operation != reconciliation.ReconcileNone:
  163. klog.Warningf("skipped reconcile-protected clusterrole.%s/%s with missing permissions: %v", rbac.GroupName, clusterRole.Name, result.MissingRules)
  164. case result.Operation == reconciliation.ReconcileUpdate:
  165. klog.V(2).Infof("updated clusterrole.%s/%s with additional permissions: %v", rbac.GroupName, clusterRole.Name, result.MissingRules)
  166. case result.Operation == reconciliation.ReconcileCreate:
  167. klog.V(2).Infof("created clusterrole.%s/%s", rbac.GroupName, clusterRole.Name)
  168. }
  169. return nil
  170. })
  171. if err != nil {
  172. // don't fail on failures, try to create as many as you can
  173. utilruntime.HandleError(fmt.Errorf("unable to reconcile clusterrole.%s/%s: %v", rbac.GroupName, clusterRole.Name, err))
  174. }
  175. }
  176. // ensure bootstrap rolebindings are created or reconciled
  177. for _, clusterRoleBinding := range p.ClusterRoleBindings {
  178. opts := reconciliation.ReconcileRoleBindingOptions{
  179. RoleBinding: reconciliation.ClusterRoleBindingAdapter{ClusterRoleBinding: &clusterRoleBinding},
  180. Client: reconciliation.ClusterRoleBindingClientAdapter{Client: clientset.ClusterRoleBindings()},
  181. Confirm: true,
  182. }
  183. err := retry.RetryOnConflict(retry.DefaultBackoff, func() error {
  184. result, err := opts.Run()
  185. if err != nil {
  186. return err
  187. }
  188. switch {
  189. case result.Protected && result.Operation != reconciliation.ReconcileNone:
  190. klog.Warningf("skipped reconcile-protected clusterrolebinding.%s/%s with missing subjects: %v", rbac.GroupName, clusterRoleBinding.Name, result.MissingSubjects)
  191. case result.Operation == reconciliation.ReconcileUpdate:
  192. klog.V(2).Infof("updated clusterrolebinding.%s/%s with additional subjects: %v", rbac.GroupName, clusterRoleBinding.Name, result.MissingSubjects)
  193. case result.Operation == reconciliation.ReconcileCreate:
  194. klog.V(2).Infof("created clusterrolebinding.%s/%s", rbac.GroupName, clusterRoleBinding.Name)
  195. case result.Operation == reconciliation.ReconcileRecreate:
  196. klog.V(2).Infof("recreated clusterrolebinding.%s/%s", rbac.GroupName, clusterRoleBinding.Name)
  197. }
  198. return nil
  199. })
  200. if err != nil {
  201. // don't fail on failures, try to create as many as you can
  202. utilruntime.HandleError(fmt.Errorf("unable to reconcile clusterrolebinding.%s/%s: %v", rbac.GroupName, clusterRoleBinding.Name, err))
  203. }
  204. }
  205. // ensure bootstrap namespaced roles are created or reconciled
  206. for namespace, roles := range p.Roles {
  207. for _, role := range roles {
  208. opts := reconciliation.ReconcileRoleOptions{
  209. Role: reconciliation.RoleRuleOwner{Role: &role},
  210. Client: reconciliation.RoleModifier{Client: clientset, NamespaceClient: coreclientset.Namespaces()},
  211. Confirm: true,
  212. }
  213. err := retry.RetryOnConflict(retry.DefaultBackoff, func() error {
  214. result, err := opts.Run()
  215. if err != nil {
  216. return err
  217. }
  218. switch {
  219. case result.Protected && result.Operation != reconciliation.ReconcileNone:
  220. klog.Warningf("skipped reconcile-protected role.%s/%s in %v with missing permissions: %v", rbac.GroupName, role.Name, namespace, result.MissingRules)
  221. case result.Operation == reconciliation.ReconcileUpdate:
  222. klog.V(2).Infof("updated role.%s/%s in %v with additional permissions: %v", rbac.GroupName, role.Name, namespace, result.MissingRules)
  223. case result.Operation == reconciliation.ReconcileCreate:
  224. klog.V(2).Infof("created role.%s/%s in %v", rbac.GroupName, role.Name, namespace)
  225. }
  226. return nil
  227. })
  228. if err != nil {
  229. // don't fail on failures, try to create as many as you can
  230. utilruntime.HandleError(fmt.Errorf("unable to reconcile role.%s/%s in %v: %v", rbac.GroupName, role.Name, namespace, err))
  231. }
  232. }
  233. }
  234. // ensure bootstrap namespaced rolebindings are created or reconciled
  235. for namespace, roleBindings := range p.RoleBindings {
  236. for _, roleBinding := range roleBindings {
  237. opts := reconciliation.ReconcileRoleBindingOptions{
  238. RoleBinding: reconciliation.RoleBindingAdapter{RoleBinding: &roleBinding},
  239. Client: reconciliation.RoleBindingClientAdapter{Client: clientset, NamespaceClient: coreclientset.Namespaces()},
  240. Confirm: true,
  241. }
  242. err := retry.RetryOnConflict(retry.DefaultBackoff, func() error {
  243. result, err := opts.Run()
  244. if err != nil {
  245. return err
  246. }
  247. switch {
  248. case result.Protected && result.Operation != reconciliation.ReconcileNone:
  249. klog.Warningf("skipped reconcile-protected rolebinding.%s/%s in %v with missing subjects: %v", rbac.GroupName, roleBinding.Name, namespace, result.MissingSubjects)
  250. case result.Operation == reconciliation.ReconcileUpdate:
  251. klog.V(2).Infof("updated rolebinding.%s/%s in %v with additional subjects: %v", rbac.GroupName, roleBinding.Name, namespace, result.MissingSubjects)
  252. case result.Operation == reconciliation.ReconcileCreate:
  253. klog.V(2).Infof("created rolebinding.%s/%s in %v", rbac.GroupName, roleBinding.Name, namespace)
  254. case result.Operation == reconciliation.ReconcileRecreate:
  255. klog.V(2).Infof("recreated rolebinding.%s/%s in %v", rbac.GroupName, roleBinding.Name, namespace)
  256. }
  257. return nil
  258. })
  259. if err != nil {
  260. // don't fail on failures, try to create as many as you can
  261. utilruntime.HandleError(fmt.Errorf("unable to reconcile rolebinding.%s/%s in %v: %v", rbac.GroupName, roleBinding.Name, namespace, err))
  262. }
  263. }
  264. }
  265. return true, nil
  266. })
  267. // if we're never able to make it through initialization, kill the API server
  268. if err != nil {
  269. return fmt.Errorf("unable to initialize roles: %v", err)
  270. }
  271. return nil
  272. }
  273. }
  274. func (p RESTStorageProvider) GroupName() string {
  275. return rbac.GroupName
  276. }
  277. // primeAggregatedClusterRoles copies roles that have transitioned to aggregated roles and may need to pick up changes
  278. // that were done to the legacy roles.
  279. func primeAggregatedClusterRoles(clusterRolesToAggregate map[string]string, clusterRoleClient rbacv1client.ClusterRolesGetter) error {
  280. for oldName, newName := range clusterRolesToAggregate {
  281. _, err := clusterRoleClient.ClusterRoles().Get(newName, metav1.GetOptions{})
  282. if err == nil {
  283. continue
  284. }
  285. if !apierrors.IsNotFound(err) {
  286. return err
  287. }
  288. existingRole, err := clusterRoleClient.ClusterRoles().Get(oldName, metav1.GetOptions{})
  289. if apierrors.IsNotFound(err) {
  290. continue
  291. }
  292. if err != nil {
  293. return err
  294. }
  295. if existingRole.AggregationRule != nil {
  296. // the old role already moved to an aggregated role, so there are no custom rules to migrate at this point
  297. return nil
  298. }
  299. klog.V(1).Infof("migrating %v to %v", existingRole.Name, newName)
  300. existingRole.Name = newName
  301. existingRole.ResourceVersion = "" // clear this so the object can be created.
  302. if _, err := clusterRoleClient.ClusterRoles().Create(existingRole); err != nil && !apierrors.IsAlreadyExists(err) {
  303. return err
  304. }
  305. }
  306. return nil
  307. }
  308. // primeSplitClusterRoleBindings ensures the existence of target ClusterRoleBindings
  309. // by copying Subjects, Annotations, and Labels from the specified source
  310. // ClusterRoleBinding, if present.
  311. func primeSplitClusterRoleBindings(clusterRoleBindingToSplit map[string]rbacapiv1.ClusterRoleBinding, clusterRoleBindingClient rbacv1client.ClusterRoleBindingsGetter) error {
  312. for existingBindingName, clusterRoleBindingToCreate := range clusterRoleBindingToSplit {
  313. // If source ClusterRoleBinding does not exist, do nothing.
  314. existingRoleBinding, err := clusterRoleBindingClient.ClusterRoleBindings().Get(existingBindingName, metav1.GetOptions{})
  315. if apierrors.IsNotFound(err) {
  316. continue
  317. }
  318. if err != nil {
  319. return err
  320. }
  321. // If the target ClusterRoleBinding already exists, do nothing.
  322. _, err = clusterRoleBindingClient.ClusterRoleBindings().Get(clusterRoleBindingToCreate.Name, metav1.GetOptions{})
  323. if err == nil {
  324. continue
  325. }
  326. if !apierrors.IsNotFound(err) {
  327. return err
  328. }
  329. // If the source exists, but the target does not,
  330. // copy the subjects, labels, and annotations from the former to create the latter.
  331. klog.V(1).Infof("copying subjects, labels, and annotations from ClusterRoleBinding %q to template %q", existingBindingName, clusterRoleBindingToCreate.Name)
  332. newCRB := clusterRoleBindingToCreate.DeepCopy()
  333. newCRB.Subjects = existingRoleBinding.Subjects
  334. newCRB.Labels = existingRoleBinding.Labels
  335. newCRB.Annotations = existingRoleBinding.Annotations
  336. if _, err := clusterRoleBindingClient.ClusterRoleBindings().Create(newCRB); err != nil && !apierrors.IsAlreadyExists(err) {
  337. return err
  338. }
  339. }
  340. return nil
  341. }