Skip to content

Commit

Permalink
switch to role
Browse files Browse the repository at this point in the history
  • Loading branch information
agouin committed Oct 18, 2023
1 parent b52072d commit 153cb45
Show file tree
Hide file tree
Showing 7 changed files with 63 additions and 58 deletions.
6 changes: 4 additions & 2 deletions config/rbac/role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -148,11 +148,13 @@ rules:
- apiGroups:
- rbac.authorization.k8s.io
resources:
- clusterrolebindings
- clusterroles
- rolebindings
- roles
verbs:
- bind
- create
- delete
- escalate
- get
- list
- patch
Expand Down
10 changes: 5 additions & 5 deletions controllers/cosmosfullnode_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ type CosmosFullNodeReconciler struct {
serviceControl fullnode.ServiceControl
statusClient *fullnode.StatusClient
serviceAccountControl fullnode.ServiceAccountControl
clusterRoleControl fullnode.ClusterRoleControl
clusterRoleBindingControl fullnode.ClusterRoleBindingControl
clusterRoleControl fullnode.RoleControl
clusterRoleBindingControl fullnode.RoleBindingControl
}

// NewFullNode returns a valid CosmosFullNode controller.
Expand All @@ -77,8 +77,8 @@ func NewFullNode(
serviceControl: fullnode.NewServiceControl(client),
statusClient: statusClient,
serviceAccountControl: fullnode.NewServiceAccountControl(client),
clusterRoleControl: fullnode.NewClusterRoleControl(client),
clusterRoleBindingControl: fullnode.NewClusterRoleBindingControl(client),
clusterRoleControl: fullnode.NewRoleControl(client),
clusterRoleBindingControl: fullnode.NewRoleBindingControl(client),
}
}

