From c96408ab5367af82333157f20226efc7f230ff36 Mon Sep 17 00:00:00 2001 From: Simo Sorce Date: Mon, 3 Jul 2017 10:57:30 -0400 Subject: [PATCH] Proxy {Cluster}Role{Binding}s to Native Kube RBAC Store them as native RBAC Objects via Kubernetes. Also: - Provides backwards compatible Openshift API. - Kills Policy Sync Controller - Removes init of PolicyRegistry - Move helpers closer to their users - Remove TestRBACController - Remove tests that check only PolicyBindings related stuff - hack around TestAuthorizationResolution Signed-off-by: Simo Sorce Signed-off-by: Monis Khan --- pkg/auth/client/impersonate.go | 57 +++++ pkg/auth/client/impersonate_rbac.go | 17 ++ .../controller/authorizationsync/generic.go | 115 --------- .../authorizationsync/generic_test.go | 55 ---- .../origin_to_rbac_clusterrole_controller.go | 173 ------------- ...gin_to_rbac_clusterrole_controller_test.go | 241 ------------------ ...n_to_rbac_clusterrolebinding_controller.go | 173 ------------- ...rbac_clusterrolebinding_controller_test.go | 182 ------------- .../origin_to_rbac_role_controller.go | 178 ------------- .../origin_to_rbac_role_controller_test.go | 218 ---------------- .../origin_to_rbac_rolebinding_controller.go | 178 ------------- ...gin_to_rbac_rolebinding_controller_test.go | 182 ------------- .../registry/clusterrole/proxy.go | 172 +++++++++++++ .../registry/clusterrole/registry_test.go | 5 - .../registry/clusterrolebinding/proxy.go | 172 +++++++++++++ .../clusterrolebinding/registry_test.go | 5 - pkg/authorization/registry/role/proxy.go | 176 +++++++++++++ .../registry/rolebinding/proxy.go | 192 ++++++++++++++ pkg/authorization/registry/util/convert.go | 138 ++++++++++ .../util}/normalize.go | 17 +- pkg/authorization/util/convert/convert.go | 74 ------ pkg/authorization/util/util.go | 91 ------- .../server/admin/overwrite_bootstrappolicy.go | 78 +++++- pkg/cmd/server/origin/controller/config.go | 3 - pkg/cmd/server/origin/controller/security.go | 44 ---- pkg/cmd/server/origin/master_config.go | 7 +- pkg/cmd/server/origin/storage.go | 23 +- .../migrate/authorization/authorization.go | 18 +- .../delegated/delegated_test.go | 87 ------- .../templateinstance_impersonation.go | 11 - test/integration/authorization_test.go | 6 +- test/integration/etcd_storage_path_test.go | 109 ++++---- test/integration/project_request_test.go | 6 +- test/integration/rbac_controller_test.go | 215 ---------------- test/integration/restrictusers_test.go | 14 - 35 files changed, 1078 insertions(+), 2354 deletions(-) create mode 100644 pkg/auth/client/impersonate_rbac.go delete mode 100644 pkg/authorization/controller/authorizationsync/generic.go delete mode 100644 pkg/authorization/controller/authorizationsync/generic_test.go delete mode 100644 pkg/authorization/controller/authorizationsync/origin_to_rbac_clusterrole_controller.go delete mode 100644 pkg/authorization/controller/authorizationsync/origin_to_rbac_clusterrole_controller_test.go delete mode 100644 pkg/authorization/controller/authorizationsync/origin_to_rbac_clusterrolebinding_controller.go delete mode 100644 pkg/authorization/controller/authorizationsync/origin_to_rbac_clusterrolebinding_controller_test.go delete mode 100644 pkg/authorization/controller/authorizationsync/origin_to_rbac_role_controller.go delete mode 100644 pkg/authorization/controller/authorizationsync/origin_to_rbac_role_controller_test.go delete mode 100644 pkg/authorization/controller/authorizationsync/origin_to_rbac_rolebinding_controller.go delete mode 100644 pkg/authorization/controller/authorizationsync/origin_to_rbac_rolebinding_controller_test.go create mode 100644 pkg/authorization/registry/clusterrole/proxy.go delete mode 100644 pkg/authorization/registry/clusterrole/registry_test.go create mode 100644 pkg/authorization/registry/clusterrolebinding/proxy.go delete mode 100644 pkg/authorization/registry/clusterrolebinding/registry_test.go create mode 100644 pkg/authorization/registry/role/proxy.go create mode 100644 pkg/authorization/registry/rolebinding/proxy.go create mode 100644 pkg/authorization/registry/util/convert.go rename pkg/authorization/{controller/authorizationsync => registry/util}/normalize.go (89%) delete mode 100644 pkg/authorization/util/convert/convert.go delete mode 100644 pkg/cmd/server/origin/controller/security.go delete mode 100644 pkg/project/registry/projectrequest/delegated/delegated_test.go delete mode 100644 test/integration/rbac_controller_test.go diff --git a/pkg/auth/client/impersonate.go b/pkg/auth/client/impersonate.go index ea51fa212383..844a831921f2 100644 --- a/pkg/auth/client/impersonate.go +++ b/pkg/auth/client/impersonate.go @@ -3,8 +3,11 @@ package client import ( "net/http" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/types" "k8s.io/apiserver/pkg/authentication/user" restclient "k8s.io/client-go/rest" + "k8s.io/client-go/util/flowcontrol" kclientset "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset" authenticationapi "github.com/openshift/origin/pkg/auth/api" @@ -59,3 +62,57 @@ func NewImpersonatingKubernetesClientset(user user.Info, config restclient.Confi impersonatingConfig := NewImpersonatingConfig(user, config) return kclientset.NewForConfig(&impersonatingConfig) } + +func NewImpersonatingKubernetesClientsetFromRESTClient(user user.Info, client restclient.Interface) kclientset.Interface { + return kclientset.New(NewImpersonatingRESTClient(user, client)) +} + +// impersonatingRESTClient sets impersonating user, groups, and scopes headers per request +type impersonatingRESTClient struct { + user user.Info + delegate restclient.Interface +} + +func NewImpersonatingRESTClient(user user.Info, client restclient.Interface) restclient.Interface { + return &impersonatingRESTClient{user: user, delegate: client} +} + +// Verb does the impersonation per request by setting the proper headers +func (c impersonatingRESTClient) impersonate(req *restclient.Request) *restclient.Request { + req.SetHeader(authenticationapi.ImpersonateUserHeader, c.user.GetName()) + req.SetHeader(authenticationapi.ImpersonateGroupHeader, c.user.GetGroups()...) + req.SetHeader(authenticationapi.ImpersonateUserScopeHeader, c.user.GetExtra()[authorizationapi.ScopesKey]...) + return req +} + +func (c impersonatingRESTClient) Verb(verb string) *restclient.Request { + return c.impersonate(c.delegate.Verb(verb)) +} + +func (c impersonatingRESTClient) Post() *restclient.Request { + return c.impersonate(c.delegate.Post()) +} + +func (c impersonatingRESTClient) Put() *restclient.Request { + return c.impersonate(c.delegate.Put()) +} + +func (c impersonatingRESTClient) Patch(pt types.PatchType) *restclient.Request { + return c.impersonate(c.delegate.Patch(pt)) +} + +func (c impersonatingRESTClient) Get() *restclient.Request { + return c.impersonate(c.delegate.Get()) +} + +func (c impersonatingRESTClient) Delete() *restclient.Request { + return c.impersonate(c.delegate.Delete()) +} + +func (c impersonatingRESTClient) APIVersion() schema.GroupVersion { + return c.delegate.APIVersion() +} + +func (c impersonatingRESTClient) GetRateLimiter() flowcontrol.RateLimiter { + return c.delegate.GetRateLimiter() +} diff --git a/pkg/auth/client/impersonate_rbac.go b/pkg/auth/client/impersonate_rbac.go new file mode 100644 index 000000000000..bd99ddf4f570 --- /dev/null +++ b/pkg/auth/client/impersonate_rbac.go @@ -0,0 +1,17 @@ +package client + +import ( + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apiserver/pkg/endpoints/request" + apirequest "k8s.io/apiserver/pkg/endpoints/request" + "k8s.io/client-go/rest" + rbacinternalversion "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/rbac/internalversion" +) + +func NewImpersonatingRBACFromContext(ctx apirequest.Context, restclient rest.Interface) (rbacinternalversion.RbacInterface, error) { + user, ok := request.UserFrom(ctx) + if !ok { + return nil, apierrors.NewBadRequest("user missing from context") + } + return rbacinternalversion.New(NewImpersonatingRESTClient(user, restclient)), nil +} diff --git a/pkg/authorization/controller/authorizationsync/generic.go b/pkg/authorization/controller/authorizationsync/generic.go deleted file mode 100644 index 652a45de8864..000000000000 --- a/pkg/authorization/controller/authorizationsync/generic.go +++ /dev/null @@ -1,115 +0,0 @@ -package authorizationsync - -import ( - "fmt" - "time" - - "github.com/golang/glog" - - "k8s.io/apimachinery/pkg/conversion" - "k8s.io/apimachinery/pkg/runtime" - utilruntime "k8s.io/apimachinery/pkg/util/runtime" - "k8s.io/apimachinery/pkg/util/wait" - "k8s.io/client-go/tools/cache" - "k8s.io/client-go/util/workqueue" - "k8s.io/kubernetes/pkg/controller" -) - -// genericController provides some boilerplate for the 4 (soon to be 8) controllers. -// They do very simple "listen, wait, work" flows. -type genericController struct { - name string - cachesSynced cache.InformerSynced - syncFunc func(key string) error - - queue workqueue.RateLimitingInterface -} - -func (c *genericController) Run(workers int, stopCh <-chan struct{}) { - defer utilruntime.HandleCrash() - defer c.queue.ShutDown() - defer glog.Infof("Shutting %v controller", c.name) - - glog.Infof("Starting %v controller", c.name) - - if !cache.WaitForCacheSync(stopCh, c.cachesSynced) { - utilruntime.HandleError(fmt.Errorf("%v: timed out waiting for caches to sync", c.name)) - return - } - - for i := 0; i < workers; i++ { - go wait.Until(c.runWorker, time.Second, stopCh) - } - - <-stopCh -} - -func (c *genericController) runWorker() { - for c.processNextWorkItem() { - } -} - -func (c *genericController) processNextWorkItem() bool { - key, quit := c.queue.Get() - if quit { - return false - } - defer c.queue.Done(key) - - err := c.syncFunc(key.(string)) - if err == nil { - c.queue.Forget(key) - return true - } - - utilruntime.HandleError(fmt.Errorf("%v: %v failed with : %v", c.name, key, err)) - c.queue.AddRateLimited(key) - - return true -} - -func naiveEventHandler(queue workqueue.Interface) cache.ResourceEventHandler { - return cache.ResourceEventHandlerFuncs{ - AddFunc: func(obj interface{}) { - key, err := controller.KeyFunc(obj) - if err != nil { - utilruntime.HandleError(err) - return - } - queue.Add(key) - }, - UpdateFunc: func(old, cur interface{}) { - key, err := controller.KeyFunc(cur) - if err != nil { - utilruntime.HandleError(err) - return - } - queue.Add(key) - }, - DeleteFunc: func(obj interface{}) { - key, err := getDeleteKey(obj) - if err != nil { - utilruntime.HandleError(err) - return - } - queue.Add(key) - }, - } -} - -func getDeleteKey(uncast interface{}) (string, error) { - obj, ok := uncast.(runtime.Object) - if !ok { - tombstone, ok := uncast.(cache.DeletedFinalStateUnknown) - if !ok { - return "", fmt.Errorf("Couldn't get object from tombstone %#v", uncast) - } - obj, ok = tombstone.Obj.(runtime.Object) - if !ok { - return "", fmt.Errorf("Tombstone contained object that is not a runtime.Object %#v", uncast) - } - } - return controller.KeyFunc(obj) -} - -var cloner = conversion.NewCloner() diff --git a/pkg/authorization/controller/authorizationsync/generic_test.go b/pkg/authorization/controller/authorizationsync/generic_test.go deleted file mode 100644 index 33f39c194286..000000000000 --- a/pkg/authorization/controller/authorizationsync/generic_test.go +++ /dev/null @@ -1,55 +0,0 @@ -package authorizationsync - -import ( - "fmt" - - clienttesting "k8s.io/client-go/testing" -) - -func ensureSingleCreateAction(actions []clienttesting.Action) (clienttesting.CreateAction, error) { - // ought to have one action writing status - if len(actions) != 1 { - return nil, fmt.Errorf("expected %v, got %v", 1, actions) - } - - action, ok := actions[0].(clienttesting.CreateAction) - if !ok { - return nil, fmt.Errorf("expected %v, got %v", "create", actions[0]) - } - - return action, nil -} - -func ensureSingleUpdateAction(actions []clienttesting.Action) (clienttesting.UpdateAction, error) { - // ought to have one action writing status - if len(actions) != 1 { - return nil, fmt.Errorf("expected %v, got %v", 1, actions) - } - - action, ok := actions[0].(clienttesting.UpdateAction) - if !ok { - return nil, fmt.Errorf("expected %v, got %v", "update", actions[0]) - } - - return action, nil -} - -func ensureSingleDeleteAction(actions []clienttesting.Action) (clienttesting.DeleteAction, error) { - // ought to have one action writing status - if len(actions) != 1 { - return nil, fmt.Errorf("expected %v, got %v", 1, actions) - } - - action, ok := actions[0].(clienttesting.DeleteAction) - if !ok { - return nil, fmt.Errorf("expected %v, got %v", "update", actions[0]) - } - - return action, nil -} - -// reactionMatch used to add reaction funcs -type reactionMatch struct { - verb string - resource string -} diff --git a/pkg/authorization/controller/authorizationsync/origin_to_rbac_clusterrole_controller.go b/pkg/authorization/controller/authorizationsync/origin_to_rbac_clusterrole_controller.go deleted file mode 100644 index b358c2416e87..000000000000 --- a/pkg/authorization/controller/authorizationsync/origin_to_rbac_clusterrole_controller.go +++ /dev/null @@ -1,173 +0,0 @@ -package authorizationsync - -import ( - "fmt" - - "github.com/golang/glog" - - apierrors "k8s.io/apimachinery/pkg/api/errors" - utilruntime "k8s.io/apimachinery/pkg/util/runtime" - "k8s.io/apimachinery/pkg/util/sets" - "k8s.io/client-go/tools/cache" - "k8s.io/client-go/util/workqueue" - rbacclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/rbac/internalversion" - rbacinformers "k8s.io/kubernetes/pkg/client/informers/informers_generated/internalversion/rbac/internalversion" - rbaclister "k8s.io/kubernetes/pkg/client/listers/rbac/internalversion" - "k8s.io/kubernetes/pkg/controller" - - authorizationapi "github.com/openshift/origin/pkg/authorization/apis/authorization" - origininformers "github.com/openshift/origin/pkg/authorization/generated/informers/internalversion/authorization/internalversion" - originlister "github.com/openshift/origin/pkg/authorization/generated/listers/authorization/internalversion" -) - -type OriginClusterRoleToRBACClusterRoleController struct { - rbacClient rbacclient.ClusterRolesGetter - - rbacLister rbaclister.ClusterRoleLister - originIndexer cache.Indexer - originLister originlister.ClusterRoleLister - - genericController -} - -func NewOriginToRBACClusterRoleController(rbacClusterRoleInformer rbacinformers.ClusterRoleInformer, originClusterPolicyInformer origininformers.ClusterPolicyInformer, rbacClient rbacclient.ClusterRolesGetter) *OriginClusterRoleToRBACClusterRoleController { - originIndexer := cache.NewIndexer(cache.MetaNamespaceKeyFunc, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}) - c := &OriginClusterRoleToRBACClusterRoleController{ - rbacClient: rbacClient, - rbacLister: rbacClusterRoleInformer.Lister(), - originIndexer: originIndexer, - originLister: originlister.NewClusterRoleLister(originIndexer), - - genericController: genericController{ - name: "OriginClusterRoleToRBACClusterRoleController", - cachesSynced: func() bool { - return rbacClusterRoleInformer.Informer().HasSynced() && originClusterPolicyInformer.Informer().HasSynced() - }, - queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "origin-to-rbac-role"), - }, - } - c.genericController.syncFunc = c.syncClusterRole - - rbacClusterRoleInformer.Informer().AddEventHandler(naiveEventHandler(c.queue)) - originClusterPolicyInformer.Informer().AddEventHandler(c.clusterPolicyEventHandler()) - - return c -} - -func (c *OriginClusterRoleToRBACClusterRoleController) syncClusterRole(name string) error { - rbacClusterRole, rbacErr := c.rbacLister.Get(name) - if !apierrors.IsNotFound(rbacErr) && rbacErr != nil { - return rbacErr - } - originClusterRole, originErr := c.originLister.Get(name) - if !apierrors.IsNotFound(originErr) && originErr != nil { - return originErr - } - - // if neither role exists, return - if apierrors.IsNotFound(rbacErr) && apierrors.IsNotFound(originErr) { - return nil - } - // if the origin role doesn't exist, just delete the rbac role - if apierrors.IsNotFound(originErr) { - // orphan on delete to minimize fanout. We ought to clean the rest via controller too. - deleteErr := c.rbacClient.ClusterRoles().Delete(name, nil) - if apierrors.IsNotFound(deleteErr) { - return nil - } - return deleteErr - } - - // determine if we need to create, update or do nothing - equivalentClusterRole, err := ConvertToRBACClusterRole(originClusterRole) - if err != nil { - return err - } - - // if we're missing the rbacClusterRole, create it - if apierrors.IsNotFound(rbacErr) { - _, err := c.rbacClient.ClusterRoles().Create(equivalentClusterRole) - return err - } - - // if they are not equal, we need to update - if PrepareForUpdateClusterRole(equivalentClusterRole, rbacClusterRole) { - glog.V(1).Infof("writing RBAC clusterrole %v", name) - _, err := c.rbacClient.ClusterRoles().Update(equivalentClusterRole) - // if the update was invalid, we're probably changing an immutable field or something like that - // either way, the existing object is wrong. Delete it and try again. - if apierrors.IsInvalid(err) { - c.rbacClient.ClusterRoles().Delete(name, nil) // ignore delete error - } - return err - } - - // they are equal so we have no work to do - return nil -} - -func (c *OriginClusterRoleToRBACClusterRoleController) clusterPolicyEventHandler() cache.ResourceEventHandler { - return cache.ResourceEventHandlerFuncs{ - AddFunc: func(obj interface{}) { - originContainerObj := obj.(*authorizationapi.ClusterPolicy) - for _, originObj := range originContainerObj.Roles { - c.originIndexer.Add(originObj) - key, err := controller.KeyFunc(originObj) - if err != nil { - utilruntime.HandleError(err) - continue - } - c.queue.Add(key) - } - }, - UpdateFunc: func(old, cur interface{}) { - curKeys := sets.NewString() - for _, originObj := range cur.(*authorizationapi.ClusterPolicy).Roles { - c.originIndexer.Add(originObj) - key, err := controller.KeyFunc(originObj) - if err != nil { - utilruntime.HandleError(err) - continue - } - c.queue.Add(key) - curKeys.Insert(key) - } - for _, originObj := range old.(*authorizationapi.ClusterPolicy).Roles { - key, err := controller.KeyFunc(originObj) - if err != nil { - utilruntime.HandleError(err) - continue - } - if !curKeys.Has(key) { - c.originIndexer.Delete(originObj) - c.queue.Add(key) - } - } - }, - DeleteFunc: func(obj interface{}) { - originContainerObj, ok := obj.(*authorizationapi.ClusterPolicy) - if !ok { - tombstone, ok := obj.(cache.DeletedFinalStateUnknown) - if !ok { - utilruntime.HandleError(fmt.Errorf("Couldn't get object from tombstone %#v", obj)) - return - } - originContainerObj, ok = tombstone.Obj.(*authorizationapi.ClusterPolicy) - if !ok { - utilruntime.HandleError(fmt.Errorf("Tombstone contained object that is not a runtime.Object %#v", obj)) - return - } - } - - for _, originObj := range originContainerObj.Roles { - c.originIndexer.Delete(originObj) - key, err := controller.KeyFunc(originObj) - if err != nil { - utilruntime.HandleError(err) - continue - } - c.queue.Add(key) - } - }, - } -} diff --git a/pkg/authorization/controller/authorizationsync/origin_to_rbac_clusterrole_controller_test.go b/pkg/authorization/controller/authorizationsync/origin_to_rbac_clusterrole_controller_test.go deleted file mode 100644 index 253465cbc2dc..000000000000 --- a/pkg/authorization/controller/authorizationsync/origin_to_rbac_clusterrole_controller_test.go +++ /dev/null @@ -1,241 +0,0 @@ -package authorizationsync - -import ( - "fmt" - "strings" - "testing" - - apiequality "k8s.io/apimachinery/pkg/api/equality" - apierrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/util/sets" - clienttesting "k8s.io/client-go/testing" - "k8s.io/client-go/tools/cache" - "k8s.io/kubernetes/pkg/apis/rbac" - "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake" - rbaclister "k8s.io/kubernetes/pkg/client/listers/rbac/internalversion" - - authorizationapi "github.com/openshift/origin/pkg/authorization/apis/authorization" - originlister "github.com/openshift/origin/pkg/authorization/generated/listers/authorization/internalversion" -) - -func TestSyncClusterRole(t *testing.T) { - tests := []struct { - name string - - key string - startingRBAC []*rbac.ClusterRole - startingOrigin []*authorizationapi.ClusterRole - reactions map[reactionMatch]clienttesting.ReactionFunc - - actionCheck func([]clienttesting.Action) error - expectedError string - }{ - { - name: "no action on missing both", - key: "resource-01", - actionCheck: func(actions []clienttesting.Action) error { - if len(actions) != 0 { - return fmt.Errorf("expected %v, got %v", 0, actions) - } - return nil - }, - }, - { - name: "simple create", - key: "resource-01", - startingOrigin: []*authorizationapi.ClusterRole{ - {ObjectMeta: metav1.ObjectMeta{Name: "resource-01"}}, - }, - actionCheck: func(actions []clienttesting.Action) error { - action, err := ensureSingleCreateAction(actions) - if err != nil { - return err - } - if e, a := "resource-01", action.GetObject().(*rbac.ClusterRole).Name; e != a { - return fmt.Errorf("expected %v, got %v", e, a) - } - return nil - }, - }, - { - name: "simple create with normalization", - key: "resource-01", - startingOrigin: []*authorizationapi.ClusterRole{ - { - ObjectMeta: metav1.ObjectMeta{Name: "resource-01"}, - Rules: []authorizationapi.PolicyRule{ - { - Verbs: sets.NewString("CREATE"), - Resources: sets.NewString("NAMESPACE"), - APIGroups: []string{"V2"}, - }, - }, - }, - }, - actionCheck: func(actions []clienttesting.Action) error { - action, err := ensureSingleCreateAction(actions) - if err != nil { - return err - } - rbacRole := action.GetObject().(*rbac.ClusterRole) - if e, a := "resource-01", rbacRole.Name; e != a { - return fmt.Errorf("expected %v, got %v", e, a) - } - expectedRBACRules := []rbac.PolicyRule{ - { - Verbs: []string{"create"}, - Resources: []string{"namespace"}, - APIGroups: []string{"v2"}, - }, - } - if !apiequality.Semantic.DeepEqual(expectedRBACRules, rbacRole.Rules) { - return fmt.Errorf("expected %v, got %v", expectedRBACRules, rbacRole.Rules) - } - return nil - }, - }, - { - name: "delete on missing origin", - key: "resource-01", - startingRBAC: []*rbac.ClusterRole{ - {ObjectMeta: metav1.ObjectMeta{Name: "resource-01"}}, - }, - actionCheck: func(actions []clienttesting.Action) error { - action, err := ensureSingleDeleteAction(actions) - if err != nil { - return err - } - if e, a := "resource-01", action.GetName(); e != a { - return fmt.Errorf("expected %v, got %v", e, a) - } - return nil - }, - }, - { - name: "simple update", - key: "resource-01", - startingRBAC: []*rbac.ClusterRole{ - {ObjectMeta: metav1.ObjectMeta{Name: "resource-01"}}, - }, - startingOrigin: []*authorizationapi.ClusterRole{ - {ObjectMeta: metav1.ObjectMeta{Name: "resource-01", Annotations: map[string]string{"foo": "different"}}}, - }, - actionCheck: func(actions []clienttesting.Action) error { - action, err := ensureSingleUpdateAction(actions) - if err != nil { - return err - } - if e, a := "resource-01", action.GetObject().(*rbac.ClusterRole).Name; e != a { - return fmt.Errorf("expected %v, got %v", e, a) - } - return nil - }, - }, - { - name: "update with annotation transform", - key: "resource-01", - startingRBAC: []*rbac.ClusterRole{ - {ObjectMeta: metav1.ObjectMeta{Name: "resource-01"}}, - }, - startingOrigin: []*authorizationapi.ClusterRole{ - {ObjectMeta: metav1.ObjectMeta{Name: "resource-01", Annotations: map[string]string{"openshift.io/reconcile-protect": "true"}}}, - }, - actionCheck: func(actions []clienttesting.Action) error { - action, err := ensureSingleUpdateAction(actions) - if err != nil { - return err - } - if e, a := "resource-01", action.GetObject().(*rbac.ClusterRole).Name; e != a { - return fmt.Errorf("expected %v, got %v", e, a) - } - if e, a := "false", action.GetObject().(*rbac.ClusterRole).Annotations["rbac.authorization.kubernetes.io/autoupdate"]; e != a { - return fmt.Errorf("expected %v, got %v", e, a) - } - return nil - }, - }, - { - name: "no action on zero diff", - key: "resource-01", - startingRBAC: []*rbac.ClusterRole{ - {ObjectMeta: metav1.ObjectMeta{Name: "resource-01"}}, - }, - startingOrigin: []*authorizationapi.ClusterRole{ - {ObjectMeta: metav1.ObjectMeta{Name: "resource-01"}}, - }, - actionCheck: func(actions []clienttesting.Action) error { - if len(actions) != 0 { - return fmt.Errorf("expected %v, got %v", 0, actions) - } - return nil - }, - }, - { - name: "invalid update", - key: "resource-01", - startingRBAC: []*rbac.ClusterRole{ - {ObjectMeta: metav1.ObjectMeta{Name: "resource-01"}}, - }, - startingOrigin: []*authorizationapi.ClusterRole{ - {ObjectMeta: metav1.ObjectMeta{Name: "resource-01", Annotations: map[string]string{"foo": "different"}}}, - }, - actionCheck: func(actions []clienttesting.Action) error { - if len(actions) != 2 { - return fmt.Errorf("expected update then delete, got %v", actions) - } - if _, ok := actions[0].(clienttesting.UpdateAction); !ok { - return fmt.Errorf("expected update, got %v", actions) - } - if _, ok := actions[1].(clienttesting.DeleteAction); !ok { - return fmt.Errorf("expected delete, got %v", actions) - } - return nil - }, - reactions: map[reactionMatch]clienttesting.ReactionFunc{ - {verb: "update", resource: "clusterroles"}: func(action clienttesting.Action) (handled bool, ret runtime.Object, err error) { - return true, nil, apierrors.NewInvalid(rbac.Kind("ClusterRole"), "dummy", nil) - }, - }, - expectedError: "is invalid", - }, - } - - for _, tc := range tests { - objs := []runtime.Object{} - rbacIndexer := cache.NewIndexer(cache.MetaNamespaceKeyFunc, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}) - originIndexer := cache.NewIndexer(cache.MetaNamespaceKeyFunc, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}) - for _, obj := range tc.startingRBAC { - rbacIndexer.Add(obj) - objs = append(objs, obj) - } - for _, obj := range tc.startingOrigin { - originIndexer.Add(obj) - } - fakeClient := fake.NewSimpleClientset(objs...) - for reactionMatch, action := range tc.reactions { - fakeClient.PrependReactor(reactionMatch.verb, reactionMatch.resource, action) - } - - c := &OriginClusterRoleToRBACClusterRoleController{ - rbacClient: fakeClient.Rbac(), - rbacLister: rbaclister.NewClusterRoleLister(rbacIndexer), - originLister: originlister.NewClusterRoleLister(originIndexer), - } - err := c.syncClusterRole(tc.key) - switch { - case len(tc.expectedError) == 0 && err == nil: - case len(tc.expectedError) == 0 && err != nil: - t.Errorf("%s: %v", tc.name, err) - case len(tc.expectedError) != 0 && err == nil: - t.Errorf("%s: missing %v", tc.name, tc.expectedError) - case len(tc.expectedError) != 0 && err != nil && !strings.Contains(err.Error(), tc.expectedError): - t.Errorf("%s: expected %v, got %v", tc.name, tc.expectedError, err) - } - - if err := tc.actionCheck(fakeClient.Actions()); err != nil { - t.Errorf("%s: %v", tc.name, err) - } - } -} diff --git a/pkg/authorization/controller/authorizationsync/origin_to_rbac_clusterrolebinding_controller.go b/pkg/authorization/controller/authorizationsync/origin_to_rbac_clusterrolebinding_controller.go deleted file mode 100644 index 27af1c79ab38..000000000000 --- a/pkg/authorization/controller/authorizationsync/origin_to_rbac_clusterrolebinding_controller.go +++ /dev/null @@ -1,173 +0,0 @@ -package authorizationsync - -import ( - "fmt" - - "github.com/golang/glog" - - apierrors "k8s.io/apimachinery/pkg/api/errors" - utilruntime "k8s.io/apimachinery/pkg/util/runtime" - "k8s.io/apimachinery/pkg/util/sets" - "k8s.io/client-go/tools/cache" - "k8s.io/client-go/util/workqueue" - rbacclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/rbac/internalversion" - rbacinformers "k8s.io/kubernetes/pkg/client/informers/informers_generated/internalversion/rbac/internalversion" - rbaclister "k8s.io/kubernetes/pkg/client/listers/rbac/internalversion" - "k8s.io/kubernetes/pkg/controller" - - authorizationapi "github.com/openshift/origin/pkg/authorization/apis/authorization" - origininformers "github.com/openshift/origin/pkg/authorization/generated/informers/internalversion/authorization/internalversion" - originlister "github.com/openshift/origin/pkg/authorization/generated/listers/authorization/internalversion" -) - -type OriginClusterRoleBindingToRBACClusterRoleBindingController struct { - rbacClient rbacclient.ClusterRoleBindingsGetter - - rbacLister rbaclister.ClusterRoleBindingLister - originIndexer cache.Indexer - originLister originlister.ClusterRoleBindingLister - - genericController -} - -func NewOriginToRBACClusterRoleBindingController(rbacClusterRoleBindingInformer rbacinformers.ClusterRoleBindingInformer, originClusterPolicyBindingInformer origininformers.ClusterPolicyBindingInformer, rbacClient rbacclient.ClusterRoleBindingsGetter) *OriginClusterRoleBindingToRBACClusterRoleBindingController { - originIndexer := cache.NewIndexer(cache.MetaNamespaceKeyFunc, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}) - c := &OriginClusterRoleBindingToRBACClusterRoleBindingController{ - rbacClient: rbacClient, - rbacLister: rbacClusterRoleBindingInformer.Lister(), - originIndexer: originIndexer, - originLister: originlister.NewClusterRoleBindingLister(originIndexer), - - genericController: genericController{ - name: "OriginClusterRoleBindingToRBACClusterRoleBindingController", - cachesSynced: func() bool { - return rbacClusterRoleBindingInformer.Informer().HasSynced() && originClusterPolicyBindingInformer.Informer().HasSynced() - }, - queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "origin-to-rbac-rolebinding"), - }, - } - c.genericController.syncFunc = c.syncClusterRoleBinding - - rbacClusterRoleBindingInformer.Informer().AddEventHandler(naiveEventHandler(c.queue)) - originClusterPolicyBindingInformer.Informer().AddEventHandler(c.clusterPolicyBindingEventHandler()) - - return c -} - -func (c *OriginClusterRoleBindingToRBACClusterRoleBindingController) syncClusterRoleBinding(name string) error { - rbacClusterRoleBinding, rbacErr := c.rbacLister.Get(name) - if !apierrors.IsNotFound(rbacErr) && rbacErr != nil { - return rbacErr - } - originClusterRoleBinding, originErr := c.originLister.Get(name) - if !apierrors.IsNotFound(originErr) && originErr != nil { - return originErr - } - - // if neither roleBinding exists, return - if apierrors.IsNotFound(rbacErr) && apierrors.IsNotFound(originErr) { - return nil - } - // if the origin roleBinding doesn't exist, just delete the rbac roleBinding - if apierrors.IsNotFound(originErr) { - // orphan on delete to minimize fanout. We ought to clean the rest via controller too. - deleteErr := c.rbacClient.ClusterRoleBindings().Delete(name, nil) - if apierrors.IsNotFound(deleteErr) { - return nil - } - return deleteErr - } - - // determine if we need to create, update or do nothing - equivalentClusterRoleBinding, err := ConvertToRBACClusterRoleBinding(originClusterRoleBinding) - if err != nil { - return err - } - - // if we're missing the rbacClusterRoleBinding, create it - if apierrors.IsNotFound(rbacErr) { - _, err := c.rbacClient.ClusterRoleBindings().Create(equivalentClusterRoleBinding) - return err - } - - // if they are not equal, we need to update - if PrepareForUpdateClusterRoleBinding(equivalentClusterRoleBinding, rbacClusterRoleBinding) { - glog.V(1).Infof("writing RBAC clusterrolebinding %v", name) - _, err := c.rbacClient.ClusterRoleBindings().Update(equivalentClusterRoleBinding) - // if the update was invalid, we're probably changing an immutable field or something like that - // either way, the existing object is wrong. Delete it and try again. - if apierrors.IsInvalid(err) { - c.rbacClient.ClusterRoleBindings().Delete(name, nil) // ignore delete error - } - return err - } - - // they are equal so we have no work to do - return nil -} - -func (c *OriginClusterRoleBindingToRBACClusterRoleBindingController) clusterPolicyBindingEventHandler() cache.ResourceEventHandler { - return cache.ResourceEventHandlerFuncs{ - AddFunc: func(obj interface{}) { - originContainerObj := obj.(*authorizationapi.ClusterPolicyBinding) - for _, originObj := range originContainerObj.RoleBindings { - c.originIndexer.Add(originObj) - key, err := controller.KeyFunc(originObj) - if err != nil { - utilruntime.HandleError(err) - continue - } - c.queue.Add(key) - } - }, - UpdateFunc: func(old, cur interface{}) { - curKeys := sets.NewString() - for _, originObj := range cur.(*authorizationapi.ClusterPolicyBinding).RoleBindings { - c.originIndexer.Add(originObj) - key, err := controller.KeyFunc(originObj) - if err != nil { - utilruntime.HandleError(err) - continue - } - c.queue.Add(key) - curKeys.Insert(key) - } - for _, originObj := range old.(*authorizationapi.ClusterPolicyBinding).RoleBindings { - key, err := controller.KeyFunc(originObj) - if err != nil { - utilruntime.HandleError(err) - continue - } - if !curKeys.Has(key) { - c.originIndexer.Delete(originObj) - c.queue.Add(key) - } - } - }, - DeleteFunc: func(obj interface{}) { - originContainerObj, ok := obj.(*authorizationapi.ClusterPolicyBinding) - if !ok { - tombstone, ok := obj.(cache.DeletedFinalStateUnknown) - if !ok { - utilruntime.HandleError(fmt.Errorf("Couldn't get object from tombstone %#v", obj)) - return - } - originContainerObj, ok = tombstone.Obj.(*authorizationapi.ClusterPolicyBinding) - if !ok { - utilruntime.HandleError(fmt.Errorf("Tombstone contained object that is not a runtime.Object %#v", obj)) - return - } - } - - for _, originObj := range originContainerObj.RoleBindings { - c.originIndexer.Delete(originObj) - key, err := controller.KeyFunc(originObj) - if err != nil { - utilruntime.HandleError(err) - continue - } - c.queue.Add(key) - } - }, - } -} diff --git a/pkg/authorization/controller/authorizationsync/origin_to_rbac_clusterrolebinding_controller_test.go b/pkg/authorization/controller/authorizationsync/origin_to_rbac_clusterrolebinding_controller_test.go deleted file mode 100644 index 16eb0a6398a8..000000000000 --- a/pkg/authorization/controller/authorizationsync/origin_to_rbac_clusterrolebinding_controller_test.go +++ /dev/null @@ -1,182 +0,0 @@ -package authorizationsync - -import ( - "fmt" - "strings" - "testing" - - apierrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - clienttesting "k8s.io/client-go/testing" - "k8s.io/client-go/tools/cache" - "k8s.io/kubernetes/pkg/apis/rbac" - "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake" - rbaclister "k8s.io/kubernetes/pkg/client/listers/rbac/internalversion" - - authorizationapi "github.com/openshift/origin/pkg/authorization/apis/authorization" - originlister "github.com/openshift/origin/pkg/authorization/generated/listers/authorization/internalversion" -) - -func TestSyncClusterRoleBinding(t *testing.T) { - tests := []struct { - name string - - key string - startingRBAC []*rbac.ClusterRoleBinding - startingOrigin []*authorizationapi.ClusterRoleBinding - reactions map[reactionMatch]clienttesting.ReactionFunc - - actionCheck func([]clienttesting.Action) error - expectedError string - }{ - { - name: "no action on missing both", - key: "resource-01", - actionCheck: func(actions []clienttesting.Action) error { - if len(actions) != 0 { - return fmt.Errorf("expected %v, got %v", 0, actions) - } - return nil - }, - }, - { - name: "simple create", - key: "resource-01", - startingOrigin: []*authorizationapi.ClusterRoleBinding{ - {ObjectMeta: metav1.ObjectMeta{Name: "resource-01"}}, - }, - actionCheck: func(actions []clienttesting.Action) error { - action, err := ensureSingleCreateAction(actions) - if err != nil { - return err - } - if e, a := "resource-01", action.GetObject().(*rbac.ClusterRoleBinding).Name; e != a { - return fmt.Errorf("expected %v, got %v", e, a) - } - return nil - }, - }, - { - name: "delete on missing origin", - key: "resource-01", - startingRBAC: []*rbac.ClusterRoleBinding{ - {ObjectMeta: metav1.ObjectMeta{Name: "resource-01"}}, - }, - actionCheck: func(actions []clienttesting.Action) error { - action, err := ensureSingleDeleteAction(actions) - if err != nil { - return err - } - if e, a := "resource-01", action.GetName(); e != a { - return fmt.Errorf("expected %v, got %v", e, a) - } - return nil - }, - }, - { - name: "simple update", - key: "resource-01", - startingRBAC: []*rbac.ClusterRoleBinding{ - {ObjectMeta: metav1.ObjectMeta{Name: "resource-01"}}, - }, - startingOrigin: []*authorizationapi.ClusterRoleBinding{ - {ObjectMeta: metav1.ObjectMeta{Name: "resource-01", Annotations: map[string]string{"foo": "different"}}}, - }, - actionCheck: func(actions []clienttesting.Action) error { - action, err := ensureSingleUpdateAction(actions) - if err != nil { - return err - } - if e, a := "resource-01", action.GetObject().(*rbac.ClusterRoleBinding).Name; e != a { - return fmt.Errorf("expected %v, got %v", e, a) - } - return nil - }, - }, - { - name: "no action on zero diff", - key: "resource-01", - startingRBAC: []*rbac.ClusterRoleBinding{ - { - ObjectMeta: metav1.ObjectMeta{Name: "resource-01"}, - RoleRef: rbac.RoleRef{APIGroup: "rbac.authorization.k8s.io", Kind: "ClusterRole"}, - }, - }, - startingOrigin: []*authorizationapi.ClusterRoleBinding{ - {ObjectMeta: metav1.ObjectMeta{Name: "resource-01"}}, - }, - actionCheck: func(actions []clienttesting.Action) error { - if len(actions) != 0 { - return fmt.Errorf("expected %v, got %v", 0, actions) - } - return nil - }, - }, - { - name: "invalid update", - key: "resource-01", - startingRBAC: []*rbac.ClusterRoleBinding{ - {ObjectMeta: metav1.ObjectMeta{Name: "resource-01"}}, - }, - startingOrigin: []*authorizationapi.ClusterRoleBinding{ - {ObjectMeta: metav1.ObjectMeta{Name: "resource-01", Annotations: map[string]string{"foo": "different"}}}, - }, - actionCheck: func(actions []clienttesting.Action) error { - if len(actions) != 2 { - return fmt.Errorf("expected update then delete, got %v", actions) - } - if _, ok := actions[0].(clienttesting.UpdateAction); !ok { - return fmt.Errorf("expected update, got %v", actions) - } - if _, ok := actions[1].(clienttesting.DeleteAction); !ok { - return fmt.Errorf("expected delete, got %v", actions) - } - return nil - }, - reactions: map[reactionMatch]clienttesting.ReactionFunc{ - {verb: "update", resource: "clusterrolebindings"}: func(action clienttesting.Action) (handled bool, ret runtime.Object, err error) { - return true, nil, apierrors.NewInvalid(rbac.Kind("ClusterRoleBinding"), "dummy", nil) - }, - }, - expectedError: "is invalid", - }, - } - - for _, tc := range tests { - objs := []runtime.Object{} - rbacIndexer := cache.NewIndexer(cache.MetaNamespaceKeyFunc, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}) - originIndexer := cache.NewIndexer(cache.MetaNamespaceKeyFunc, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}) - for _, obj := range tc.startingRBAC { - rbacIndexer.Add(obj) - objs = append(objs, obj) - } - for _, obj := range tc.startingOrigin { - originIndexer.Add(obj) - } - fakeClient := fake.NewSimpleClientset(objs...) - for reactionMatch, action := range tc.reactions { - fakeClient.PrependReactor(reactionMatch.verb, reactionMatch.resource, action) - } - - c := &OriginClusterRoleBindingToRBACClusterRoleBindingController{ - rbacClient: fakeClient.Rbac(), - rbacLister: rbaclister.NewClusterRoleBindingLister(rbacIndexer), - originLister: originlister.NewClusterRoleBindingLister(originIndexer), - } - err := c.syncClusterRoleBinding(tc.key) - switch { - case len(tc.expectedError) == 0 && err == nil: - case len(tc.expectedError) == 0 && err != nil: - t.Errorf("%s: %v", tc.name, err) - case len(tc.expectedError) != 0 && err == nil: - t.Errorf("%s: missing %v", tc.name, tc.expectedError) - case len(tc.expectedError) != 0 && err != nil && !strings.Contains(err.Error(), tc.expectedError): - t.Errorf("%s: expected %v, got %v", tc.name, tc.expectedError, err) - } - - if err := tc.actionCheck(fakeClient.Actions()); err != nil { - t.Errorf("%s: %v", tc.name, err) - } - } -} diff --git a/pkg/authorization/controller/authorizationsync/origin_to_rbac_role_controller.go b/pkg/authorization/controller/authorizationsync/origin_to_rbac_role_controller.go deleted file mode 100644 index f26eff01a06c..000000000000 --- a/pkg/authorization/controller/authorizationsync/origin_to_rbac_role_controller.go +++ /dev/null @@ -1,178 +0,0 @@ -package authorizationsync - -import ( - "fmt" - - "github.com/golang/glog" - - apierrors "k8s.io/apimachinery/pkg/api/errors" - utilruntime "k8s.io/apimachinery/pkg/util/runtime" - "k8s.io/apimachinery/pkg/util/sets" - "k8s.io/client-go/tools/cache" - "k8s.io/client-go/util/workqueue" - rbacclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/rbac/internalversion" - rbacinformers "k8s.io/kubernetes/pkg/client/informers/informers_generated/internalversion/rbac/internalversion" - rbaclister "k8s.io/kubernetes/pkg/client/listers/rbac/internalversion" - "k8s.io/kubernetes/pkg/controller" - - authorizationapi "github.com/openshift/origin/pkg/authorization/apis/authorization" - origininformers "github.com/openshift/origin/pkg/authorization/generated/informers/internalversion/authorization/internalversion" - originlister "github.com/openshift/origin/pkg/authorization/generated/listers/authorization/internalversion" -) - -type OriginRoleToRBACRoleController struct { - rbacClient rbacclient.RolesGetter - - rbacLister rbaclister.RoleLister - originIndexer cache.Indexer - originLister originlister.RoleLister - - genericController -} - -func NewOriginToRBACRoleController(rbacRoleInformer rbacinformers.RoleInformer, originPolicyInformer origininformers.PolicyInformer, rbacClient rbacclient.RolesGetter) *OriginRoleToRBACRoleController { - originIndexer := cache.NewIndexer(cache.MetaNamespaceKeyFunc, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}) - c := &OriginRoleToRBACRoleController{ - rbacClient: rbacClient, - rbacLister: rbacRoleInformer.Lister(), - originIndexer: originIndexer, - originLister: originlister.NewRoleLister(originIndexer), - - genericController: genericController{ - name: "OriginRoleToRBACRoleController", - cachesSynced: func() bool { - return rbacRoleInformer.Informer().HasSynced() && originPolicyInformer.Informer().HasSynced() - }, - queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "origin-to-rbac-role"), - }, - } - c.genericController.syncFunc = c.syncRole - - rbacRoleInformer.Informer().AddEventHandler(naiveEventHandler(c.queue)) - originPolicyInformer.Informer().AddEventHandler(c.policyEventHandler()) - - return c -} - -func (c *OriginRoleToRBACRoleController) syncRole(key string) error { - namespace, name, err := cache.SplitMetaNamespaceKey(key) - if err != nil { - return err - } - - rbacRole, rbacErr := c.rbacLister.Roles(namespace).Get(name) - if !apierrors.IsNotFound(rbacErr) && rbacErr != nil { - return rbacErr - } - originRole, originErr := c.originLister.Roles(namespace).Get(name) - if !apierrors.IsNotFound(originErr) && originErr != nil { - return originErr - } - - // if neither role exists, return - if apierrors.IsNotFound(rbacErr) && apierrors.IsNotFound(originErr) { - return nil - } - // if the origin role doesn't exist, just delete the rbac role - if apierrors.IsNotFound(originErr) { - // orphan on delete to minimize fanout. We ought to clean the rest via controller too. - deleteErr := c.rbacClient.Roles(namespace).Delete(name, nil) - if apierrors.IsNotFound(deleteErr) { - return nil - } - return deleteErr - } - - // determine if we need to create, update or do nothing - equivalentRole, err := ConvertToRBACRole(originRole) - if err != nil { - return err - } - - // if we're missing the rbacRole, create it - if apierrors.IsNotFound(rbacErr) { - _, err := c.rbacClient.Roles(namespace).Create(equivalentRole) - return err - } - - // if they are not equal, we need to update - if PrepareForUpdateRole(equivalentRole, rbacRole) { - glog.V(1).Infof("writing RBAC role %v/%v", namespace, name) - _, err := c.rbacClient.Roles(namespace).Update(equivalentRole) - // if the update was invalid, we're probably changing an immutable field or something like that - // either way, the existing object is wrong. Delete it and try again. - if apierrors.IsInvalid(err) { - c.rbacClient.Roles(namespace).Delete(name, nil) // ignore delete error - } - return err - } - - // they are equal so we have no work to do - return nil -} - -func (c *OriginRoleToRBACRoleController) policyEventHandler() cache.ResourceEventHandler { - return cache.ResourceEventHandlerFuncs{ - AddFunc: func(obj interface{}) { - originContainerObj := obj.(*authorizationapi.Policy) - for _, originObj := range originContainerObj.Roles { - c.originIndexer.Add(originObj) - key, err := controller.KeyFunc(originObj) - if err != nil { - utilruntime.HandleError(err) - continue - } - c.queue.Add(key) - } - }, - UpdateFunc: func(old, cur interface{}) { - curKeys := sets.NewString() - for _, originObj := range cur.(*authorizationapi.Policy).Roles { - c.originIndexer.Add(originObj) - key, err := controller.KeyFunc(originObj) - if err != nil { - utilruntime.HandleError(err) - continue - } - c.queue.Add(key) - curKeys.Insert(key) - } - for _, originObj := range old.(*authorizationapi.Policy).Roles { - key, err := controller.KeyFunc(originObj) - if err != nil { - utilruntime.HandleError(err) - continue - } - if !curKeys.Has(key) { - c.originIndexer.Delete(originObj) - c.queue.Add(key) - } - } - }, - DeleteFunc: func(obj interface{}) { - originContainerObj, ok := obj.(*authorizationapi.Policy) - if !ok { - tombstone, ok := obj.(cache.DeletedFinalStateUnknown) - if !ok { - utilruntime.HandleError(fmt.Errorf("Couldn't get object from tombstone %#v", obj)) - return - } - originContainerObj, ok = tombstone.Obj.(*authorizationapi.Policy) - if !ok { - utilruntime.HandleError(fmt.Errorf("Tombstone contained object that is not a runtime.Object %#v", obj)) - return - } - } - - for _, originObj := range originContainerObj.Roles { - c.originIndexer.Delete(originObj) - key, err := controller.KeyFunc(originObj) - if err != nil { - utilruntime.HandleError(err) - continue - } - c.queue.Add(key) - } - }, - } -} diff --git a/pkg/authorization/controller/authorizationsync/origin_to_rbac_role_controller_test.go b/pkg/authorization/controller/authorizationsync/origin_to_rbac_role_controller_test.go deleted file mode 100644 index 086b67895f65..000000000000 --- a/pkg/authorization/controller/authorizationsync/origin_to_rbac_role_controller_test.go +++ /dev/null @@ -1,218 +0,0 @@ -package authorizationsync - -import ( - "fmt" - "strings" - "testing" - - apiequality "k8s.io/apimachinery/pkg/api/equality" - apierrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/util/sets" - clienttesting "k8s.io/client-go/testing" - "k8s.io/client-go/tools/cache" - "k8s.io/kubernetes/pkg/apis/rbac" - "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake" - rbaclister "k8s.io/kubernetes/pkg/client/listers/rbac/internalversion" - - authorizationapi "github.com/openshift/origin/pkg/authorization/apis/authorization" - originlister "github.com/openshift/origin/pkg/authorization/generated/listers/authorization/internalversion" -) - -func TestSyncRole(t *testing.T) { - tests := []struct { - name string - - key string - startingRBAC []*rbac.Role - startingOrigin []*authorizationapi.Role - reactions map[reactionMatch]clienttesting.ReactionFunc - - actionCheck func([]clienttesting.Action) error - expectedError string - }{ - { - name: "no action on missing both", - key: "foo/resource-01", - actionCheck: func(actions []clienttesting.Action) error { - if len(actions) != 0 { - return fmt.Errorf("expected %v, got %v", 0, actions) - } - return nil - }, - }, - { - name: "simple create", - key: "foo/resource-01", - startingOrigin: []*authorizationapi.Role{ - {ObjectMeta: metav1.ObjectMeta{Namespace: "foo", Name: "resource-01"}}, - }, - actionCheck: func(actions []clienttesting.Action) error { - action, err := ensureSingleCreateAction(actions) - if err != nil { - return err - } - if e, a := "resource-01", action.GetObject().(*rbac.Role).Name; e != a { - return fmt.Errorf("expected %v, got %v", e, a) - } - return nil - }, - }, - { - name: "simple create with normalization", - key: "foo/resource-01", - startingOrigin: []*authorizationapi.Role{ - { - ObjectMeta: metav1.ObjectMeta{Namespace: "foo", Name: "resource-01"}, - Rules: []authorizationapi.PolicyRule{ - { - Verbs: sets.NewString("GET"), - Resources: sets.NewString("PODS"), - APIGroups: []string{"V1"}, - }, - }, - }, - }, - actionCheck: func(actions []clienttesting.Action) error { - action, err := ensureSingleCreateAction(actions) - if err != nil { - return err - } - rbacRole := action.GetObject().(*rbac.Role) - if e, a := "resource-01", rbacRole.Name; e != a { - return fmt.Errorf("expected %v, got %v", e, a) - } - expectedRBACRules := []rbac.PolicyRule{ - { - Verbs: []string{"get"}, - Resources: []string{"pods"}, - APIGroups: []string{"v1"}, - }, - } - if !apiequality.Semantic.DeepEqual(expectedRBACRules, rbacRole.Rules) { - return fmt.Errorf("expected %v, got %v", expectedRBACRules, rbacRole.Rules) - } - return nil - }, - }, - { - name: "delete on missing origin", - key: "foo/resource-01", - startingRBAC: []*rbac.Role{ - {ObjectMeta: metav1.ObjectMeta{Namespace: "foo", Name: "resource-01"}}, - }, - actionCheck: func(actions []clienttesting.Action) error { - action, err := ensureSingleDeleteAction(actions) - if err != nil { - return err - } - if e, a := "resource-01", action.GetName(); e != a { - return fmt.Errorf("expected %v, got %v", e, a) - } - return nil - }, - }, - { - name: "simple update", - key: "foo/resource-01", - startingRBAC: []*rbac.Role{ - {ObjectMeta: metav1.ObjectMeta{Namespace: "foo", Name: "resource-01"}}, - }, - startingOrigin: []*authorizationapi.Role{ - {ObjectMeta: metav1.ObjectMeta{Namespace: "foo", Name: "resource-01", Annotations: map[string]string{"foo": "different"}}}, - }, - actionCheck: func(actions []clienttesting.Action) error { - action, err := ensureSingleUpdateAction(actions) - if err != nil { - return err - } - if e, a := "resource-01", action.GetObject().(*rbac.Role).Name; e != a { - return fmt.Errorf("expected %v, got %v", e, a) - } - return nil - }, - }, - { - name: "no action on zero diff", - key: "foo/resource-01", - startingRBAC: []*rbac.Role{ - {ObjectMeta: metav1.ObjectMeta{Namespace: "foo", Name: "resource-01"}}, - }, - startingOrigin: []*authorizationapi.Role{ - {ObjectMeta: metav1.ObjectMeta{Namespace: "foo", Name: "resource-01"}}, - }, - actionCheck: func(actions []clienttesting.Action) error { - if len(actions) != 0 { - return fmt.Errorf("expected %v, got %v", 0, actions) - } - return nil - }, - }, - { - name: "invalid update", - key: "foo/resource-01", - startingRBAC: []*rbac.Role{ - {ObjectMeta: metav1.ObjectMeta{Namespace: "foo", Name: "resource-01"}}, - }, - startingOrigin: []*authorizationapi.Role{ - {ObjectMeta: metav1.ObjectMeta{Namespace: "foo", Name: "resource-01", Annotations: map[string]string{"foo": "different"}}}, - }, - actionCheck: func(actions []clienttesting.Action) error { - if len(actions) != 2 { - return fmt.Errorf("expected update then delete, got %v", actions) - } - if _, ok := actions[0].(clienttesting.UpdateAction); !ok { - return fmt.Errorf("expected update, got %v", actions) - } - if _, ok := actions[1].(clienttesting.DeleteAction); !ok { - return fmt.Errorf("expected delete, got %v", actions) - } - return nil - }, - reactions: map[reactionMatch]clienttesting.ReactionFunc{ - {verb: "update", resource: "roles"}: func(action clienttesting.Action) (handled bool, ret runtime.Object, err error) { - return true, nil, apierrors.NewInvalid(rbac.Kind("Role"), "dummy", nil) - }, - }, - expectedError: "is invalid", - }, - } - - for _, tc := range tests { - objs := []runtime.Object{} - rbacIndexer := cache.NewIndexer(cache.MetaNamespaceKeyFunc, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}) - originIndexer := cache.NewIndexer(cache.MetaNamespaceKeyFunc, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}) - for _, obj := range tc.startingRBAC { - rbacIndexer.Add(obj) - objs = append(objs, obj) - } - for _, obj := range tc.startingOrigin { - originIndexer.Add(obj) - } - fakeClient := fake.NewSimpleClientset(objs...) - for reactionMatch, action := range tc.reactions { - fakeClient.PrependReactor(reactionMatch.verb, reactionMatch.resource, action) - } - - c := &OriginRoleToRBACRoleController{ - rbacClient: fakeClient.Rbac(), - rbacLister: rbaclister.NewRoleLister(rbacIndexer), - originLister: originlister.NewRoleLister(originIndexer), - } - err := c.syncRole(tc.key) - switch { - case len(tc.expectedError) == 0 && err == nil: - case len(tc.expectedError) == 0 && err != nil: - t.Errorf("%s: %v", tc.name, err) - case len(tc.expectedError) != 0 && err == nil: - t.Errorf("%s: missing %v", tc.name, tc.expectedError) - case len(tc.expectedError) != 0 && err != nil && !strings.Contains(err.Error(), tc.expectedError): - t.Errorf("%s: expected %v, got %v", tc.name, tc.expectedError, err) - } - - if err := tc.actionCheck(fakeClient.Actions()); err != nil { - t.Errorf("%s: %v", tc.name, err) - } - } -} diff --git a/pkg/authorization/controller/authorizationsync/origin_to_rbac_rolebinding_controller.go b/pkg/authorization/controller/authorizationsync/origin_to_rbac_rolebinding_controller.go deleted file mode 100644 index dc75f604ef8c..000000000000 --- a/pkg/authorization/controller/authorizationsync/origin_to_rbac_rolebinding_controller.go +++ /dev/null @@ -1,178 +0,0 @@ -package authorizationsync - -import ( - "fmt" - - "github.com/golang/glog" - - apierrors "k8s.io/apimachinery/pkg/api/errors" - utilruntime "k8s.io/apimachinery/pkg/util/runtime" - "k8s.io/apimachinery/pkg/util/sets" - "k8s.io/client-go/tools/cache" - "k8s.io/client-go/util/workqueue" - rbacclient "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/rbac/internalversion" - rbacinformers "k8s.io/kubernetes/pkg/client/informers/informers_generated/internalversion/rbac/internalversion" - rbaclister "k8s.io/kubernetes/pkg/client/listers/rbac/internalversion" - "k8s.io/kubernetes/pkg/controller" - - authorizationapi "github.com/openshift/origin/pkg/authorization/apis/authorization" - origininformers "github.com/openshift/origin/pkg/authorization/generated/informers/internalversion/authorization/internalversion" - originlister "github.com/openshift/origin/pkg/authorization/generated/listers/authorization/internalversion" -) - -type OriginRoleBindingToRBACRoleBindingController struct { - rbacClient rbacclient.RoleBindingsGetter - - rbacLister rbaclister.RoleBindingLister - originIndexer cache.Indexer - originLister originlister.RoleBindingLister - - genericController -} - -func NewOriginToRBACRoleBindingController(rbacRoleBindingInformer rbacinformers.RoleBindingInformer, originPolicyBindingInformer origininformers.PolicyBindingInformer, rbacClient rbacclient.RoleBindingsGetter) *OriginRoleBindingToRBACRoleBindingController { - originIndexer := cache.NewIndexer(cache.MetaNamespaceKeyFunc, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}) - c := &OriginRoleBindingToRBACRoleBindingController{ - rbacClient: rbacClient, - rbacLister: rbacRoleBindingInformer.Lister(), - originIndexer: originIndexer, - originLister: originlister.NewRoleBindingLister(originIndexer), - - genericController: genericController{ - name: "OriginRoleBindingToRBACRoleBindingController", - cachesSynced: func() bool { - return rbacRoleBindingInformer.Informer().HasSynced() && originPolicyBindingInformer.Informer().HasSynced() - }, - queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "origin-to-rbac-rolebinding"), - }, - } - c.genericController.syncFunc = c.syncRoleBinding - - rbacRoleBindingInformer.Informer().AddEventHandler(naiveEventHandler(c.queue)) - originPolicyBindingInformer.Informer().AddEventHandler(c.policyBindingEventHandler()) - - return c -} - -func (c *OriginRoleBindingToRBACRoleBindingController) syncRoleBinding(key string) error { - namespace, name, err := cache.SplitMetaNamespaceKey(key) - if err != nil { - return err - } - - rbacRoleBinding, rbacErr := c.rbacLister.RoleBindings(namespace).Get(name) - if !apierrors.IsNotFound(rbacErr) && rbacErr != nil { - return rbacErr - } - originRoleBinding, originErr := c.originLister.RoleBindings(namespace).Get(name) - if !apierrors.IsNotFound(originErr) && originErr != nil { - return originErr - } - - // if neither roleBinding exists, return - if apierrors.IsNotFound(rbacErr) && apierrors.IsNotFound(originErr) { - return nil - } - // if the origin roleBinding doesn't exist, just delete the rbac roleBinding - if apierrors.IsNotFound(originErr) { - // orphan on delete to minimize fanout. We ought to clean the rest via controller too. - deleteErr := c.rbacClient.RoleBindings(namespace).Delete(name, nil) - if apierrors.IsNotFound(deleteErr) { - return nil - } - return deleteErr - } - - // determine if we need to create, update or do nothing - equivalentRoleBinding, err := ConvertToRBACRoleBinding(originRoleBinding) - if err != nil { - return err - } - - // if we're missing the rbacRoleBinding, create it - if apierrors.IsNotFound(rbacErr) { - _, err := c.rbacClient.RoleBindings(namespace).Create(equivalentRoleBinding) - return err - } - - // if they are not equal, we need to update - if PrepareForUpdateRoleBinding(equivalentRoleBinding, rbacRoleBinding) { - glog.V(1).Infof("writing RBAC rolebinding %v/%v", namespace, name) - _, err := c.rbacClient.RoleBindings(namespace).Update(equivalentRoleBinding) - // if the update was invalid, we're probably changing an immutable field or something like that - // either way, the existing object is wrong. Delete it and try again. - if apierrors.IsInvalid(err) { - c.rbacClient.RoleBindings(namespace).Delete(name, nil) // ignore delete error - } - return err - } - - // they are equal so we have no work to do - return nil -} - -func (c *OriginRoleBindingToRBACRoleBindingController) policyBindingEventHandler() cache.ResourceEventHandler { - return cache.ResourceEventHandlerFuncs{ - AddFunc: func(obj interface{}) { - originContainerObj := obj.(*authorizationapi.PolicyBinding) - for _, originObj := range originContainerObj.RoleBindings { - c.originIndexer.Add(originObj) - key, err := controller.KeyFunc(originObj) - if err != nil { - utilruntime.HandleError(err) - continue - } - c.queue.Add(key) - } - }, - UpdateFunc: func(old, cur interface{}) { - curKeys := sets.NewString() - for _, originObj := range cur.(*authorizationapi.PolicyBinding).RoleBindings { - c.originIndexer.Add(originObj) - key, err := controller.KeyFunc(originObj) - if err != nil { - utilruntime.HandleError(err) - continue - } - c.queue.Add(key) - curKeys.Insert(key) - } - for _, originObj := range old.(*authorizationapi.PolicyBinding).RoleBindings { - key, err := controller.KeyFunc(originObj) - if err != nil { - utilruntime.HandleError(err) - continue - } - if !curKeys.Has(key) { - c.originIndexer.Delete(originObj) - c.queue.Add(key) - } - } - }, - DeleteFunc: func(obj interface{}) { - originContainerObj, ok := obj.(*authorizationapi.PolicyBinding) - if !ok { - tombstone, ok := obj.(cache.DeletedFinalStateUnknown) - if !ok { - utilruntime.HandleError(fmt.Errorf("Couldn't get object from tombstone %#v", obj)) - return - } - originContainerObj, ok = tombstone.Obj.(*authorizationapi.PolicyBinding) - if !ok { - utilruntime.HandleError(fmt.Errorf("Tombstone contained object that is not a runtime.Object %#v", obj)) - return - } - } - - for _, originObj := range originContainerObj.RoleBindings { - c.originIndexer.Delete(originObj) - key, err := controller.KeyFunc(originObj) - if err != nil { - utilruntime.HandleError(err) - continue - } - c.queue.Add(key) - } - }, - } -} diff --git a/pkg/authorization/controller/authorizationsync/origin_to_rbac_rolebinding_controller_test.go b/pkg/authorization/controller/authorizationsync/origin_to_rbac_rolebinding_controller_test.go deleted file mode 100644 index 646c7f78da62..000000000000 --- a/pkg/authorization/controller/authorizationsync/origin_to_rbac_rolebinding_controller_test.go +++ /dev/null @@ -1,182 +0,0 @@ -package authorizationsync - -import ( - "fmt" - "strings" - "testing" - - apierrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - clienttesting "k8s.io/client-go/testing" - "k8s.io/client-go/tools/cache" - "k8s.io/kubernetes/pkg/apis/rbac" - "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/fake" - rbaclister "k8s.io/kubernetes/pkg/client/listers/rbac/internalversion" - - authorizationapi "github.com/openshift/origin/pkg/authorization/apis/authorization" - originlister "github.com/openshift/origin/pkg/authorization/generated/listers/authorization/internalversion" -) - -func TestSyncRoleBinding(t *testing.T) { - tests := []struct { - name string - - key string - startingRBAC []*rbac.RoleBinding - startingOrigin []*authorizationapi.RoleBinding - reactions map[reactionMatch]clienttesting.ReactionFunc - - actionCheck func([]clienttesting.Action) error - expectedError string - }{ - { - name: "no action on missing both", - key: "foo/resource-01", - actionCheck: func(actions []clienttesting.Action) error { - if len(actions) != 0 { - return fmt.Errorf("expected %v, got %v", 0, actions) - } - return nil - }, - }, - { - name: "simple create", - key: "foo/resource-01", - startingOrigin: []*authorizationapi.RoleBinding{ - {ObjectMeta: metav1.ObjectMeta{Namespace: "foo", Name: "resource-01"}}, - }, - actionCheck: func(actions []clienttesting.Action) error { - action, err := ensureSingleCreateAction(actions) - if err != nil { - return err - } - if e, a := "resource-01", action.GetObject().(*rbac.RoleBinding).Name; e != a { - return fmt.Errorf("expected %v, got %v", e, a) - } - return nil - }, - }, - { - name: "delete on missing origin", - key: "foo/resource-01", - startingRBAC: []*rbac.RoleBinding{ - {ObjectMeta: metav1.ObjectMeta{Namespace: "foo", Name: "resource-01"}}, - }, - actionCheck: func(actions []clienttesting.Action) error { - action, err := ensureSingleDeleteAction(actions) - if err != nil { - return err - } - if e, a := "resource-01", action.GetName(); e != a { - return fmt.Errorf("expected %v, got %v", e, a) - } - return nil - }, - }, - { - name: "simple update", - key: "foo/resource-01", - startingRBAC: []*rbac.RoleBinding{ - {ObjectMeta: metav1.ObjectMeta{Namespace: "foo", Name: "resource-01"}}, - }, - startingOrigin: []*authorizationapi.RoleBinding{ - {ObjectMeta: metav1.ObjectMeta{Namespace: "foo", Name: "resource-01", Annotations: map[string]string{"foo": "different"}}}, - }, - actionCheck: func(actions []clienttesting.Action) error { - action, err := ensureSingleUpdateAction(actions) - if err != nil { - return err - } - if e, a := "resource-01", action.GetObject().(*rbac.RoleBinding).Name; e != a { - return fmt.Errorf("expected %v, got %v", e, a) - } - return nil - }, - }, - { - name: "no action on zero diff", - key: "foo/resource-01", - startingRBAC: []*rbac.RoleBinding{ - { - ObjectMeta: metav1.ObjectMeta{Namespace: "foo", Name: "resource-01"}, - RoleRef: rbac.RoleRef{APIGroup: "rbac.authorization.k8s.io", Kind: "ClusterRole"}, - }, - }, - startingOrigin: []*authorizationapi.RoleBinding{ - {ObjectMeta: metav1.ObjectMeta{Namespace: "foo", Name: "resource-01"}}, - }, - actionCheck: func(actions []clienttesting.Action) error { - if len(actions) != 0 { - return fmt.Errorf("expected %v, got %v", 0, actions) - } - return nil - }, - }, - { - name: "invalid update", - key: "foo/resource-01", - startingRBAC: []*rbac.RoleBinding{ - {ObjectMeta: metav1.ObjectMeta{Namespace: "foo", Name: "resource-01"}}, - }, - startingOrigin: []*authorizationapi.RoleBinding{ - {ObjectMeta: metav1.ObjectMeta{Namespace: "foo", Name: "resource-01", Annotations: map[string]string{"foo": "different"}}}, - }, - actionCheck: func(actions []clienttesting.Action) error { - if len(actions) != 2 { - return fmt.Errorf("expected update then delete, got %v", actions) - } - if _, ok := actions[0].(clienttesting.UpdateAction); !ok { - return fmt.Errorf("expected update, got %v", actions) - } - if _, ok := actions[1].(clienttesting.DeleteAction); !ok { - return fmt.Errorf("expected delete, got %v", actions) - } - return nil - }, - reactions: map[reactionMatch]clienttesting.ReactionFunc{ - {verb: "update", resource: "rolebindings"}: func(action clienttesting.Action) (handled bool, ret runtime.Object, err error) { - return true, nil, apierrors.NewInvalid(rbac.Kind("RoleBinding"), "dummy", nil) - }, - }, - expectedError: "is invalid", - }, - } - - for _, tc := range tests { - objs := []runtime.Object{} - rbacIndexer := cache.NewIndexer(cache.MetaNamespaceKeyFunc, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}) - originIndexer := cache.NewIndexer(cache.MetaNamespaceKeyFunc, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}) - for _, obj := range tc.startingRBAC { - rbacIndexer.Add(obj) - objs = append(objs, obj) - } - for _, obj := range tc.startingOrigin { - originIndexer.Add(obj) - } - fakeClient := fake.NewSimpleClientset(objs...) - for reactionMatch, action := range tc.reactions { - fakeClient.PrependReactor(reactionMatch.verb, reactionMatch.resource, action) - } - - c := &OriginRoleBindingToRBACRoleBindingController{ - rbacClient: fakeClient.Rbac(), - rbacLister: rbaclister.NewRoleBindingLister(rbacIndexer), - originLister: originlister.NewRoleBindingLister(originIndexer), - } - err := c.syncRoleBinding(tc.key) - switch { - case len(tc.expectedError) == 0 && err == nil: - case len(tc.expectedError) == 0 && err != nil: - t.Errorf("%s: %v", tc.name, err) - case len(tc.expectedError) != 0 && err == nil: - t.Errorf("%s: missing %v", tc.name, tc.expectedError) - case len(tc.expectedError) != 0 && err != nil && !strings.Contains(err.Error(), tc.expectedError): - t.Errorf("%s: expected %v, got %v", tc.name, tc.expectedError, err) - } - - if err := tc.actionCheck(fakeClient.Actions()); err != nil { - t.Errorf("%s: %v", tc.name, err) - } - } -} diff --git a/pkg/authorization/registry/clusterrole/proxy.go b/pkg/authorization/registry/clusterrole/proxy.go new file mode 100644 index 000000000000..aa83c728240f --- /dev/null +++ b/pkg/authorization/registry/clusterrole/proxy.go @@ -0,0 +1,172 @@ +package clusterrole + +import ( + apierrors "k8s.io/apimachinery/pkg/api/errors" + metainternal "k8s.io/apimachinery/pkg/apis/meta/internalversion" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + apirequest "k8s.io/apiserver/pkg/endpoints/request" + "k8s.io/apiserver/pkg/registry/rest" + restclient "k8s.io/client-go/rest" + rbacinternalversion "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/rbac/internalversion" + + authclient "github.com/openshift/origin/pkg/auth/client" + authorizationapi "github.com/openshift/origin/pkg/authorization/apis/authorization" + "github.com/openshift/origin/pkg/authorization/registry/util" +) + +type REST struct { + privilegedClient restclient.Interface + resource schema.GroupResource +} + +var _ rest.Lister = &REST{} +var _ rest.Getter = &REST{} +var _ rest.CreaterUpdater = &REST{} +var _ rest.GracefulDeleter = &REST{} + +func NewREST(client restclient.Interface) *REST { + return &REST{privilegedClient: client, resource: authorizationapi.Resource("clusterrole")} +} + +func (s *REST) New() runtime.Object { + return &authorizationapi.ClusterRole{} +} +func (s *REST) NewList() runtime.Object { + return &authorizationapi.ClusterRoleList{} +} + +func (s *REST) List(ctx apirequest.Context, options *metainternal.ListOptions) (runtime.Object, error) { + client, err := s.getImpersonatingClient(ctx) + if err != nil { + return nil, err + } + + optv1 := metav1.ListOptions{} + if err := metainternal.Convert_internalversion_ListOptions_To_v1_ListOptions(options, &optv1, nil); err != nil { + return nil, err + } + + roles, err := client.List(optv1) + if err != nil { + return nil, err + } + + ret := &authorizationapi.ClusterRoleList{} + for _, curr := range roles.Items { + role, err := util.ClusterRoleFromRBAC(&curr) + if err != nil { + return nil, err + } + ret.Items = append(ret.Items, *role) + } + ret.ListMeta.ResourceVersion = roles.ResourceVersion + return ret, nil +} + +func (s *REST) Get(ctx apirequest.Context, name string, options *metav1.GetOptions) (runtime.Object, error) { + client, err := s.getImpersonatingClient(ctx) + if err != nil { + return nil, err + } + + ret, err := client.Get(name, *options) + if err != nil { + if apierrors.IsNotFound(err) { + return nil, apierrors.NewNotFound(s.resource, name) + } + return nil, err + } + + role, err := util.ClusterRoleFromRBAC(ret) + if err != nil { + return nil, err + } + return role, nil +} + +func (s *REST) Delete(ctx apirequest.Context, name string, options *metav1.DeleteOptions) (runtime.Object, bool, error) { + client, err := s.getImpersonatingClient(ctx) + if err != nil { + return nil, false, err + } + + if err := client.Delete(name, options); err != nil { + return nil, false, err + } + + return &metav1.Status{Status: metav1.StatusSuccess}, true, nil +} + +func (s *REST) Create(ctx apirequest.Context, obj runtime.Object, _ bool) (runtime.Object, error) { + client, err := s.getImpersonatingClient(ctx) + if err != nil { + return nil, err + } + + convertedObj, err := util.ClusterRoleToRBAC(obj.(*authorizationapi.ClusterRole)) + if err != nil { + return nil, err + } + + ret, err := client.Create(convertedObj) + if err != nil { + return nil, err + } + + role, err := util.ClusterRoleFromRBAC(ret) + if err != nil { + return nil, err + } + return role, nil +} + +func (s *REST) Update(ctx apirequest.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) { + client, err := s.getImpersonatingClient(ctx) + if err != nil { + return nil, false, err + } + + old, err := client.Get(name, metav1.GetOptions{}) + if err != nil { + if apierrors.IsNotFound(err) { + return nil, false, apierrors.NewNotFound(s.resource, name) + } + return nil, false, err + } + + oldRole, err := util.ClusterRoleFromRBAC(old) + if err != nil { + return nil, false, err + } + + obj, err := objInfo.UpdatedObject(ctx, oldRole) + if err != nil { + return nil, false, err + } + + updatedRole, err := util.ClusterRoleToRBAC(obj.(*authorizationapi.ClusterRole)) + if err != nil { + return nil, false, err + } + + ret, err := client.Update(updatedRole) + if err != nil { + return nil, false, err + } + + role, err := util.ClusterRoleFromRBAC(ret) + if err != nil { + return nil, false, err + } + return role, false, err +} + +func (s *REST) getImpersonatingClient(ctx apirequest.Context) (rbacinternalversion.ClusterRoleInterface, error) { + rbacClient, err := authclient.NewImpersonatingRBACFromContext(ctx, s.privilegedClient) + if err != nil { + return nil, err + } + return rbacClient.ClusterRoles(), nil +} diff --git a/pkg/authorization/registry/clusterrole/registry_test.go b/pkg/authorization/registry/clusterrole/registry_test.go deleted file mode 100644 index eb69dbc9d0a3..000000000000 --- a/pkg/authorization/registry/clusterrole/registry_test.go +++ /dev/null @@ -1,5 +0,0 @@ -package clusterrole - -import "testing" - -func TestClusterRole(t *testing.T) {} diff --git a/pkg/authorization/registry/clusterrolebinding/proxy.go b/pkg/authorization/registry/clusterrolebinding/proxy.go new file mode 100644 index 000000000000..bb02af3d1fc8 --- /dev/null +++ b/pkg/authorization/registry/clusterrolebinding/proxy.go @@ -0,0 +1,172 @@ +package clusterrolebinding + +import ( + apierrors "k8s.io/apimachinery/pkg/api/errors" + metainternal "k8s.io/apimachinery/pkg/apis/meta/internalversion" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + apirequest "k8s.io/apiserver/pkg/endpoints/request" + "k8s.io/apiserver/pkg/registry/rest" + restclient "k8s.io/client-go/rest" + rbacinternalversion "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/rbac/internalversion" + + authclient "github.com/openshift/origin/pkg/auth/client" + authorizationapi "github.com/openshift/origin/pkg/authorization/apis/authorization" + "github.com/openshift/origin/pkg/authorization/registry/util" +) + +type REST struct { + privilegedClient restclient.Interface + resource schema.GroupResource +} + +var _ rest.Lister = &REST{} +var _ rest.Getter = &REST{} +var _ rest.CreaterUpdater = &REST{} +var _ rest.GracefulDeleter = &REST{} + +func NewREST(client restclient.Interface) *REST { + return &REST{privilegedClient: client, resource: authorizationapi.Resource("clusterrolebinding")} +} + +func (s *REST) New() runtime.Object { + return &authorizationapi.ClusterRoleBinding{} +} +func (s *REST) NewList() runtime.Object { + return &authorizationapi.ClusterRoleBindingList{} +} + +func (s *REST) List(ctx apirequest.Context, options *metainternal.ListOptions) (runtime.Object, error) { + client, err := s.getImpersonatingClient(ctx) + if err != nil { + return nil, err + } + + optv1 := metav1.ListOptions{} + if err := metainternal.Convert_internalversion_ListOptions_To_v1_ListOptions(options, &optv1, nil); err != nil { + return nil, err + } + + bindings, err := client.List(optv1) + if err != nil { + return nil, err + } + + ret := &authorizationapi.ClusterRoleBindingList{} + for _, curr := range bindings.Items { + role, err := util.ClusterRoleBindingFromRBAC(&curr) + if err != nil { + return nil, err + } + ret.Items = append(ret.Items, *role) + } + ret.ListMeta.ResourceVersion = bindings.ResourceVersion + return ret, nil +} + +func (s *REST) Get(ctx apirequest.Context, name string, options *metav1.GetOptions) (runtime.Object, error) { + client, err := s.getImpersonatingClient(ctx) + if err != nil { + return nil, err + } + + ret, err := client.Get(name, *options) + if err != nil { + if apierrors.IsNotFound(err) { + return nil, apierrors.NewNotFound(s.resource, name) + } + return nil, err + } + + binding, err := util.ClusterRoleBindingFromRBAC(ret) + if err != nil { + return nil, err + } + return binding, nil +} + +func (s *REST) Delete(ctx apirequest.Context, name string, options *metav1.DeleteOptions) (runtime.Object, bool, error) { + client, err := s.getImpersonatingClient(ctx) + if err != nil { + return nil, false, err + } + + if err := client.Delete(name, options); err != nil { + return nil, false, err + } + + return &metav1.Status{Status: metav1.StatusSuccess}, true, nil +} + +func (s *REST) Create(ctx apirequest.Context, obj runtime.Object, _ bool) (runtime.Object, error) { + client, err := s.getImpersonatingClient(ctx) + if err != nil { + return nil, err + } + + convertedObj, err := util.ClusterRoleBindingToRBAC(obj.(*authorizationapi.ClusterRoleBinding)) + if err != nil { + return nil, err + } + + ret, err := client.Create(convertedObj) + if err != nil { + return nil, err + } + + binding, err := util.ClusterRoleBindingFromRBAC(ret) + if err != nil { + return nil, err + } + return binding, nil +} + +func (s *REST) Update(ctx apirequest.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) { + client, err := s.getImpersonatingClient(ctx) + if err != nil { + return nil, false, err + } + + old, err := client.Get(name, metav1.GetOptions{}) + if err != nil { + if apierrors.IsNotFound(err) { + return nil, false, apierrors.NewNotFound(s.resource, name) + } + return nil, false, err + } + + oldRoleBinding, err := util.ClusterRoleBindingFromRBAC(old) + if err != nil { + return nil, false, err + } + + obj, err := objInfo.UpdatedObject(ctx, oldRoleBinding) + if err != nil { + return nil, false, err + } + + updatedRoleBinding, err := util.ClusterRoleBindingToRBAC(obj.(*authorizationapi.ClusterRoleBinding)) + if err != nil { + return nil, false, err + } + + ret, err := client.Update(updatedRoleBinding) + if err != nil { + return nil, false, err + } + + role, err := util.ClusterRoleBindingFromRBAC(ret) + if err != nil { + return nil, false, err + } + return role, false, err +} + +func (s *REST) getImpersonatingClient(ctx apirequest.Context) (rbacinternalversion.ClusterRoleBindingInterface, error) { + rbacClient, err := authclient.NewImpersonatingRBACFromContext(ctx, s.privilegedClient) + if err != nil { + return nil, err + } + return rbacClient.ClusterRoleBindings(), nil +} diff --git a/pkg/authorization/registry/clusterrolebinding/registry_test.go b/pkg/authorization/registry/clusterrolebinding/registry_test.go deleted file mode 100644 index 1bb46afe4264..000000000000 --- a/pkg/authorization/registry/clusterrolebinding/registry_test.go +++ /dev/null @@ -1,5 +0,0 @@ -package clusterrolebinding - -import "testing" - -func TestClusterRoleBinding(t *testing.T) {} diff --git a/pkg/authorization/registry/role/proxy.go b/pkg/authorization/registry/role/proxy.go new file mode 100644 index 000000000000..545d942df15e --- /dev/null +++ b/pkg/authorization/registry/role/proxy.go @@ -0,0 +1,176 @@ +package role + +import ( + apierrors "k8s.io/apimachinery/pkg/api/errors" + metainternal "k8s.io/apimachinery/pkg/apis/meta/internalversion" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + apirequest "k8s.io/apiserver/pkg/endpoints/request" + "k8s.io/apiserver/pkg/registry/rest" + restclient "k8s.io/client-go/rest" + rbacinternalversion "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/rbac/internalversion" + + authclient "github.com/openshift/origin/pkg/auth/client" + authorizationapi "github.com/openshift/origin/pkg/authorization/apis/authorization" + "github.com/openshift/origin/pkg/authorization/registry/util" +) + +type REST struct { + privilegedClient restclient.Interface + resource schema.GroupResource +} + +var _ rest.Lister = &REST{} +var _ rest.Getter = &REST{} +var _ rest.CreaterUpdater = &REST{} +var _ rest.GracefulDeleter = &REST{} + +func NewREST(client restclient.Interface) *REST { + return &REST{privilegedClient: client, resource: authorizationapi.Resource("role")} +} + +func (s *REST) New() runtime.Object { + return &authorizationapi.Role{} +} +func (s *REST) NewList() runtime.Object { + return &authorizationapi.RoleList{} +} + +func (s *REST) List(ctx apirequest.Context, options *metainternal.ListOptions) (runtime.Object, error) { + client, err := s.getImpersonatingClient(ctx) + if err != nil { + return nil, err + } + + optv1 := metav1.ListOptions{} + if err := metainternal.Convert_internalversion_ListOptions_To_v1_ListOptions(options, &optv1, nil); err != nil { + return nil, err + } + + roles, err := client.List(optv1) + if err != nil { + return nil, err + } + + ret := &authorizationapi.RoleList{} + for _, curr := range roles.Items { + role, err := util.RoleFromRBAC(&curr) + if err != nil { + return nil, err + } + ret.Items = append(ret.Items, *role) + } + ret.ListMeta.ResourceVersion = roles.ResourceVersion + return ret, nil +} + +func (s *REST) Get(ctx apirequest.Context, name string, options *metav1.GetOptions) (runtime.Object, error) { + client, err := s.getImpersonatingClient(ctx) + if err != nil { + return nil, err + } + + ret, err := client.Get(name, *options) + if err != nil { + if apierrors.IsNotFound(err) { + return nil, apierrors.NewNotFound(s.resource, name) + } + return nil, err + } + + role, err := util.RoleFromRBAC(ret) + if err != nil { + return nil, err + } + return role, nil +} + +func (s *REST) Delete(ctx apirequest.Context, name string, options *metav1.DeleteOptions) (runtime.Object, bool, error) { + client, err := s.getImpersonatingClient(ctx) + if err != nil { + return nil, false, err + } + + if err := client.Delete(name, options); err != nil { + return nil, false, err + } + + return &metav1.Status{Status: metav1.StatusSuccess}, true, nil +} + +func (s *REST) Create(ctx apirequest.Context, obj runtime.Object, _ bool) (runtime.Object, error) { + client, err := s.getImpersonatingClient(ctx) + if err != nil { + return nil, err + } + + convertedObj, err := util.RoleToRBAC(obj.(*authorizationapi.Role)) + if err != nil { + return nil, err + } + + ret, err := client.Create(convertedObj) + if err != nil { + return nil, err + } + + role, err := util.RoleFromRBAC(ret) + if err != nil { + return nil, err + } + return role, nil +} + +func (s *REST) Update(ctx apirequest.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) { + client, err := s.getImpersonatingClient(ctx) + if err != nil { + return nil, false, err + } + + old, err := client.Get(name, metav1.GetOptions{}) + if err != nil { + if apierrors.IsNotFound(err) { + return nil, false, apierrors.NewNotFound(s.resource, name) + } + return nil, false, err + } + + oldRole, err := util.RoleFromRBAC(old) + if err != nil { + return nil, false, err + } + + obj, err := objInfo.UpdatedObject(ctx, oldRole) + if err != nil { + return nil, false, err + } + + updatedRole, err := util.RoleToRBAC(obj.(*authorizationapi.Role)) + if err != nil { + return nil, false, err + } + + ret, err := client.Update(updatedRole) + if err != nil { + return nil, false, err + } + + role, err := util.RoleFromRBAC(ret) + if err != nil { + return nil, false, err + } + return role, false, err +} + +func (s *REST) getImpersonatingClient(ctx apirequest.Context) (rbacinternalversion.RoleInterface, error) { + namespace, ok := apirequest.NamespaceFrom(ctx) + if !ok { + return nil, apierrors.NewBadRequest("namespace parameter required") + } + rbacClient, err := authclient.NewImpersonatingRBACFromContext(ctx, s.privilegedClient) + if err != nil { + return nil, err + } + return rbacClient.Roles(namespace), nil +} diff --git a/pkg/authorization/registry/rolebinding/proxy.go b/pkg/authorization/registry/rolebinding/proxy.go new file mode 100644 index 000000000000..bd982134c381 --- /dev/null +++ b/pkg/authorization/registry/rolebinding/proxy.go @@ -0,0 +1,192 @@ +package rolebinding + +import ( + apierrors "k8s.io/apimachinery/pkg/api/errors" + metainternal "k8s.io/apimachinery/pkg/apis/meta/internalversion" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/conversion" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + apirequest "k8s.io/apiserver/pkg/endpoints/request" + "k8s.io/apiserver/pkg/registry/rest" + restclient "k8s.io/client-go/rest" + rbacinternalversion "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/rbac/internalversion" + + authclient "github.com/openshift/origin/pkg/auth/client" + authorizationapi "github.com/openshift/origin/pkg/authorization/apis/authorization" + "github.com/openshift/origin/pkg/authorization/registry/util" +) + +type REST struct { + privilegedClient restclient.Interface + resource schema.GroupResource +} + +var _ rest.Lister = &REST{} +var _ rest.Getter = &REST{} +var _ rest.CreaterUpdater = &REST{} +var _ rest.GracefulDeleter = &REST{} + +func NewREST(client restclient.Interface) *REST { + return &REST{privilegedClient: client, resource: authorizationapi.Resource("rolebinding")} +} + +func (s *REST) New() runtime.Object { + return &authorizationapi.RoleBinding{} +} +func (s *REST) NewList() runtime.Object { + return &authorizationapi.RoleBindingList{} +} + +func (s *REST) List(ctx apirequest.Context, options *metainternal.ListOptions) (runtime.Object, error) { + client, err := s.getImpersonatingClient(ctx) + if err != nil { + return nil, err + } + + optv1 := metav1.ListOptions{} + if err := metainternal.Convert_internalversion_ListOptions_To_v1_ListOptions(options, &optv1, nil); err != nil { + return nil, err + } + + bindings, err := client.List(optv1) + if err != nil { + return nil, err + } + + ret := &authorizationapi.RoleBindingList{} + for _, curr := range bindings.Items { + role, err := util.RoleBindingFromRBAC(&curr) + if err != nil { + return nil, err + } + ret.Items = append(ret.Items, *role) + } + ret.ListMeta.ResourceVersion = bindings.ResourceVersion + return ret, nil +} + +func (s *REST) Get(ctx apirequest.Context, name string, options *metav1.GetOptions) (runtime.Object, error) { + client, err := s.getImpersonatingClient(ctx) + if err != nil { + return nil, err + } + + ret, err := client.Get(name, *options) + if err != nil { + if apierrors.IsNotFound(err) { + return nil, apierrors.NewNotFound(s.resource, name) + } + return nil, err + } + + binding, err := util.RoleBindingFromRBAC(ret) + if err != nil { + return nil, err + } + return binding, nil +} + +func (s *REST) Delete(ctx apirequest.Context, name string, options *metav1.DeleteOptions) (runtime.Object, bool, error) { + client, err := s.getImpersonatingClient(ctx) + if err != nil { + return nil, false, err + } + + if err := client.Delete(name, options); err != nil { + return nil, false, err + } + + return &metav1.Status{Status: metav1.StatusSuccess}, true, nil +} + +func (s *REST) Create(ctx apirequest.Context, obj runtime.Object, _ bool) (runtime.Object, error) { + client, err := s.getImpersonatingClient(ctx) + if err != nil { + return nil, err + } + + rb := obj.(*authorizationapi.RoleBinding) + + // Default the namespace if it is not specified so conversion does not error + // Normally this is done during the REST strategy but we avoid those here to keep the proxies simple + if ns, ok := apirequest.NamespaceFrom(ctx); ok && len(ns) > 0 && len(rb.Namespace) == 0 && len(rb.RoleRef.Namespace) > 0 { + deepcopiedObj := &authorizationapi.RoleBinding{} + if err := authorizationapi.DeepCopy_authorization_RoleBinding(rb, deepcopiedObj, cloner); err != nil { + return nil, err + } + deepcopiedObj.Namespace = ns + rb = deepcopiedObj + } + + convertedObj, err := util.RoleBindingToRBAC(rb) + if err != nil { + return nil, err + } + + ret, err := client.Create(convertedObj) + if err != nil { + return nil, err + } + + binding, err := util.RoleBindingFromRBAC(ret) + if err != nil { + return nil, err + } + return binding, nil +} + +func (s *REST) Update(ctx apirequest.Context, name string, objInfo rest.UpdatedObjectInfo) (runtime.Object, bool, error) { + client, err := s.getImpersonatingClient(ctx) + if err != nil { + return nil, false, err + } + + old, err := client.Get(name, metav1.GetOptions{}) + if err != nil { + if apierrors.IsNotFound(err) { + return nil, false, apierrors.NewNotFound(s.resource, name) + } + return nil, false, err + } + + oldRoleBinding, err := util.RoleBindingFromRBAC(old) + if err != nil { + return nil, false, err + } + + obj, err := objInfo.UpdatedObject(ctx, oldRoleBinding) + if err != nil { + return nil, false, err + } + + updatedRoleBinding, err := util.RoleBindingToRBAC(obj.(*authorizationapi.RoleBinding)) + if err != nil { + return nil, false, err + } + + ret, err := client.Update(updatedRoleBinding) + if err != nil { + return nil, false, err + } + + role, err := util.RoleBindingFromRBAC(ret) + if err != nil { + return nil, false, err + } + return role, false, err +} + +func (s *REST) getImpersonatingClient(ctx apirequest.Context) (rbacinternalversion.RoleBindingInterface, error) { + namespace, ok := apirequest.NamespaceFrom(ctx) + if !ok { + return nil, apierrors.NewBadRequest("namespace parameter required") + } + rbacClient, err := authclient.NewImpersonatingRBACFromContext(ctx, s.privilegedClient) + if err != nil { + return nil, err + } + return rbacClient.RoleBindings(namespace), nil +} + +var cloner = conversion.NewCloner() diff --git a/pkg/authorization/registry/util/convert.go b/pkg/authorization/registry/util/convert.go new file mode 100644 index 000000000000..d6cb33e56890 --- /dev/null +++ b/pkg/authorization/registry/util/convert.go @@ -0,0 +1,138 @@ +package util + +import ( + "k8s.io/apimachinery/pkg/conversion" + "k8s.io/kubernetes/pkg/apis/rbac" + + authorizationapi "github.com/openshift/origin/pkg/authorization/apis/authorization" +) + +// ClusterRoleToRBAC turns an OpenShift ClusterRole into a Kubernetes RBAC +// ClusterRole, the returned object is safe to mutate +func ClusterRoleToRBAC(obj *authorizationapi.ClusterRole) (*rbac.ClusterRole, error) { + convertedObj := &rbac.ClusterRole{} + if err := authorizationapi.Convert_authorization_ClusterRole_To_rbac_ClusterRole(obj, convertedObj, nil); err != nil { + return nil, err + } + // do a deep copy here since conversion does not guarantee a new object. + deepcopiedObj := &rbac.ClusterRole{} + if err := rbac.DeepCopy_rbac_ClusterRole(convertedObj, deepcopiedObj, cloner); err != nil { + return nil, err + } + + return deepcopiedObj, nil +} + +// ClusterRoleBindingToRBAC turns an OpenShift ClusterRoleBinding into a Kubernetes +// RBAC ClusterRoleBinding, the returned object is safe to mutate +func ClusterRoleBindingToRBAC(obj *authorizationapi.ClusterRoleBinding) (*rbac.ClusterRoleBinding, error) { + convertedObj := &rbac.ClusterRoleBinding{} + if err := authorizationapi.Convert_authorization_ClusterRoleBinding_To_rbac_ClusterRoleBinding(obj, convertedObj, nil); err != nil { + return nil, err + } + // do a deep copy here since conversion does not guarantee a new object. + deepcopiedObj := &rbac.ClusterRoleBinding{} + if err := rbac.DeepCopy_rbac_ClusterRoleBinding(convertedObj, deepcopiedObj, cloner); err != nil { + return nil, err + } + + return deepcopiedObj, nil +} + +// RoleToRBAC turns an OpenShift Role into a Kubernetes RBAC Role, +// the returned object is safe to mutate +func RoleToRBAC(obj *authorizationapi.Role) (*rbac.Role, error) { + convertedObj := &rbac.Role{} + if err := authorizationapi.Convert_authorization_Role_To_rbac_Role(obj, convertedObj, nil); err != nil { + return nil, err + } + // do a deep copy here since conversion does not guarantee a new object. + deepcopiedObj := &rbac.Role{} + if err := rbac.DeepCopy_rbac_Role(convertedObj, deepcopiedObj, cloner); err != nil { + return nil, err + } + + return deepcopiedObj, nil +} + +// RoleBindingToRBAC turns an OpenShift RoleBinding into a Kubernetes RBAC +// Rolebinding, the returned object is safe to mutate +func RoleBindingToRBAC(obj *authorizationapi.RoleBinding) (*rbac.RoleBinding, error) { + convertedObj := &rbac.RoleBinding{} + if err := authorizationapi.Convert_authorization_RoleBinding_To_rbac_RoleBinding(obj, convertedObj, nil); err != nil { + return nil, err + } + // do a deep copy here since conversion does not guarantee a new object. + deepcopiedObj := &rbac.RoleBinding{} + if err := rbac.DeepCopy_rbac_RoleBinding(convertedObj, deepcopiedObj, cloner); err != nil { + return nil, err + } + + return deepcopiedObj, nil +} + +// ClusterRoleFromRBAC turns a Kubernetes RBAC ClusterRole into an Openshift +// ClusterRole, the returned object is safe to mutate +func ClusterRoleFromRBAC(obj *rbac.ClusterRole) (*authorizationapi.ClusterRole, error) { + convertedObj := &authorizationapi.ClusterRole{} + if err := authorizationapi.Convert_rbac_ClusterRole_To_authorization_ClusterRole(obj, convertedObj, nil); err != nil { + return nil, err + } + // do a deep copy here since conversion does not guarantee a new object. + deepcopiedObj := &authorizationapi.ClusterRole{} + if err := authorizationapi.DeepCopy_authorization_ClusterRole(convertedObj, deepcopiedObj, cloner); err != nil { + return nil, err + } + + return deepcopiedObj, nil +} + +// ClusterRoleBindingFromRBAC turns a Kuberenets RBAC ClusterRoleBinding into +// an Openshift ClusterRoleBinding, the returned object is safe to mutate +func ClusterRoleBindingFromRBAC(obj *rbac.ClusterRoleBinding) (*authorizationapi.ClusterRoleBinding, error) { + convertedObj := &authorizationapi.ClusterRoleBinding{} + if err := authorizationapi.Convert_rbac_ClusterRoleBinding_To_authorization_ClusterRoleBinding(obj, convertedObj, nil); err != nil { + return nil, err + } + // do a deep copy here since conversion does not guarantee a new object. + deepcopiedObj := &authorizationapi.ClusterRoleBinding{} + if err := authorizationapi.DeepCopy_authorization_ClusterRoleBinding(convertedObj, deepcopiedObj, cloner); err != nil { + return nil, err + } + + return deepcopiedObj, nil +} + +// RoleFromRBAC turns a Kubernetes RBAC Role into an OpenShift Role, +// the returned object is safe to mutate +func RoleFromRBAC(obj *rbac.Role) (*authorizationapi.Role, error) { + convertedObj := &authorizationapi.Role{} + if err := authorizationapi.Convert_rbac_Role_To_authorization_Role(obj, convertedObj, nil); err != nil { + return nil, err + } + // do a deep copy here since conversion does not guarantee a new object. + deepcopiedObj := &authorizationapi.Role{} + if err := authorizationapi.DeepCopy_authorization_Role(convertedObj, deepcopiedObj, cloner); err != nil { + return nil, err + } + + return deepcopiedObj, nil +} + +// RoleBindingFromRBAC turns a Kubernetes RBAC RoleBinding into an OpenShift +// Rolebinding, the returned object is safe to mutate +func RoleBindingFromRBAC(obj *rbac.RoleBinding) (*authorizationapi.RoleBinding, error) { + convertedObj := &authorizationapi.RoleBinding{} + if err := authorizationapi.Convert_rbac_RoleBinding_To_authorization_RoleBinding(obj, convertedObj, nil); err != nil { + return nil, err + } + // do a deep copy here since conversion does not guarantee a new object. + deepcopiedObj := &authorizationapi.RoleBinding{} + if err := authorizationapi.DeepCopy_authorization_RoleBinding(convertedObj, deepcopiedObj, cloner); err != nil { + return nil, err + } + + return deepcopiedObj, nil +} + +var cloner = conversion.NewCloner() diff --git a/pkg/authorization/controller/authorizationsync/normalize.go b/pkg/authorization/registry/util/normalize.go similarity index 89% rename from pkg/authorization/controller/authorizationsync/normalize.go rename to pkg/authorization/registry/util/normalize.go index 24adef026aed..a0f1869908a6 100644 --- a/pkg/authorization/controller/authorizationsync/normalize.go +++ b/pkg/authorization/registry/util/normalize.go @@ -1,4 +1,4 @@ -package authorizationsync +package util import ( "strings" @@ -9,13 +9,12 @@ import ( "k8s.io/kubernetes/pkg/apis/rbac" authorizationapi "github.com/openshift/origin/pkg/authorization/apis/authorization" - "github.com/openshift/origin/pkg/authorization/util/convert" ) // ConvertToRBACClusterRole performs the conversion and guarantees the returned object is safe to mutate. func ConvertToRBACClusterRole(originClusterRole *authorizationapi.ClusterRole) (*rbac.ClusterRole, error) { // convert the origin role to an rbac role - equivalentClusterRole, err := convert.ClusterRoleToRBAC(originClusterRole) + equivalentClusterRole, err := ClusterRoleToRBAC(originClusterRole) if err != nil { return nil, err } @@ -23,12 +22,6 @@ func ConvertToRBACClusterRole(originClusterRole *authorizationapi.ClusterRole) ( // normalize rules before persisting so RBAC's case sensitive authorizer will work normalizePolicyRules(equivalentClusterRole.Rules) - // there's one wrinkle. If `openshift.io/reconcile-protect` is to true, then we must set rbac.authorization.kubernetes.io/autoupdate to false to - if equivalentClusterRole.Annotations["openshift.io/reconcile-protect"] == "true" { - equivalentClusterRole.Annotations["rbac.authorization.kubernetes.io/autoupdate"] = "false" - delete(equivalentClusterRole.Annotations, "openshift.io/reconcile-protect") - } - // resource version cannot be set during creation equivalentClusterRole.ResourceVersion = "" @@ -49,7 +42,7 @@ func PrepareForUpdateClusterRole(newClusterRole, existingClusterRole *rbac.Clust // ConvertToRBACClusterRoleBinding performs the conversion and guarantees the returned object is safe to mutate. func ConvertToRBACClusterRoleBinding(originClusterRoleBinding *authorizationapi.ClusterRoleBinding) (*rbac.ClusterRoleBinding, error) { // convert the origin roleBinding to an rbac roleBinding - equivalentClusterRoleBinding, err := convert.ClusterRoleBindingToRBAC(originClusterRoleBinding) + equivalentClusterRoleBinding, err := ClusterRoleBindingToRBAC(originClusterRoleBinding) if err != nil { return nil, err } @@ -74,7 +67,7 @@ func PrepareForUpdateClusterRoleBinding(newClusterRoleBinding, existingClusterRo // ConvertToRBACRole performs the conversion and guarantees the returned object is safe to mutate. func ConvertToRBACRole(originRole *authorizationapi.Role) (*rbac.Role, error) { // convert the origin role to an rbac role - equivalentRole, err := convert.RoleToRBAC(originRole) + equivalentRole, err := RoleToRBAC(originRole) if err != nil { return nil, err } @@ -102,7 +95,7 @@ func PrepareForUpdateRole(newRole, existingRole *rbac.Role) bool { // ConvertToRBACRoleBinding performs the conversion and guarantees the returned object is safe to mutate. func ConvertToRBACRoleBinding(originRoleBinding *authorizationapi.RoleBinding) (*rbac.RoleBinding, error) { // convert the origin roleBinding to an rbac roleBinding - equivalentRoleBinding, err := convert.RoleBindingToRBAC(originRoleBinding) + equivalentRoleBinding, err := RoleBindingToRBAC(originRoleBinding) if err != nil { return nil, err } diff --git a/pkg/authorization/util/convert/convert.go b/pkg/authorization/util/convert/convert.go deleted file mode 100644 index cd6844e0879b..000000000000 --- a/pkg/authorization/util/convert/convert.go +++ /dev/null @@ -1,74 +0,0 @@ -package convert - -import ( - "k8s.io/apimachinery/pkg/conversion" - "k8s.io/kubernetes/pkg/apis/rbac" - - authorizationapi "github.com/openshift/origin/pkg/authorization/apis/authorization" -) - -// ClusterRoleToRBAC turns an OpenShift ClusterRole into a Kubernetes RBAC -// ClusterRole, the returned object is safe to mutate -func ClusterRoleToRBAC(origin *authorizationapi.ClusterRole) (*rbac.ClusterRole, error) { - converted := &rbac.ClusterRole{} - if err := authorizationapi.Convert_authorization_ClusterRole_To_rbac_ClusterRole(origin, converted, nil); err != nil { - return nil, err - } - // do a deep copy here since conversion does not guarantee a new object. - deepcopied := &rbac.ClusterRole{} - if err := rbac.DeepCopy_rbac_ClusterRole(converted, deepcopied, cloner); err != nil { - return nil, err - } - - return deepcopied, nil -} - -// ClusterRoleBindingToRBAC turns an OpenShift ClusterRoleBinding into a Kubernetes -// RBAC ClusterRoleBinding, the returned object is safe to mutate -func ClusterRoleBindingToRBAC(origin *authorizationapi.ClusterRoleBinding) (*rbac.ClusterRoleBinding, error) { - converted := &rbac.ClusterRoleBinding{} - if err := authorizationapi.Convert_authorization_ClusterRoleBinding_To_rbac_ClusterRoleBinding(origin, converted, nil); err != nil { - return nil, err - } - // do a deep copy here since conversion does not guarantee a new object. - deepcopied := &rbac.ClusterRoleBinding{} - if err := rbac.DeepCopy_rbac_ClusterRoleBinding(converted, deepcopied, cloner); err != nil { - return nil, err - } - - return deepcopied, nil -} - -// RoleToRBAC turns an OpenShift Role into a Kubernetes RBAC Role, -// the returned object is safe to mutate -func RoleToRBAC(origin *authorizationapi.Role) (*rbac.Role, error) { - converted := &rbac.Role{} - if err := authorizationapi.Convert_authorization_Role_To_rbac_Role(origin, converted, nil); err != nil { - return nil, err - } - // do a deep copy here since conversion does not guarantee a new object. - deepcopied := &rbac.Role{} - if err := rbac.DeepCopy_rbac_Role(converted, deepcopied, cloner); err != nil { - return nil, err - } - - return deepcopied, nil -} - -// RoleBindingToRBAC turns an OpenShift RoleBinding into a Kubernetes RBAC -// Rolebinding, the returned object is safe to mutate -func RoleBindingToRBAC(origin *authorizationapi.RoleBinding) (*rbac.RoleBinding, error) { - converted := &rbac.RoleBinding{} - if err := authorizationapi.Convert_authorization_RoleBinding_To_rbac_RoleBinding(origin, converted, nil); err != nil { - return nil, err - } - // do a deep copy here since conversion does not guarantee a new object. - deepcopied := &rbac.RoleBinding{} - if err := rbac.DeepCopy_rbac_RoleBinding(converted, deepcopied, cloner); err != nil { - return nil, err - } - - return deepcopied, nil -} - -var cloner = conversion.NewCloner() diff --git a/pkg/authorization/util/util.go b/pkg/authorization/util/util.go index ce520120725e..a80d0a940ad5 100644 --- a/pkg/authorization/util/util.go +++ b/pkg/authorization/util/util.go @@ -8,25 +8,6 @@ import ( "k8s.io/apiserver/pkg/authentication/user" "k8s.io/kubernetes/pkg/apis/authorization" "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/authorization/internalversion" - - clusterpolicyregistry "github.com/openshift/origin/pkg/authorization/registry/clusterpolicy" - clusterpolicyetcd "github.com/openshift/origin/pkg/authorization/registry/clusterpolicy/etcd" - clusterpolicybindingregistry "github.com/openshift/origin/pkg/authorization/registry/clusterpolicybinding" - clusterpolicybindingetcd "github.com/openshift/origin/pkg/authorization/registry/clusterpolicybinding/etcd" - "github.com/openshift/origin/pkg/authorization/registry/clusterrole" - clusterrolestorage "github.com/openshift/origin/pkg/authorization/registry/clusterrole/proxy" - "github.com/openshift/origin/pkg/authorization/registry/clusterrolebinding" - clusterrolebindingstorage "github.com/openshift/origin/pkg/authorization/registry/clusterrolebinding/proxy" - policyregistry "github.com/openshift/origin/pkg/authorization/registry/policy" - policyetcd "github.com/openshift/origin/pkg/authorization/registry/policy/etcd" - policybindingregistry "github.com/openshift/origin/pkg/authorization/registry/policybinding" - policybindingetcd "github.com/openshift/origin/pkg/authorization/registry/policybinding/etcd" - "github.com/openshift/origin/pkg/authorization/registry/role" - rolestorage "github.com/openshift/origin/pkg/authorization/registry/role/policybased" - "github.com/openshift/origin/pkg/authorization/registry/rolebinding" - rolebindingstorage "github.com/openshift/origin/pkg/authorization/registry/rolebinding/policybased" - "github.com/openshift/origin/pkg/authorization/rulevalidation" - "github.com/openshift/origin/pkg/util/restoptions" ) // AddUserToSAR adds the requisite user information to a SubjectAccessReview. @@ -65,75 +46,3 @@ func Authorize(sarClient internalversion.SubjectAccessReviewInterface, user user } return kerrors.NewForbidden(schema.GroupResource{Group: resourceAttributes.Group, Resource: resourceAttributes.Resource}, resourceAttributes.Name, err) } - -func NewLiveRuleResolver(policyRegistry policyregistry.Registry, policyBindingRegistry policybindingregistry.Registry, clusterPolicyRegistry clusterpolicyregistry.Registry, clusterBindingRegistry clusterpolicybindingregistry.Registry) rulevalidation.AuthorizationRuleResolver { - return rulevalidation.NewDefaultRuleResolver( - &policyregistry.ReadOnlyPolicyListerNamespacer{ - Registry: policyRegistry, - }, - &policybindingregistry.ReadOnlyPolicyBindingListerNamespacer{ - Registry: policyBindingRegistry, - }, - &clusterpolicyregistry.ReadOnlyClusterPolicyClientShim{ - ReadOnlyClusterPolicy: clusterpolicyregistry.ReadOnlyClusterPolicy{Registry: clusterPolicyRegistry}, - }, - &clusterpolicybindingregistry.ReadOnlyClusterPolicyBindingClientShim{ - ReadOnlyClusterPolicyBinding: clusterpolicybindingregistry.ReadOnlyClusterPolicyBinding{Registry: clusterBindingRegistry}, - }, - ) -} - -func GetAuthorizationStorage(optsGetter restoptions.Getter, cachedRuleResolver rulevalidation.AuthorizationRuleResolver) (*AuthorizationStorage, error) { - policyStorage, err := policyetcd.NewREST(optsGetter) - if err != nil { - return nil, err - } - policyRegistry := policyregistry.NewRegistry(policyStorage) - - policyBindingStorage, err := policybindingetcd.NewREST(optsGetter) - if err != nil { - return nil, err - } - policyBindingRegistry := policybindingregistry.NewRegistry(policyBindingStorage) - - clusterPolicyStorage, err := clusterpolicyetcd.NewREST(optsGetter) - if err != nil { - return nil, err - } - clusterPolicyRegistry := clusterpolicyregistry.NewRegistry(clusterPolicyStorage) - - clusterPolicyBindingStorage, err := clusterpolicybindingetcd.NewREST(optsGetter) - if err != nil { - return nil, err - } - clusterPolicyBindingRegistry := clusterpolicybindingregistry.NewRegistry(clusterPolicyBindingStorage) - - liveRuleResolver := NewLiveRuleResolver(policyRegistry, policyBindingRegistry, clusterPolicyRegistry, clusterPolicyBindingRegistry) - - roleStorage := rolestorage.NewVirtualStorage(policyRegistry, liveRuleResolver, cachedRuleResolver) - roleBindingStorage := rolebindingstorage.NewVirtualStorage(policyBindingRegistry, liveRuleResolver, cachedRuleResolver) - clusterRoleStorage := clusterrolestorage.NewClusterRoleStorage(clusterPolicyRegistry, liveRuleResolver, cachedRuleResolver) - clusterRoleBindingStorage := clusterrolebindingstorage.NewClusterRoleBindingStorage(clusterPolicyBindingRegistry, liveRuleResolver, cachedRuleResolver) - - return &AuthorizationStorage{ - Policy: policyStorage, - PolicyBinding: policyBindingStorage, - ClusterPolicy: clusterPolicyStorage, - ClusterPolicyBinding: clusterPolicyBindingStorage, - Role: roleStorage, - RoleBinding: roleBindingStorage, - ClusterRole: clusterRoleStorage, - ClusterRoleBinding: clusterRoleBindingStorage, - }, nil -} - -type AuthorizationStorage struct { - Policy policyregistry.Storage - PolicyBinding policybindingregistry.Storage - ClusterPolicy clusterpolicyregistry.Storage - ClusterPolicyBinding clusterpolicybindingregistry.Storage - Role role.Storage - RoleBinding rolebinding.Storage - ClusterRole clusterrole.Storage - ClusterRoleBinding clusterrolebinding.Storage -} diff --git a/pkg/cmd/server/admin/overwrite_bootstrappolicy.go b/pkg/cmd/server/admin/overwrite_bootstrappolicy.go index 6fcc9e911785..99701a561746 100644 --- a/pkg/cmd/server/admin/overwrite_bootstrappolicy.go +++ b/pkg/cmd/server/admin/overwrite_bootstrappolicy.go @@ -18,13 +18,30 @@ import ( "k8s.io/kubernetes/pkg/kubectl/resource" authorizationapi "github.com/openshift/origin/pkg/authorization/apis/authorization" - "github.com/openshift/origin/pkg/authorization/util" configapilatest "github.com/openshift/origin/pkg/cmd/server/api/latest" originrest "github.com/openshift/origin/pkg/cmd/server/origin/rest" "github.com/openshift/origin/pkg/oc/cli/describe" templateapi "github.com/openshift/origin/pkg/template/apis/template" "github.com/openshift/origin/pkg/util/restoptions" + + clusterpolicyregistry "github.com/openshift/origin/pkg/authorization/registry/clusterpolicy" + clusterpolicyetcd "github.com/openshift/origin/pkg/authorization/registry/clusterpolicy/etcd" + clusterpolicybindingregistry "github.com/openshift/origin/pkg/authorization/registry/clusterpolicybinding" + clusterpolicybindingetcd "github.com/openshift/origin/pkg/authorization/registry/clusterpolicybinding/etcd" + "github.com/openshift/origin/pkg/authorization/registry/clusterrole" + clusterrolestorage "github.com/openshift/origin/pkg/authorization/registry/clusterrole/proxy" + "github.com/openshift/origin/pkg/authorization/registry/clusterrolebinding" + clusterrolebindingstorage "github.com/openshift/origin/pkg/authorization/registry/clusterrolebinding/proxy" + policyregistry "github.com/openshift/origin/pkg/authorization/registry/policy" + policyetcd "github.com/openshift/origin/pkg/authorization/registry/policy/etcd" + policybindingregistry "github.com/openshift/origin/pkg/authorization/registry/policybinding" + policybindingetcd "github.com/openshift/origin/pkg/authorization/registry/policybinding/etcd" + "github.com/openshift/origin/pkg/authorization/registry/role" + rolestorage "github.com/openshift/origin/pkg/authorization/registry/role/policybased" + "github.com/openshift/origin/pkg/authorization/registry/rolebinding" + rolebindingstorage "github.com/openshift/origin/pkg/authorization/registry/rolebinding/policybased" + "github.com/openshift/origin/pkg/authorization/rulevalidation" ) const OverwriteBootstrapPolicyCommandName = "overwrite-policy" @@ -98,6 +115,63 @@ func (o OverwriteBootstrapPolicyOptions) OverwriteBootstrapPolicy() error { return OverwriteBootstrapPolicy(optsGetter, o.File, o.CreateBootstrapPolicyCommand, o.Force, o.Out) } +type authorizationStorage struct { + Role role.Storage + RoleBinding rolebinding.Storage + ClusterRole clusterrole.Storage + ClusterRoleBinding clusterrolebinding.Storage +} + +func newLiveRuleResolver(policyRegistry policyregistry.Registry, policyBindingRegistry policybindingregistry.Registry, clusterPolicyRegistry clusterpolicyregistry.Registry, clusterBindingRegistry clusterpolicybindingregistry.Registry) rulevalidation.AuthorizationRuleResolver { + return rulevalidation.NewDefaultRuleResolver( + &policyregistry.ReadOnlyPolicyListerNamespacer{ + Registry: policyRegistry, + }, + &policybindingregistry.ReadOnlyPolicyBindingListerNamespacer{ + Registry: policyBindingRegistry, + }, + &clusterpolicyregistry.ReadOnlyClusterPolicyClientShim{ + ReadOnlyClusterPolicy: clusterpolicyregistry.ReadOnlyClusterPolicy{Registry: clusterPolicyRegistry}, + }, + &clusterpolicybindingregistry.ReadOnlyClusterPolicyBindingClientShim{ + ReadOnlyClusterPolicyBinding: clusterpolicybindingregistry.ReadOnlyClusterPolicyBinding{Registry: clusterBindingRegistry}, + }, + ) +} + +func getAuthorizationStorage(optsGetter restoptions.Getter) (*authorizationStorage, error) { + policyStorage, err := policyetcd.NewREST(optsGetter) + if err != nil { + return nil, err + } + policyBindingStorage, err := policybindingetcd.NewREST(optsGetter) + if err != nil { + return nil, err + } + clusterPolicyStorage, err := clusterpolicyetcd.NewREST(optsGetter) + if err != nil { + return nil, err + } + clusterPolicyBindingStorage, err := clusterpolicybindingetcd.NewREST(optsGetter) + if err != nil { + return nil, err + } + + policyRegistry := policyregistry.NewRegistry(policyStorage) + policyBindingRegistry := policybindingregistry.NewRegistry(policyBindingStorage) + clusterPolicyRegistry := clusterpolicyregistry.NewRegistry(clusterPolicyStorage) + clusterPolicyBindingRegistry := clusterpolicybindingregistry.NewRegistry(clusterPolicyBindingStorage) + + liveRuleResolver := newLiveRuleResolver(policyRegistry, policyBindingRegistry, clusterPolicyRegistry, clusterPolicyBindingRegistry) + + return &authorizationStorage{ + Role: rolestorage.NewVirtualStorage(policyRegistry, liveRuleResolver, nil), + RoleBinding: rolebindingstorage.NewVirtualStorage(policyBindingRegistry, liveRuleResolver, nil), + ClusterRole: clusterrolestorage.NewClusterRoleStorage(clusterPolicyRegistry, liveRuleResolver, nil), + ClusterRoleBinding: clusterrolebindingstorage.NewClusterRoleBindingStorage(clusterPolicyBindingRegistry, liveRuleResolver, nil), + }, nil +} + func OverwriteBootstrapPolicy(optsGetter restoptions.Getter, policyFile, createBootstrapPolicyCommand string, change bool, out io.Writer) error { if !change { fmt.Fprintf(out, "Performing a dry run of policy overwrite:\n\n") @@ -118,7 +192,7 @@ func OverwriteBootstrapPolicy(optsGetter restoptions.Getter, policyFile, createB return r.Err() } - authStorage, err := util.GetAuthorizationStorage(optsGetter, nil) + authStorage, err := getAuthorizationStorage(optsGetter) if err != nil { return err } diff --git a/pkg/cmd/server/origin/controller/config.go b/pkg/cmd/server/origin/controller/config.go index 1ac5f813f711..d51669ed30b9 100644 --- a/pkg/cmd/server/origin/controller/config.go +++ b/pkg/cmd/server/origin/controller/config.go @@ -23,8 +23,6 @@ type OpenshiftControllerConfig struct { UnidlingControllerConfig UnidlingControllerConfig IngressIPControllerConfig IngressIPControllerConfig - OriginToRBACSyncControllerConfig OriginToRBACSyncControllerConfig - ClusterQuotaMappingControllerConfig ClusterQuotaMappingControllerConfig ClusterQuotaReconciliationControllerConfig ClusterQuotaReconciliationControllerConfig } @@ -60,7 +58,6 @@ func (c *OpenshiftControllerConfig) GetControllerInitializers() (map[string]Init ret["openshift.io/cluster-quota-reconciliation"] = c.ClusterQuotaReconciliationControllerConfig.RunController ret["openshift.io/cluster-quota-mapping"] = c.ClusterQuotaMappingControllerConfig.RunController - ret["openshift.io/origin-to-rbac"] = c.OriginToRBACSyncControllerConfig.RunController return ret, nil } diff --git a/pkg/cmd/server/origin/controller/security.go b/pkg/cmd/server/origin/controller/security.go deleted file mode 100644 index c477e6862f40..000000000000 --- a/pkg/cmd/server/origin/controller/security.go +++ /dev/null @@ -1,44 +0,0 @@ -package controller - -import ( - rbacinternalversion "k8s.io/kubernetes/pkg/client/clientset_generated/internalclientset/typed/rbac/internalversion" - - "github.com/openshift/origin/pkg/authorization/controller/authorizationsync" -) - -type OriginToRBACSyncControllerConfig struct { - PrivilegedRBACClient rbacinternalversion.RbacInterface -} - -func (c *OriginToRBACSyncControllerConfig) RunController(ctx ControllerContext) (bool, error) { - rbacInformer := ctx.InternalKubeInformers.Rbac().InternalVersion() - authInformer := ctx.AuthorizationInformers.Authorization().InternalVersion() - - clusterRoles := authorizationsync.NewOriginToRBACClusterRoleController( - rbacInformer.ClusterRoles(), - authInformer.ClusterPolicies(), - c.PrivilegedRBACClient, - ) - go clusterRoles.Run(5, ctx.Stop) - clusterRoleBindings := authorizationsync.NewOriginToRBACClusterRoleBindingController( - rbacInformer.ClusterRoleBindings(), - authInformer.ClusterPolicyBindings(), - c.PrivilegedRBACClient, - ) - go clusterRoleBindings.Run(5, ctx.Stop) - - roles := authorizationsync.NewOriginToRBACRoleController( - rbacInformer.Roles(), - authInformer.Policies(), - c.PrivilegedRBACClient, - ) - go roles.Run(5, ctx.Stop) - roleBindings := authorizationsync.NewOriginToRBACRoleBindingController( - rbacInformer.RoleBindings(), - authInformer.PolicyBindings(), - c.PrivilegedRBACClient, - ) - go roleBindings.Run(5, ctx.Stop) - - return true, nil -} diff --git a/pkg/cmd/server/origin/master_config.go b/pkg/cmd/server/origin/master_config.go index 2558649e0a99..96a678a30cc1 100644 --- a/pkg/cmd/server/origin/master_config.go +++ b/pkg/cmd/server/origin/master_config.go @@ -420,7 +420,7 @@ func BuildOpenshiftControllerConfig(options configapi.MasterConfig, informers In var err error ret := &origincontrollers.OpenshiftControllerConfig{} - kubeInternal, loopbackClientConfig, err := configapi.GetInternalKubeClient(options.MasterClients.OpenShiftLoopbackKubeConfig, options.MasterClients.OpenShiftLoopbackClientConnectionOverrides) + _, loopbackClientConfig, err := configapi.GetInternalKubeClient(options.MasterClients.OpenShiftLoopbackKubeConfig, options.MasterClients.OpenShiftLoopbackClientConnectionOverrides) if err != nil { return nil, err } @@ -530,11 +530,6 @@ func BuildOpenshiftControllerConfig(options configapi.MasterConfig, informers In IngressIPNetworkCIDR: options.NetworkConfig.IngressIPNetworkCIDR, } - // this needs a privileged client to skip the RBAC escalation checks. - ret.OriginToRBACSyncControllerConfig = origincontrollers.OriginToRBACSyncControllerConfig{ - PrivilegedRBACClient: kubeInternal.Rbac(), - } - // TODO rewire this to accep them during the init function clusterQuotaMappingController := clusterquotamapping.NewClusterQuotaMappingController( informers.GetExternalKubeInformers().Core().V1().Namespaces(), diff --git a/pkg/cmd/server/origin/storage.go b/pkg/cmd/server/origin/storage.go index b0b40632f066..04816a3b4f7c 100644 --- a/pkg/cmd/server/origin/storage.go +++ b/pkg/cmd/server/origin/storage.go @@ -17,7 +17,6 @@ import ( kubeletclient "k8s.io/kubernetes/pkg/kubelet/client" authzapiv1 "github.com/openshift/origin/pkg/authorization/apis/authorization/v1" - "github.com/openshift/origin/pkg/authorization/util" buildapiv1 "github.com/openshift/origin/pkg/build/apis/build/v1" buildclientset "github.com/openshift/origin/pkg/build/generated/internalclientset" buildgenerator "github.com/openshift/origin/pkg/build/generator" @@ -84,9 +83,13 @@ import ( clusterresourcequotaetcd "github.com/openshift/origin/pkg/quota/registry/clusterresourcequota/etcd" "github.com/openshift/origin/pkg/api/v1" + "github.com/openshift/origin/pkg/authorization/registry/clusterrole" + "github.com/openshift/origin/pkg/authorization/registry/clusterrolebinding" "github.com/openshift/origin/pkg/authorization/registry/localresourceaccessreview" "github.com/openshift/origin/pkg/authorization/registry/localsubjectaccessreview" "github.com/openshift/origin/pkg/authorization/registry/resourceaccessreview" + "github.com/openshift/origin/pkg/authorization/registry/role" + "github.com/openshift/origin/pkg/authorization/registry/rolebinding" rolebindingrestrictionetcd "github.com/openshift/origin/pkg/authorization/registry/rolebindingrestriction/etcd" "github.com/openshift/origin/pkg/authorization/registry/selfsubjectrulesreview" "github.com/openshift/origin/pkg/authorization/registry/subjectaccessreview" @@ -197,11 +200,6 @@ func (c OpenshiftAPIConfig) GetRestStorage() (map[schema.GroupVersion]map[string selfSubjectRulesReviewStorage := selfsubjectrulesreview.NewREST(c.RuleResolver, clusterPolicies) subjectRulesReviewStorage := subjectrulesreview.NewREST(c.RuleResolver, clusterPolicies) - authStorage, err := util.GetAuthorizationStorage(c.GenericConfig.RESTOptionsGetter, c.RuleResolver) - if err != nil { - return nil, fmt.Errorf("error building authorization REST storage: %v", err) - } - subjectAccessReviewStorage := subjectaccessreview.NewREST(c.GenericConfig.Authorizer) subjectAccessReviewRegistry := subjectaccessreview.NewRegistry(subjectAccessReviewStorage) localSubjectAccessReviewStorage := localsubjectaccessreview.NewREST(subjectAccessReviewRegistry) @@ -408,15 +406,10 @@ func (c OpenshiftAPIConfig) GetRestStorage() (map[schema.GroupVersion]map[string "selfSubjectRulesReviews": selfSubjectRulesReviewStorage, "subjectRulesReviews": subjectRulesReviewStorage, - "policies": authStorage.Policy, - "policyBindings": authStorage.PolicyBinding, - "roles": authStorage.Role, - "roleBindings": authStorage.RoleBinding, - - "clusterPolicies": authStorage.ClusterPolicy, - "clusterPolicyBindings": authStorage.ClusterPolicyBinding, - "clusterRoleBindings": authStorage.ClusterRoleBinding, - "clusterRoles": authStorage.ClusterRole, + "roles": role.NewREST(c.KubeClientInternal.Rbac().RESTClient()), + "roleBindings": rolebinding.NewREST(c.KubeClientInternal.Rbac().RESTClient()), + "clusterRoles": clusterrole.NewREST(c.KubeClientInternal.Rbac().RESTClient()), + "clusterRoleBindings": clusterrolebinding.NewREST(c.KubeClientInternal.Rbac().RESTClient()), "roleBindingRestrictions": roleBindingRestrictionStorage, } diff --git a/pkg/oc/admin/migrate/authorization/authorization.go b/pkg/oc/admin/migrate/authorization/authorization.go index 1b8395a78c8d..8ff6f951d4ab 100644 --- a/pkg/oc/admin/migrate/authorization/authorization.go +++ b/pkg/oc/admin/migrate/authorization/authorization.go @@ -14,7 +14,7 @@ import ( "k8s.io/kubernetes/pkg/kubectl/resource" authorizationapi "github.com/openshift/origin/pkg/authorization/apis/authorization" - "github.com/openshift/origin/pkg/authorization/controller/authorizationsync" + "github.com/openshift/origin/pkg/authorization/registry/util" "github.com/openshift/origin/pkg/cmd/util/clientcmd" "github.com/openshift/origin/pkg/oc/admin/migrate" @@ -126,7 +126,7 @@ func (o *MigrateAuthorizationOptions) checkClusterRole(originClusterRole *author var errlist []error // convert the origin role to a rbac role - convertedClusterRole, err := authorizationsync.ConvertToRBACClusterRole(originClusterRole) + convertedClusterRole, err := util.ConvertToRBACClusterRole(originClusterRole) if err != nil { errlist = append(errlist, err) } @@ -140,7 +140,7 @@ func (o *MigrateAuthorizationOptions) checkClusterRole(originClusterRole *author // compare the results if there have been no errors so far if len(errlist) == 0 { // if they are not equal, something has gone wrong and the two objects are not in sync - if authorizationsync.PrepareForUpdateClusterRole(convertedClusterRole, rbacClusterRole) { + if util.PrepareForUpdateClusterRole(convertedClusterRole, rbacClusterRole) { errlist = append(errlist, errOutOfSync) } } @@ -152,7 +152,7 @@ func (o *MigrateAuthorizationOptions) checkRole(originRole *authorizationapi.Rol var errlist []error // convert the origin role to a rbac role - convertedRole, err := authorizationsync.ConvertToRBACRole(originRole) + convertedRole, err := util.ConvertToRBACRole(originRole) if err != nil { errlist = append(errlist, err) } @@ -166,7 +166,7 @@ func (o *MigrateAuthorizationOptions) checkRole(originRole *authorizationapi.Rol // compare the results if there have been no errors so far if len(errlist) == 0 { // if they are not equal, something has gone wrong and the two objects are not in sync - if authorizationsync.PrepareForUpdateRole(convertedRole, rbacRole) { + if util.PrepareForUpdateRole(convertedRole, rbacRole) { errlist = append(errlist, errOutOfSync) } } @@ -178,7 +178,7 @@ func (o *MigrateAuthorizationOptions) checkClusterRoleBinding(originRoleBinding var errlist []error // convert the origin role binding to a rbac role binding - convertedRoleBinding, err := authorizationsync.ConvertToRBACClusterRoleBinding(originRoleBinding) + convertedRoleBinding, err := util.ConvertToRBACClusterRoleBinding(originRoleBinding) if err != nil { errlist = append(errlist, err) } @@ -192,7 +192,7 @@ func (o *MigrateAuthorizationOptions) checkClusterRoleBinding(originRoleBinding // compare the results if there have been no errors so far if len(errlist) == 0 { // if they are not equal, something has gone wrong and the two objects are not in sync - if authorizationsync.PrepareForUpdateClusterRoleBinding(convertedRoleBinding, rbacRoleBinding) { + if util.PrepareForUpdateClusterRoleBinding(convertedRoleBinding, rbacRoleBinding) { errlist = append(errlist, errOutOfSync) } } @@ -204,7 +204,7 @@ func (o *MigrateAuthorizationOptions) checkRoleBinding(originRoleBinding *author var errlist []error // convert the origin role binding to a rbac role binding - convertedRoleBinding, err := authorizationsync.ConvertToRBACRoleBinding(originRoleBinding) + convertedRoleBinding, err := util.ConvertToRBACRoleBinding(originRoleBinding) if err != nil { errlist = append(errlist, err) } @@ -218,7 +218,7 @@ func (o *MigrateAuthorizationOptions) checkRoleBinding(originRoleBinding *author // compare the results if there have been no errors so far if len(errlist) == 0 { // if they are not equal, something has gone wrong and the two objects are not in sync - if authorizationsync.PrepareForUpdateRoleBinding(convertedRoleBinding, rbacRoleBinding) { + if util.PrepareForUpdateRoleBinding(convertedRoleBinding, rbacRoleBinding) { errlist = append(errlist, errOutOfSync) } } diff --git a/pkg/project/registry/projectrequest/delegated/delegated_test.go b/pkg/project/registry/projectrequest/delegated/delegated_test.go deleted file mode 100644 index 6e8ee600a716..000000000000 --- a/pkg/project/registry/projectrequest/delegated/delegated_test.go +++ /dev/null @@ -1,87 +0,0 @@ -package delegated - -import ( - "sync" - "testing" - "time" - - "k8s.io/apimachinery/pkg/labels" - - authorizationapi "github.com/openshift/origin/pkg/authorization/apis/authorization" - authorizationlister "github.com/openshift/origin/pkg/authorization/generated/listers/authorization/internalversion" - "github.com/openshift/origin/pkg/cmd/server/bootstrappolicy" -) - -func TestDelegatedWait(t *testing.T) { - cache := &testReadOnlyPolicyBinding{} - storage := &REST{policyBindings: cache} - - cache.binding = &authorizationapi.PolicyBinding{} - cache.binding.RoleBindings = map[string]*authorizationapi.RoleBinding{} - cache.binding.RoleBindings["anything"] = nil - - callReturnedCh := testWait(storage) - - select { - case <-callReturnedCh: - t.Errorf("too fast, should have blocked") - case <-time.After(1 * time.Second): - } - - func() { - cache.lock.Lock() - defer cache.lock.Unlock() - cache.binding.RoleBindings[bootstrappolicy.AdminRoleName] = nil - }() - - select { - case <-callReturnedCh: - case <-time.After(1 * time.Second): - t.Errorf("too slow, should have returned") - } -} - -func testWait(storage *REST) chan struct{} { - ret := make(chan struct{}) - - go func() { - storage.waitForRoleBinding("foo", bootstrappolicy.AdminRoleName) - close(ret) - }() - - return ret -} - -type testReadOnlyPolicyBinding struct { - binding *authorizationapi.PolicyBinding - lock sync.Mutex -} - -func (t *testReadOnlyPolicyBinding) PolicyBindings(namespace string) authorizationlister.PolicyBindingNamespaceLister { - return t -} - -// ReadOnlyPolicyBindingInterface exposes methods on PolicyBindings resources -func (t *testReadOnlyPolicyBinding) List(label labels.Selector) ([]*authorizationapi.PolicyBinding, error) { - t.lock.Lock() - defer t.lock.Unlock() - - var ret []*authorizationapi.PolicyBinding - if t.binding != nil { - returning := authorizationapi.PolicyBinding{} - returning.RoleBindings = map[string]*authorizationapi.RoleBinding{} - for k, v := range t.binding.RoleBindings { - returning.RoleBindings[k] = v - } - - ret = []*authorizationapi.PolicyBinding{&returning} - } - - return ret, nil -} - -func (t *testReadOnlyPolicyBinding) Get(name string) (*authorizationapi.PolicyBinding, error) { - t.lock.Lock() - defer t.lock.Unlock() - return t.binding, nil -} diff --git a/test/extended/templates/templateinstance_impersonation.go b/test/extended/templates/templateinstance_impersonation.go index 9642e74db515..3d0f311c32eb 100644 --- a/test/extended/templates/templateinstance_impersonation.go +++ b/test/extended/templates/templateinstance_impersonation.go @@ -145,17 +145,6 @@ var _ = g.Describe("[templates] templateinstance impersonation tests", func() { }) o.Expect(err).NotTo(o.HaveOccurred()) - _, err = cli.AdminClient().PolicyBindings(cli.Namespace()).Create(&authorizationapi.PolicyBinding{ - ObjectMeta: metav1.ObjectMeta{ - Name: authorizationapi.GetPolicyBindingName(cli.Namespace()), - }, - PolicyRef: kapi.ObjectReference{ - Name: "default", - Namespace: cli.Namespace(), - }, - }) - o.Expect(err).NotTo(o.HaveOccurred()) - _, err = cli.AdminClient().RoleBindings(cli.Namespace()).Create(&authorizationapi.RoleBinding{ ObjectMeta: metav1.ObjectMeta{ Name: "impersonater-binding", diff --git a/test/integration/authorization_test.go b/test/integration/authorization_test.go index fdebde90f637..db0bfdc8edd6 100644 --- a/test/integration/authorization_test.go +++ b/test/integration/authorization_test.go @@ -306,7 +306,7 @@ func TestAuthorizationResolution(t *testing.T) { // the policy cache taking time to react if err := wait.Poll(time.Second, 2*time.Minute, func() (bool, error) { err := addValerie.AddRole() - if kapierror.IsNotFound(err) { + if err == nil || kapierror.IsNotFound(err) { // TODO what does this mean? return true, nil } return false, err @@ -318,7 +318,7 @@ func TestAuthorizationResolution(t *testing.T) { roleWithGroup.Name = "with-group" roleWithGroup.Rules = append(roleWithGroup.Rules, authorizationapi.PolicyRule{ Verbs: sets.NewString("list"), - Resources: sets.NewString("resourcegroup:builds"), + Resources: sets.NewString("builds"), // TODO we may need to track these down }) if _, err := clusterAdminClient.ClusterRoles().Create(roleWithGroup); err != nil { t.Fatalf("unexpected error: %v", err) @@ -628,7 +628,7 @@ func TestAuthorizationResourceAccessReview(t *testing.T) { Users: sets.NewString("edgar"), Groups: sets.NewString(), Namespace: "mallet-project", - EvaluationError: `[role.authorization.openshift.io "admin" not found, role.authorization.openshift.io "admin" not found]`, + EvaluationError: `[clusterrole.rbac.authorization.k8s.io "admin" not found, clusterrole.rbac.authorization.k8s.io "admin" not found]`, }, } test.response.Users.Insert(globalClusterReaderUsers.List()...) diff --git a/test/integration/etcd_storage_path_test.go b/test/integration/etcd_storage_path_test.go index 3ec34e686ce3..85019ede6a79 100644 --- a/test/integration/etcd_storage_path_test.go +++ b/test/integration/etcd_storage_path_test.go @@ -45,28 +45,45 @@ var etcdStorageData = map[schema.GroupVersionResource]struct { expectedGVK *schema.GroupVersionKind // The GVK that we expect this object to be stored as - leave this nil to use the default }{ // github.com/openshift/origin/pkg/authorization/apis/authorization/v1 - gvr("", "v1", "clusterpolicybindings"): { // no stub because cannot create one of these but it always exists - expectedEtcdPath: "openshift.io/authorization/cluster/policybindings/:default", - }, - gvr("authorization.openshift.io", "v1", "clusterpolicybindings"): { // no stub because cannot create one of these but it always exists - expectedEtcdPath: "openshift.io/authorization/cluster/policybindings/:default", - expectedGVK: gvkP("", "v1", "ClusterPolicyBinding"), // expect the legacy group to be persisted - }, - gvr("", "v1", "clusterpolicies"): { // no stub because cannot create one of these but it always exists - expectedEtcdPath: "openshift.io/authorization/cluster/policies/default", - }, - gvr("authorization.openshift.io", "v1", "clusterpolicies"): { // no stub because cannot create one of these but it always exists - expectedEtcdPath: "openshift.io/authorization/cluster/policies/default", - expectedGVK: gvkP("", "v1", "ClusterPolicy"), // expect the legacy group to be persisted - }, - gvr("", "v1", "policybindings"): { - stub: `{"metadata": {"name": ":default"}, "roleBindings": [{"name": "rb", "roleBinding": {"metadata": {"name": "rb", "namespace": "etcdstoragepathtestnamespace"}, "roleRef": {"name": "r"}}}]}`, - expectedEtcdPath: "openshift.io/authorization/local/policybindings/etcdstoragepathtestnamespace/:default", - }, - gvr("authorization.openshift.io", "v1", "policybindings"): { - stub: `{"metadata": {"name": ":default"}, "roleBindings": [{"name": "rb", "roleBinding": {"metadata": {"name": "rb", "namespace": "etcdstoragepathtestnamespace"}, "roleRef": {"name": "r"}}}]}`, - expectedEtcdPath: "openshift.io/authorization/local/policybindings/etcdstoragepathtestnamespace/:default", - expectedGVK: gvkP("", "v1", "PolicyBinding"), // expect the legacy group to be persisted + gvr("", "v1", "roles"): { + stub: `{"metadata": {"name": "r1b1o1"}, "rules": [{"verbs": ["create"], "apiGroups": ["authorization.k8s.io"], "resources": ["selfsubjectaccessreviews"]}]}`, + expectedEtcdPath: "kubernetes.io/roles/etcdstoragepathtestnamespace/r1b1o1", + expectedGVK: gvkP("rbac.authorization.k8s.io", "v1beta1", "Role"), // proxy to RBAC + }, + gvr("authorization.openshift.io", "v1", "roles"): { + stub: `{"metadata": {"name": "r1b1o2"}, "rules": [{"verbs": ["create"], "apiGroups": ["authorization.k8s.io"], "resources": ["selfsubjectaccessreviews"]}]}`, + expectedEtcdPath: "kubernetes.io/roles/etcdstoragepathtestnamespace/r1b1o2", + expectedGVK: gvkP("rbac.authorization.k8s.io", "v1beta1", "Role"), // proxy to RBAC + }, + gvr("", "v1", "clusterroles"): { + stub: `{"metadata": {"name": "cr1a1o1"}, "rules": [{"verbs": ["create"], "apiGroups": ["authorization.k8s.io"], "resources": ["selfsubjectaccessreviews"]}]}`, + expectedEtcdPath: "kubernetes.io/clusterroles/cr1a1o1", + expectedGVK: gvkP("rbac.authorization.k8s.io", "v1beta1", "ClusterRole"), // proxy to RBAC + }, + gvr("authorization.openshift.io", "v1", "clusterroles"): { + stub: `{"metadata": {"name": "cr1a1o2"}, "rules": [{"verbs": ["create"], "apiGroups": ["authorization.k8s.io"], "resources": ["selfsubjectaccessreviews"]}]}`, + expectedEtcdPath: "kubernetes.io/clusterroles/cr1a1o2", + expectedGVK: gvkP("rbac.authorization.k8s.io", "v1beta1", "ClusterRole"), // proxy to RBAC + }, + gvr("", "v1", "rolebindings"): { + stub: `{"metadata": {"name": "rb1a1o1"}, "subjects": [{"kind": "Group", "name": "system:authenticated"}], "roleRef": {"kind": "Role", "name": "r1a1"}}`, + expectedEtcdPath: "kubernetes.io/rolebindings/etcdstoragepathtestnamespace/rb1a1o1", + expectedGVK: gvkP("rbac.authorization.k8s.io", "v1beta1", "RoleBinding"), // proxy to RBAC + }, + gvr("authorization.openshift.io", "v1", "rolebindings"): { + stub: `{"metadata": {"name": "rb1a1o2"}, "subjects": [{"kind": "Group", "name": "system:authenticated"}], "roleRef": {"kind": "Role", "name": "r1a1"}}`, + expectedEtcdPath: "kubernetes.io/rolebindings/etcdstoragepathtestnamespace/rb1a1o2", + expectedGVK: gvkP("rbac.authorization.k8s.io", "v1beta1", "RoleBinding"), // proxy to RBAC + }, + gvr("", "v1", "clusterrolebindings"): { + stub: `{"metadata": {"name": "crb1a1o1"}, "subjects": [{"kind": "Group", "name": "system:authenticated"}], "roleRef": {"kind": "ClusterRole", "name": "cr1a1"}}`, + expectedEtcdPath: "kubernetes.io/clusterrolebindings/crb1a1o1", + expectedGVK: gvkP("rbac.authorization.k8s.io", "v1beta1", "ClusterRoleBinding"), // proxy to RBAC + }, + gvr("authorization.openshift.io", "v1", "clusterrolebindings"): { + stub: `{"metadata": {"name": "crb1a1o2"}, "subjects": [{"kind": "Group", "name": "system:authenticated"}], "roleRef": {"kind": "ClusterRole", "name": "cr1a1"}}`, + expectedEtcdPath: "kubernetes.io/clusterrolebindings/crb1a1o2", + expectedGVK: gvkP("rbac.authorization.k8s.io", "v1beta1", "ClusterRoleBinding"), // proxy to RBAC }, gvr("", "v1", "rolebindingrestrictions"): { stub: `{"metadata": {"name": "rbr"}, "spec": {"serviceaccountrestriction": {"serviceaccounts": [{"name": "sa"}]}}}`, @@ -77,15 +94,6 @@ var etcdStorageData = map[schema.GroupVersionResource]struct { expectedEtcdPath: "openshift.io/rolebindingrestrictions/etcdstoragepathtestnamespace/rbrg", expectedGVK: gvkP("", "v1", "RoleBindingRestriction"), // expect the legacy group to be persisted }, - gvr("", "v1", "policies"): { - stub: `{"metadata": {"name": "default"}, "roles": [{"name": "r", "role": {"metadata": {"name": "r", "namespace": "etcdstoragepathtestnamespace"}}}]}`, - expectedEtcdPath: "openshift.io/authorization/local/policies/etcdstoragepathtestnamespace/default", - }, - gvr("authorization.openshift.io", "v1", "policies"): { - stub: `{"metadata": {"name": "default"}, "roles": [{"name": "r", "role": {"metadata": {"name": "r", "namespace": "etcdstoragepathtestnamespace"}}}]}`, - expectedEtcdPath: "openshift.io/authorization/local/policies/etcdstoragepathtestnamespace/default", - expectedGVK: gvkP("", "v1", "Policy"), // expect the legacy group to be persisted - }, // -- // github.com/openshift/origin/pkg/build/apis/build/v1 @@ -617,15 +625,15 @@ var etcdStorageData = map[schema.GroupVersionResource]struct { var ephemeralWhiteList = createEphemeralWhiteList( // github.com/openshift/origin/pkg/authorization/apis/authorization/v1 - // virtual objects that are not stored in etcd // TODO this will change in the future when policies go away - gvr("", "v1", "roles"), - gvr("authorization.openshift.io", "v1", "roles"), - gvr("", "v1", "clusterroles"), - gvr("authorization.openshift.io", "v1", "clusterroles"), - gvr("", "v1", "rolebindings"), - gvr("authorization.openshift.io", "v1", "rolebindings"), - gvr("", "v1", "clusterrolebindings"), - gvr("authorization.openshift.io", "v1", "clusterrolebindings"), + // All {cluster}policy{binding} objects are deprecated + gvr("", "v1", "clusterpolicybindings"), + gvr("authorization.openshift.io", "v1", "clusterpolicybindings"), + gvr("", "v1", "clusterpolicies"), + gvr("authorization.openshift.io", "v1", "clusterpolicies"), + gvr("", "v1", "policybindings"), + gvr("authorization.openshift.io", "v1", "policybindings"), + gvr("", "v1", "policies"), + gvr("authorization.openshift.io", "v1", "policies"), // SAR objects that are not stored in etcd gvr("", "v1", "subjectrulesreviews"), @@ -1033,9 +1041,7 @@ func testEtcdStoragePath(t *testing.T, etcdServer *etcdtest.EtcdTestServer, gett } addGVKToEtcdBucket(cohabitatingResources, actualGVK, getEtcdBucket(testData.expectedEtcdPath)) - if !isSingletonResource(gvResource) { - pathSeen[testData.expectedEtcdPath] = append(pathSeen[testData.expectedEtcdPath], gvResource) - } + pathSeen[testData.expectedEtcdPath] = append(pathSeen[testData.expectedEtcdPath], gvResource) }() } @@ -1094,23 +1100,6 @@ func getEtcdBucket(path string) string { return bucket } -// isSingletonResource is used to determine if an object can have duplicate expectedEtcdPath test data. -// Do not add new objects to this list. -func isSingletonResource(gvResource schema.GroupVersionResource) bool { - switch gvResource { - case gvr("", "v1", "clusterpolicies"), - gvr("", "v1", "policies"), - gvr("", "v1", "clusterpolicybindings"), - gvr("", "v1", "policybindings"), - gvr("authorization.openshift.io", "v1", "clusterpolicies"), - gvr("authorization.openshift.io", "v1", "policies"), - gvr("authorization.openshift.io", "v1", "clusterpolicybindings"), - gvr("authorization.openshift.io", "v1", "policybindings"): - return true - } - return false -} - // stable fields to compare as a sanity check type metaObject struct { // all of type meta diff --git a/test/integration/project_request_test.go b/test/integration/project_request_test.go index 333a4fdbf1d5..9279bb896363 100644 --- a/test/integration/project_request_test.go +++ b/test/integration/project_request_test.go @@ -70,7 +70,7 @@ func TestProjectRequestError(t *testing.T) { if err != nil { t.Fatal(err) } - policywatch, err := openshiftClient.PolicyBindings(ns).Watch(metav1.ListOptions{}) + roleWatch, err := kubeClientset.Rbac().RoleBindings(ns).Watch(metav1.ListOptions{}) if err != nil { t.Fatal(err) } @@ -115,11 +115,11 @@ func TestProjectRequestError(t *testing.T) { } t.Errorf("expected 1 namespace to be added and deleted, got %d added / %d deleted", added, deleted) } - if added, deleted, events := pairCreationDeletion(policywatch); added != deleted || added != 1 { + if added, deleted, events := pairCreationDeletion(roleWatch); added != deleted || added != 4 { for _, e := range events { t.Logf("%s %#v", e.Type, e.Object) } - t.Errorf("expected 1 policybinding to be added and deleted, got %d added / %d deleted", added, deleted) + t.Errorf("expected 4 (1 admin + 3 SA) roleBindings to be added and deleted, got %d added / %d deleted", added, deleted) } if added, deleted, events := pairCreationDeletion(cmwatch); added != deleted || added != 1 { for _, e := range events { diff --git a/test/integration/rbac_controller_test.go b/test/integration/rbac_controller_test.go deleted file mode 100644 index 6b0f67083174..000000000000 --- a/test/integration/rbac_controller_test.go +++ /dev/null @@ -1,215 +0,0 @@ -package integration - -import ( - "testing" - "time" - - kapierrors "k8s.io/apimachinery/pkg/api/errors" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/util/wait" - kapi "k8s.io/kubernetes/pkg/api" - - authorizationapi "github.com/openshift/origin/pkg/authorization/apis/authorization" - testutil "github.com/openshift/origin/test/util" - testserver "github.com/openshift/origin/test/util/server" -) - -func TestRBACController(t *testing.T) { - masterConfig, clusterAdminKubeConfig, err := testserver.StartTestMaster() - if err != nil { - t.Fatal(err) - } - defer testserver.CleanupMasterEtcd(t, masterConfig) - - originClient, err := testutil.GetClusterAdminClient(clusterAdminKubeConfig) - if err != nil { - t.Fatal(err) - } - kubeClient, err := testutil.GetClusterAdminKubeClient(clusterAdminKubeConfig) - if err != nil { - t.Fatal(err) - } - - ns := "rbac-controller-namespace" - - if _, err := kubeClient.Core().Namespaces().Create(&kapi.Namespace{ObjectMeta: metav1.ObjectMeta{Name: ns}}); err != nil { - t.Fatalf("Error creating namespace: %v", err) - } - - // Initial creation - clusterrole, err := originClient.ClusterRoles().Create(&authorizationapi.ClusterRole{ - ObjectMeta: metav1.ObjectMeta{Name: "rbac-controller-clusterrole"}, - }) - if err != nil { - t.Fatal(err) - } - clusterrolebinding, err := originClient.ClusterRoleBindings().Create(&authorizationapi.ClusterRoleBinding{ - ObjectMeta: metav1.ObjectMeta{Name: "rbac-controller-clusterrolebinding"}, - RoleRef: kapi.ObjectReference{Name: "rbac-controller-clusterrole"}, - }) - if err != nil { - t.Fatal(err) - } - role, err := originClient.Roles(ns).Create(&authorizationapi.Role{ - ObjectMeta: metav1.ObjectMeta{Name: "rbac-controller-role"}, - }) - if err != nil { - t.Fatal(err) - } - rolebinding, err := originClient.RoleBindings(ns).Create(&authorizationapi.RoleBinding{ - ObjectMeta: metav1.ObjectMeta{Name: "rbac-controller-rolebinding"}, - RoleRef: kapi.ObjectReference{Name: "rbac-controller-role", Namespace: ns}, - }) - if err != nil { - t.Fatal(err) - } - - // Ensure propagation - err = wait.PollImmediate(time.Second, time.Minute, func() (bool, error) { - if _, err := kubeClient.Rbac().ClusterRoles().Get(clusterrole.Name, metav1.GetOptions{}); kapierrors.IsNotFound(err) { - t.Logf("Retrying: %v", err) - return false, nil - } else if err != nil { - t.Fatal(err) - } - - if _, err := kubeClient.Rbac().Roles(ns).Get(role.Name, metav1.GetOptions{}); kapierrors.IsNotFound(err) { - t.Logf("Retrying: %v", err) - return false, nil - } else if err != nil { - t.Fatal(err) - } - - if _, err := kubeClient.Rbac().ClusterRoleBindings().Get(clusterrolebinding.Name, metav1.GetOptions{}); kapierrors.IsNotFound(err) { - t.Logf("Retrying: %v", err) - return false, nil - } else if err != nil { - t.Fatal(err) - } - - if _, err := kubeClient.Rbac().RoleBindings(ns).Get(rolebinding.Name, metav1.GetOptions{}); kapierrors.IsNotFound(err) { - t.Logf("Retrying: %v", err) - return false, nil - } else if err != nil { - t.Fatal(err) - } - - return true, nil - }) - if err != nil { - t.Fatalf("created objects did not propagate: %v", err) - } - - // Update - clusterrole.Labels = map[string]string{"updated": "true"} - clusterrolebinding.Labels = map[string]string{"updated": "true"} - role.Labels = map[string]string{"updated": "true"} - rolebinding.Labels = map[string]string{"updated": "true"} - - clusterrole, err = originClient.ClusterRoles().Update(clusterrole) - if err != nil { - t.Fatal(err) - } - clusterrolebinding, err = originClient.ClusterRoleBindings().Update(clusterrolebinding) - if err != nil { - t.Fatal(err) - } - role, err = originClient.Roles(ns).Update(role) - if err != nil { - t.Fatal(err) - } - rolebinding, err = originClient.RoleBindings(ns).Update(rolebinding) - if err != nil { - t.Fatal(err) - } - - // Ensure propagation - err = wait.PollImmediate(time.Second, time.Minute, func() (bool, error) { - if rbacObject, err := kubeClient.Rbac().ClusterRoles().Get(clusterrole.Name, metav1.GetOptions{}); err != nil { - t.Fatal(err) - } else if rbacObject.Labels["updated"] != "true" { - t.Logf("not updated yet: %#v", rbacObject) - return false, nil - } - - if rbacObject, err := kubeClient.Rbac().Roles(ns).Get(role.Name, metav1.GetOptions{}); err != nil { - t.Fatal(err) - } else if rbacObject.Labels["updated"] != "true" { - t.Logf("not updated yet: %#v", rbacObject) - return false, nil - } - - if rbacObject, err := kubeClient.Rbac().ClusterRoleBindings().Get(clusterrolebinding.Name, metav1.GetOptions{}); err != nil { - t.Fatal(err) - } else if rbacObject.Labels["updated"] != "true" { - t.Logf("not updated yet: %#v", rbacObject) - return false, nil - } - - if rbacObject, err := kubeClient.Rbac().RoleBindings(ns).Get(rolebinding.Name, metav1.GetOptions{}); err != nil { - t.Fatal(err) - } else if rbacObject.Labels["updated"] != "true" { - t.Logf("not updated yet: %#v", rbacObject) - return false, nil - } - - return true, nil - }) - if err != nil { - t.Fatalf("updated objects did not propagate: %v", err) - } - - // Delete - err = originClient.ClusterRoles().Delete(clusterrole.Name) - if err != nil { - t.Fatal(err) - } - err = originClient.ClusterRoleBindings().Delete(clusterrolebinding.Name) - if err != nil { - t.Fatal(err) - } - err = originClient.Roles(ns).Delete(role.Name) - if err != nil { - t.Fatal(err) - } - err = originClient.RoleBindings(ns).Delete(rolebinding.Name) - if err != nil { - t.Fatal(err) - } - - // Ensure propagation - err = wait.PollImmediate(time.Second, time.Minute, func() (bool, error) { - if rbacObject, err := kubeClient.Rbac().ClusterRoles().Get(clusterrole.Name, metav1.GetOptions{}); err != nil && !kapierrors.IsNotFound(err) { - t.Fatal(err) - } else if err == nil { - t.Logf("not deleted yet: %#v", rbacObject) - return false, nil - } - - if rbacObject, err := kubeClient.Rbac().Roles(ns).Get(role.Name, metav1.GetOptions{}); err != nil && !kapierrors.IsNotFound(err) { - t.Fatal(err) - } else if err == nil { - t.Logf("not deleted yet: %#v", rbacObject) - return false, nil - } - - if rbacObject, err := kubeClient.Rbac().ClusterRoleBindings().Get(clusterrolebinding.Name, metav1.GetOptions{}); err != nil && !kapierrors.IsNotFound(err) { - t.Fatal(err) - } else if err == nil { - t.Logf("not deleted yet: %#v", rbacObject) - return false, nil - } - - if rbacObject, err := kubeClient.Rbac().RoleBindings(ns).Get(rolebinding.Name, metav1.GetOptions{}); err != nil && !kapierrors.IsNotFound(err) { - t.Fatal(err) - } else if err == nil { - t.Logf("not deleted yet: %#v", rbacObject) - return false, nil - } - - return true, nil - }) - if err != nil { - t.Fatalf("deleted objects did not propagate: %v", err) - } -} diff --git a/test/integration/restrictusers_test.go b/test/integration/restrictusers_test.go index 6a6575d94697..6cb74206beb4 100644 --- a/test/integration/restrictusers_test.go +++ b/test/integration/restrictusers_test.go @@ -58,20 +58,6 @@ func TestRestrictUsers(t *testing.T) { t.Fatalf("unexpected error: %v", err) } - policyBinding := &authorizationapi.PolicyBinding{ - ObjectMeta: metav1.ObjectMeta{ - Namespace: "namespace", - Name: "policybinding", - }, - PolicyRef: kapi.ObjectReference{ - Namespace: "namespace", - Name: authorizationapi.GetPolicyBindingName("policy"), - }, - } - if _, err := clusterAdminClient.PolicyBindings("namespace").Create(policyBinding); err != nil { - t.Fatalf("unexpected error: %v", err) - } - rolebindingAlice := &authorizationapi.RoleBinding{ ObjectMeta: metav1.ObjectMeta{ Namespace: "namespace",