Skip to content

Commit

Permalink
Refactor and add finalizers in managedClsuterRoleBinding (#14)
Browse files Browse the repository at this point in the history
Signed-off-by: Rokibul Hasan <mdrokibulhasan@appscode.com>
  • Loading branch information
RokibulHasan7 authored Jun 14, 2024
1 parent 7049c6c commit 6e6ce8c
Show file tree
Hide file tree
Showing 473 changed files with 359 additions and 128,940 deletions.
15 changes: 0 additions & 15 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ require (
)

require (
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
github.com/BurntSushi/toml v1.3.2 // indirect
github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/semver/v3 v3.2.1 // indirect
Expand All @@ -40,7 +39,6 @@ require (
github.com/evanphx/json-patch/v5 v5.8.0 // indirect
github.com/fatih/structs v1.1.0 // indirect
github.com/fsnotify/fsnotify v1.7.0 // indirect
github.com/go-errors/errors v1.4.2 // indirect
github.com/go-logr/logr v1.4.1 // indirect
github.com/go-logr/zapr v1.3.0 // indirect
github.com/go-openapi/jsonpointer v0.20.0 // indirect
Expand All @@ -50,35 +48,28 @@ require (
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.4 // indirect
github.com/google/btree v1.1.2 // indirect
github.com/google/gnostic-models v0.6.8 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/google/go-containerregistry v0.19.1 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 // indirect
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect
github.com/huandu/xstrings v1.4.0 // indirect
github.com/imdario/mergo v0.3.16 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/cpuid/v2 v2.0.9 // indirect
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/matttproud/golang_protobuf_extensions/v2 v2.0.0 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
github.com/mitchellh/mapstructure v1.5.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/moby/term v0.5.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/nxadm/tail v1.4.11 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/prometheus/client_golang v1.18.0 // indirect
github.com/prometheus/client_model v0.5.0 // indirect
Expand All @@ -92,18 +83,15 @@ require (
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
github.com/xlab/treeprint v1.2.0 // indirect
github.com/yudai/gojsondiff v1.0.0 // indirect
github.com/yudai/golcs v0.0.0-20170316035057-ecda9a501e82 // indirect
github.com/zeebo/xxh3 v1.0.2 // indirect
go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.26.0 // indirect
golang.org/x/crypto v0.21.0 // indirect
golang.org/x/exp v0.0.0-20230905200255-921286631fa9 // indirect
golang.org/x/net v0.23.0 // indirect
golang.org/x/oauth2 v0.15.0 // indirect
golang.org/x/sync v0.5.0 // indirect
golang.org/x/sys v0.18.0 // indirect
golang.org/x/term v0.18.0 // indirect
golang.org/x/text v0.14.0 // indirect
Expand All @@ -125,12 +113,9 @@ require (
helm.sh/helm/v3 v3.14.3 // indirect
k8s.io/apiextensions-apiserver v0.29.2 // indirect
k8s.io/apiserver v0.29.2 // indirect
k8s.io/cli-runtime v0.29.2 // indirect
k8s.io/component-base v0.29.2 // indirect
k8s.io/kube-openapi v0.0.0-20240403164606-bc84c2ddaf99 // indirect
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
sigs.k8s.io/kustomize/api v0.13.5-0.20230601165947-6ce0bf390ce3 // indirect
sigs.k8s.io/kustomize/kyaml v0.14.3-0.20230601165947-6ce0bf390ce3 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
)

Expand Down
67 changes: 0 additions & 67 deletions go.sum

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion pkg/agent/controller/managedclusterrole_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,8 @@ func (r *ManagedClusterRoleReconciler) Reconcile(ctx context.Context, req ctrl.R
// create clusterRole in spoke cluster
cr := &rbac.ClusterRole{
ObjectMeta: metav1.ObjectMeta{
Name: managedClusterRole.Name,
Name: managedClusterRole.Name,
Labels: managedClusterRole.Labels,
},
Rules: managedClusterRole.Rules,
}
Expand Down
176 changes: 136 additions & 40 deletions pkg/agent/controller/managedclusterrolebinding_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,20 @@ package controller

import (
"context"
"fmt"

authzv1alpah1 "github.com/kluster-manager/cluster-auth/apis/authorization/v1alpha1"
"github.com/kluster-manager/cluster-auth/pkg/common"
"github.com/kluster-manager/cluster-auth/pkg/utils"

rbac "k8s.io/api/rbac/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/util/rand"
cu "kmodules.xyz/client-go/client"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
"sigs.k8s.io/controller-runtime/pkg/handler"
"sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
Expand Down Expand Up @@ -58,13 +64,35 @@ func (r *ManagedClusterRoleBindingReconciler) Reconcile(ctx context.Context, req
if err := r.HubClient.Get(ctx, req.NamespacedName, &managedCRB); err != nil {
return reconcile.Result{}, err
}

_, hubOwnerID := utils.GetUserIDAndHubOwnerIDFromLabelValues(&managedCRB)
userName := managedCRB.Subjects[0].Name

// Check if the managedCRB is marked for deletion
if managedCRB.GetDeletionTimestamp() != nil {
if controllerutil.ContainsFinalizer(&managedCRB, common.SpokeAuthorizationFinalizer) {
// Perform cleanup logic, e.g., delete related resources
if err := r.deleteAssociatedResources(&managedCRB); err != nil {
return reconcile.Result{}, err
}
// Remove the finalizer
controllerutil.RemoveFinalizer(&managedCRB, common.SpokeAuthorizationFinalizer)
if err := r.HubClient.Update(context.TODO(), &managedCRB); err != nil {
return reconcile.Result{}, err
}
}
return reconcile.Result{}, nil
}

// Add finalizer if not present
if err := r.addFinalizerIfNeeded(&managedCRB); err != nil {
return reconcile.Result{}, err
}

// impersonate clusterRole
clusterRole := &rbac.ClusterRole{
cr := rbac.ClusterRole{
ObjectMeta: metav1.ObjectMeta{
Name: "impersonate-" + userName,
Name: fmt.Sprintf("impersonate-%s-%s-%s", userName, hubOwnerID, rand.String(7)),
Labels: managedCRB.Labels,
},
Rules: []rbac.PolicyRule{
{
Expand All @@ -76,19 +104,29 @@ func (r *ManagedClusterRoleBindingReconciler) Reconcile(ctx context.Context, req
},
}

_, err := cu.CreateOrPatch(context.Background(), r.SpokeClient, clusterRole, func(obj client.Object, createOp bool) client.Object {
crList := &rbac.ClusterRoleList{}
_ = r.SpokeClient.List(ctx, crList, client.MatchingLabelsSelector{
Selector: labels.SelectorFromSet(managedCRB.Labels),
})

if len(crList.Items) > 0 {
cr = crList.Items[0]
}

_, err := cu.CreateOrPatch(context.Background(), r.SpokeClient, &cr, func(obj client.Object, createOp bool) client.Object {
in := obj.(*rbac.ClusterRole)
in.Rules = clusterRole.Rules
in.Rules = cr.Rules
return in
})
if err != nil {
return reconcile.Result{}, err
}

// this clusterRoleBinding will give permission to the user
crb := &rbac.ClusterRoleBinding{
crb := rbac.ClusterRoleBinding{
ObjectMeta: metav1.ObjectMeta{
Name: "impersonate-" + userName + "-rolebinding",
Name: cr.Name,
Labels: managedCRB.Labels,
},
Subjects: []rbac.Subject{
{
Expand All @@ -101,11 +139,20 @@ func (r *ManagedClusterRoleBindingReconciler) Reconcile(ctx context.Context, req
RoleRef: rbac.RoleRef{
APIGroup: rbac.GroupName,
Kind: "ClusterRole",
Name: "impersonate-" + userName,
Name: cr.Name,
},
}

_, err = cu.CreateOrPatch(context.Background(), r.SpokeClient, crb, func(obj client.Object, createOp bool) client.Object {
crbList := &rbac.ClusterRoleBindingList{}
_ = r.SpokeClient.List(ctx, crbList, client.MatchingLabelsSelector{
Selector: labels.SelectorFromSet(managedCRB.Labels),
})

if len(crbList.Items) > 0 {
crb = crbList.Items[0]
}

_, err = cu.CreateOrPatch(context.Background(), r.SpokeClient, &crb, func(obj client.Object, createOp bool) client.Object {
in := obj.(*rbac.ClusterRoleBinding)
in.Subjects = crb.Subjects
in.RoleRef = crb.RoleRef
Expand All @@ -115,6 +162,7 @@ func (r *ManagedClusterRoleBindingReconciler) Reconcile(ctx context.Context, req
return reconcile.Result{}, err
}

// now give actual permission to the User
sub := []rbac.Subject{
{
APIGroup: "",
Expand All @@ -130,10 +178,8 @@ func (r *ManagedClusterRoleBindingReconciler) Reconcile(ctx context.Context, req
Kind: "ClusterRoleBinding",
},
ObjectMeta: metav1.ObjectMeta{
Name: managedCRB.Name,
Labels: map[string]string{
"authentication.k8s.appscode.com/username": managedCRB.Subjects[0].Name,
},
Name: managedCRB.Name,
Labels: managedCRB.Labels,
},
Subjects: sub,
RoleRef: rbac.RoleRef{
Expand All @@ -142,7 +188,6 @@ func (r *ManagedClusterRoleBindingReconciler) Reconcile(ctx context.Context, req
Name: managedCRB.RoleRef.Name,
},
}

_, err = cu.CreateOrPatch(context.Background(), r.SpokeClient, givenClusterRolebinding, func(obj client.Object, createOp bool) client.Object {
in := obj.(*rbac.ClusterRoleBinding)
in.Subjects = givenClusterRolebinding.Subjects
Expand All @@ -153,39 +198,90 @@ func (r *ManagedClusterRoleBindingReconciler) Reconcile(ctx context.Context, req
return reconcile.Result{}, err
}
} else {
givenRolebinding := &rbac.RoleBinding{
TypeMeta: metav1.TypeMeta{
APIVersion: rbac.SchemeGroupVersion.String(),
Kind: "RoleBinding",
},
ObjectMeta: metav1.ObjectMeta{
Name: managedCRB.Name,
Namespace: managedCRB.Namespace,
Labels: map[string]string{
"authentication.k8s.appscode.com/username": managedCRB.Subjects[0].Name,
for _, ns := range managedCRB.RoleRef.Namespaces {
givenRolebinding := &rbac.RoleBinding{
TypeMeta: metav1.TypeMeta{
APIVersion: rbac.SchemeGroupVersion.String(),
Kind: "RoleBinding",
},
},
Subjects: sub,
RoleRef: rbac.RoleRef{
APIGroup: rbac.GroupName,
Kind: "Role",
Name: managedCRB.RoleRef.Name,
},
}
ObjectMeta: metav1.ObjectMeta{
Name: managedCRB.Name,
Namespace: ns,
Labels: managedCRB.Labels,
},
Subjects: sub,
RoleRef: rbac.RoleRef{
APIGroup: rbac.GroupName,
Kind: "Role",
Name: managedCRB.RoleRef.Name,
},
}

_, err = cu.CreateOrPatch(context.Background(), r.SpokeClient, givenRolebinding, func(obj client.Object, createOp bool) client.Object {
in := obj.(*rbac.RoleBinding)
in.Subjects = givenRolebinding.Subjects
in.RoleRef = givenRolebinding.RoleRef
return in
})
if err != nil {
return reconcile.Result{}, err
_, err = cu.CreateOrPatch(context.Background(), r.SpokeClient, givenRolebinding, func(obj client.Object, createOp bool) client.Object {
in := obj.(*rbac.RoleBinding)
in.Subjects = givenRolebinding.Subjects
in.RoleRef = givenRolebinding.RoleRef
return in
})
if err != nil {
return reconcile.Result{}, err
}
}
}
return reconcile.Result{}, nil
}

// AddFinalizerIfNeeded adds a finalizer to the CRD instance if it doesn't already have one
func (r *ManagedClusterRoleBindingReconciler) addFinalizerIfNeeded(managedCRB *authzv1alpah1.ManagedClusterRoleBinding) error {
if !controllerutil.ContainsFinalizer(managedCRB, common.SpokeAuthorizationFinalizer) {
controllerutil.AddFinalizer(managedCRB, common.SpokeAuthorizationFinalizer)
if err := r.HubClient.Update(context.TODO(), managedCRB); err != nil {
return err
}
}
return nil
}

func (r *ManagedClusterRoleBindingReconciler) deleteAssociatedResources(managedCRB *authzv1alpah1.ManagedClusterRoleBinding) error {
crList := rbac.ClusterRoleList{}
err := r.SpokeClient.List(context.TODO(), &crList, client.MatchingLabelsSelector{
Selector: labels.SelectorFromSet(managedCRB.Labels),
})
if err == nil {
for _, cr := range crList.Items {
if err := r.SpokeClient.Delete(context.TODO(), &cr); err != nil {
return err
}
}
}

crbList := rbac.ClusterRoleBindingList{}
err = r.SpokeClient.List(context.TODO(), &crbList, client.MatchingLabelsSelector{
Selector: labels.SelectorFromSet(managedCRB.Labels),
})
if err == nil {
for _, crb := range crbList.Items {
if err := r.SpokeClient.Delete(context.TODO(), &crb); err != nil {
return err
}
}
}

rbList := rbac.RoleBindingList{}
err = r.SpokeClient.List(context.TODO(), &rbList, client.MatchingLabelsSelector{
Selector: labels.SelectorFromSet(managedCRB.Labels),
})
if err == nil {
for _, rb := range rbList.Items {
if err := r.SpokeClient.Delete(context.TODO(), &rb); err != nil {
return err
}
}
}

return nil
}

// SetupWithManager sets up the controller with the Manager.
func (r *ManagedClusterRoleBindingReconciler) SetupWithManager(mgr ctrl.Manager) error {
return ctrl.NewControllerManagedBy(mgr).
Expand Down
17 changes: 11 additions & 6 deletions pkg/common/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,15 @@ limitations under the License.
package common

const (
AddonName = "cluster-auth"
AgentName = "cluster-auth"
AddonAgentInstallNamespace = "open-cluster-management-" + AddonName
AgentManifestsDir = "agent-manifests/" + AddonName
GatewayProxyClusterRole = "open-cluster-management:cluster-gateway:proxy"
HubKubeconfigSecretName = "cluster-auth-hub-kubeconfig"
AddonName = "cluster-auth"
AgentName = "cluster-auth"
AddonAgentInstallNamespace = "open-cluster-management-" + AddonName
AgentManifestsDir = "agent-manifests/" + AddonName
GatewayProxyClusterRole = "open-cluster-management:cluster-gateway:proxy"
HubKubeconfigSecretName = "cluster-auth-hub-kubeconfig"
HubAuthorizationFinalizer = "authorization.hub.appscode.com"
SpokeAuthorizationFinalizer = "authorization.spoke.appscode.com"
UserAuthLabel = "authentication.k8s.appscode.com/user"
HubOwnerLabel = "authentication.k8s.appscode.com/hub-owner"
HubClusterIdLabel = "cluster.k8s.appscode.com/cluster-id"
)
Loading

0 comments on commit 6e6ce8c

Please sign in to comment.