Expand All @@ -92,7 +92,7 @@ var (
//+kubebuilder:rbac:groups=cosmos.strange.love,resources=cosmosfullnodes/finalizers,verbs=update
// Generate RBAC roles to watch and update resources. IMPORTANT!!!! All resource names must be lowercase or cluster role will not work.
//+kubebuilder:rbac:groups="",resources=pods;persistentvolumeclaims;services;serviceaccounts;configmaps,verbs=get;list;watch;create;update;patch;delete
//+kubebuilder:rbac:groups="rbac.authorization.k8s.io",resources=clusterroles;clusterrolebindings,verbs=get;list;watch;create;update;patch;delete
//+kubebuilder:rbac:groups="rbac.authorization.k8s.io",resources=roles;rolebindings,verbs=get;list;watch;create;update;patch;delete;bind;escalate
//+kubebuilder:rbac:groups="",resources=secrets,verbs=get;list;watch;create;update;patch
//+kubebuilder:rbac:groups="",resources=events,verbs=create;update;patch

Expand Down
40 changes: 22 additions & 18 deletions internal/fullnode/rbac_builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,12 @@ func serviceAccountName(crd *cosmosv1.CosmosFullNode) string {
return crd.Name + "-vc"
}

func clusterRoleName(crd *cosmosv1.CosmosFullNode) string {
return crd.Name + "-cr"
func roleName(crd *cosmosv1.CosmosFullNode) string {
return crd.Namespace + "-" + crd.Name + "-cr"
}

func roleBindingName(crd *cosmosv1.CosmosFullNode) string {
return crd.Namespace + "-" + crd.Name + "-crb"
}

// BuildServiceAccounts returns a list of service accounts given the crd.
Expand All @@ -40,18 +44,18 @@ func BuildServiceAccounts(crd *cosmosv1.CosmosFullNode) []diff.Resource[*corev1.
return diffSa
}

// BuildClusterRoles returns a list of cluster roles given the crd.
// BuildRoles returns a list of role bindings given the crd.
//
// Creates a single cluster role for the version check.
func BuildClusterRoles(crd *cosmosv1.CosmosFullNode) []diff.Resource[*rbacv1.ClusterRole] {
diffCr := make([]diff.Resource[*rbacv1.ClusterRole], 1)
cr := rbacv1.ClusterRole{
// Creates a single role binding for the version check.
func BuildRoles(crd *cosmosv1.CosmosFullNode) []diff.Resource[*rbacv1.Role] {
diffCr := make([]diff.Resource[*rbacv1.Role], 1)
cr := rbacv1.Role{
TypeMeta: v1.TypeMeta{
Kind: "ClusterRole",
Kind: "Role",
APIVersion: "rbac.authorization.k8s.io/v1",
},
ObjectMeta: v1.ObjectMeta{
Name: clusterRoleName(crd),
Name: roleName(crd),
Namespace: crd.Namespace,
},
Rules: []rbacv1.PolicyRule{
Expand All @@ -75,18 +79,18 @@ func BuildClusterRoles(crd *cosmosv1.CosmosFullNode) []diff.Resource[*rbacv1.Clu
return diffCr
}

// BuildClusterRoles returns a list of cluster role bindings given the crd.
// BuildRoles returns a list of role binding bindings given the crd.
//
// Creates a single cluster role binding for the version check.
func BuildClusterRoleBindings(crd *cosmosv1.CosmosFullNode) []diff.Resource[*rbacv1.ClusterRoleBinding] {
diffCrb := make([]diff.Resource[*rbacv1.ClusterRoleBinding], 1)
crb := rbacv1.ClusterRoleBinding{
// Creates a single role binding binding for the version check.
func BuildRoleBindings(crd *cosmosv1.CosmosFullNode) []diff.Resource[*rbacv1.RoleBinding] {
diffCrb := make([]diff.Resource[*rbacv1.RoleBinding], 1)
crb := rbacv1.RoleBinding{
TypeMeta: v1.TypeMeta{
Kind: "ClusterRoleBinding",
Kind: "RoleBinding",
APIVersion: "rbac.authorization.k8s.io/v1",
},
ObjectMeta: v1.ObjectMeta{
Name: crd.Name + "-crb",
Name: roleBindingName(crd),
Namespace: crd.Namespace,
},
Subjects: []rbacv1.Subject{
Expand All @@ -97,8 +101,8 @@ func BuildClusterRoleBindings(crd *cosmosv1.CosmosFullNode) []diff.Resource[*rba
},
},
RoleRef: rbacv1.RoleRef{
Kind: "ClusterRole",
Name: clusterRoleName(crd),
Kind: "Role",
Name: roleName(crd),
APIGroup: "rbac.authorization.k8s.io",
},
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,51 +12,50 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"
)

// ClusterRoleControl creates or updates ClusterRoles.
type ClusterRoleControl struct {
// RoleBindingControl creates or updates RoleBindings.
type RoleBindingControl struct {
client Client
}

func NewClusterRoleControl(client Client) ClusterRoleControl {
return ClusterRoleControl{
func NewRoleBindingControl(client Client) RoleBindingControl {
return RoleBindingControl{
client: client,
}
}

// Reconcile creates or updates cluster roles.
func (sc ClusterRoleControl) Reconcile(ctx context.Context, log kube.Logger, crd *cosmosv1.CosmosFullNode) kube.ReconcileError {
var crs rbacv1.ClusterRoleList
// Reconcile creates or updates role bindings.
func (sc RoleBindingControl) Reconcile(ctx context.Context, log kube.Logger, crd *cosmosv1.CosmosFullNode) kube.ReconcileError {
var crs rbacv1.RoleBindingList
if err := sc.client.List(ctx, &crs,
client.InNamespace(crd.Namespace),
client.MatchingLabels{
kube.ControllerLabel: "cosmos-operator",
kube.ComponentLabel: cosmosv1.CosmosFullNodeController,
kube.ComponentLabel: "vc",
kube.NameLabel: appName(crd),
},
); err != nil {
return kube.TransientError(fmt.Errorf("list existing cluster roles: %w", err))
return kube.TransientError(fmt.Errorf("list existing role bindings: %w", err))
}

current := ptrSlice(crs.Items)
want := BuildClusterRoles(crd)
want := BuildRoleBindings(crd)
diffed := diff.New(current, want)

for _, cr := range diffed.Creates() {
log.Info("Creating cluster role", "clusterRoleName", cr.Name)
log.Info("Creating role binding", "roleBindingName", cr.Name)
if err := ctrl.SetControllerReference(crd, cr, sc.client.Scheme()); err != nil {
return kube.TransientError(fmt.Errorf("set controller reference on cluster role %q: %w", cr.Name, err))
return kube.TransientError(fmt.Errorf("set controller reference on role binding %q: %w", cr.Name, err))
}
// CreateOrUpdate (vs. only create) fixes a bug with current deployments where updating would remove the owner reference.
// This ensures we update the service with the owner reference.
if err := kube.CreateOrUpdate(ctx, sc.client, cr); err != nil {
return kube.TransientError(fmt.Errorf("create cluster role %q: %w", cr.Name, err))
return kube.TransientError(fmt.Errorf("create role binding %q: %w", cr.Name, err))
}
}

for _, cr := range diffed.Updates() {
log.Info("Updating cluster role", "clusterRoleName", cr.Name)
log.Info("Updating role binding", "roleBindingName", cr.Name)
if err := sc.client.Update(ctx, cr); err != nil {
return kube.TransientError(fmt.Errorf("update cluster role %q: %w", cr.Name, err))
return kube.TransientError(fmt.Errorf("update role binding %q: %w", cr.Name, err))
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,51 +12,50 @@ import (
"sigs.k8s.io/controller-runtime/pkg/client"
)

// ClusterRoleBindingControl creates or updates ClusterRoleBindings.
type ClusterRoleBindingControl struct {
// RoleControl creates or updates Roles.
type RoleControl struct {
client Client
}

func NewClusterRoleBindingControl(client Client) ClusterRoleBindingControl {
return ClusterRoleBindingControl{
func NewRoleControl(client Client) RoleControl {
return RoleControl{
client: client,
}
}

// Reconcile creates or updates cluster role bindings.
func (sc ClusterRoleBindingControl) Reconcile(ctx context.Context, log kube.Logger, crd *cosmosv1.CosmosFullNode) kube.ReconcileError {
var crs rbacv1.ClusterRoleBindingList
// Reconcile creates or updates roles.
func (sc RoleControl) Reconcile(ctx context.Context, log kube.Logger, crd *cosmosv1.CosmosFullNode) kube.ReconcileError {
var crs rbacv1.RoleList
if err := sc.client.List(ctx, &crs,
client.InNamespace(crd.Namespace),
client.MatchingLabels{
kube.ControllerLabel: "cosmos-operator",
kube.ComponentLabel: cosmosv1.CosmosFullNodeController,
kube.ComponentLabel: "vc",
kube.NameLabel: appName(crd),
},
); err != nil {
return kube.TransientError(fmt.Errorf("list existing cluster role bindings: %w", err))
return kube.TransientError(fmt.Errorf("list existing roles: %w", err))
}

current := ptrSlice(crs.Items)
want := BuildClusterRoleBindings(crd)
want := BuildRoles(crd)
diffed := diff.New(current, want)

for _, cr := range diffed.Creates() {
log.Info("Creating cluster role binding", "clusterRoleBindingName", cr.Name)
log.Info("Creating role", "roleName", cr.Name)
if err := ctrl.SetControllerReference(crd, cr, sc.client.Scheme()); err != nil {
return kube.TransientError(fmt.Errorf("set controller reference on cluster role binding %q: %w", cr.Name, err))
return kube.TransientError(fmt.Errorf("set controller reference on role %q: %w", cr.Name, err))
}
// CreateOrUpdate (vs. only create) fixes a bug with current deployments where updating would remove the owner reference.
// This ensures we update the service with the owner reference.
if err := kube.CreateOrUpdate(ctx, sc.client, cr); err != nil {
return kube.TransientError(fmt.Errorf("create cluster role binding %q: %w", cr.Name, err))
return kube.TransientError(fmt.Errorf("create role %q: %w", cr.Name, err))
}
}

for _, cr := range diffed.Updates() {
log.Info("Updating cluster role binding", "clusterRoleBindingName", cr.Name)
log.Info("Updating role", "roleName", cr.Name)
if err := sc.client.Update(ctx, cr); err != nil {
return kube.TransientError(fmt.Errorf("update cluster role binding %q: %w", cr.Name, err))
return kube.TransientError(fmt.Errorf("update role %q: %w", cr.Name, err))
}
}

Expand Down
2 changes: 1 addition & 1 deletion internal/fullnode/service_account_control.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ func (sc ServiceAccountControl) Reconcile(ctx context.Context, log kube.Logger,
client.InNamespace(crd.Namespace),
client.MatchingLabels{
kube.ControllerLabel: "cosmos-operator",
kube.ComponentLabel: cosmosv1.CosmosFullNodeController,
kube.ComponentLabel: "vc",
kube.NameLabel: appName(crd),
},
); err != nil {
Expand Down
1 change: 1 addition & 0 deletions local.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ RUN go mod download
# Copy the go source
COPY *.go .
COPY api/ api/
COPY cmd/ cmd/
COPY controllers/ controllers/
COPY internal/ internal/

Expand Down

0 comments on commit 153cb45

Please sign in to comment.