diff --git a/installer/helmdeployer/clusterrole.go b/installer/helmdeployer/clusterrole.go deleted file mode 100644 index 1efd7f1a6..000000000 --- a/installer/helmdeployer/clusterrole.go +++ /dev/null @@ -1,76 +0,0 @@ -package helmdeployer - -import ( - "fmt" - "github.com/gardener/landscaper/installer/resources" - v1 "k8s.io/api/rbac/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -type clusterRoleMutator struct { - *valuesHelper -} - -var _ resources.Mutator[*v1.ClusterRole] = &clusterRoleMutator{} - -func newClusterRoleMutator(b *valuesHelper) resources.Mutator[*v1.ClusterRole] { - return &clusterRoleMutator{valuesHelper: b} -} - -func (d *clusterRoleMutator) String() string { - return fmt.Sprintf("clusterrole %s", d.clusterRoleName()) -} - -func (d *clusterRoleMutator) Empty() *v1.ClusterRole { - return &v1.ClusterRole{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "rbac.authorization.k8s.io/v1", - Kind: "ClusterRole", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: d.clusterRoleName(), - }, - } -} - -func (b *clusterRoleMutator) Mutate(r *v1.ClusterRole) error { - r.ObjectMeta.Labels = b.deployerLabels() - r.Rules = []v1.PolicyRule{ - { - APIGroups: []string{"landscaper.gardener.cloud"}, - Resources: []string{"deployitems", "deployitems/status"}, - Verbs: []string{"get", "list", "watch", "update"}, - }, - { - APIGroups: []string{"landscaper.gardener.cloud"}, - Resources: []string{"targets", "contexts"}, - Verbs: []string{"get", "list", "watch"}, - }, - { - APIGroups: []string{"landscaper.gardener.cloud"}, - Resources: []string{"syncobjects", "criticalproblems"}, - Verbs: []string{"*"}, - }, - { - APIGroups: []string{""}, - Resources: []string{"namespaces", "pods", "configmaps"}, - Verbs: []string{"get", "list", "watch"}, - }, - { - APIGroups: []string{""}, - Resources: []string{"secrets"}, - Verbs: []string{"get", "list", "watch", "create", "update", "delete"}, - }, - { - APIGroups: []string{""}, - Resources: []string{"serviceaccounts/token"}, - Verbs: []string{"create"}, - }, - { - APIGroups: []string{""}, - Resources: []string{"events"}, - Verbs: []string{"get", "watch", "create", "update", "patch"}, - }, - } - return nil -} diff --git a/installer/helmdeployer/clusterrolebinding.go b/installer/helmdeployer/clusterrolebinding.go deleted file mode 100644 index 5d83452e7..000000000 --- a/installer/helmdeployer/clusterrolebinding.go +++ /dev/null @@ -1,51 +0,0 @@ -package helmdeployer - -import ( - "fmt" - "github.com/gardener/landscaper/installer/resources" - v1 "k8s.io/api/rbac/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -type clusterRoleBindingMutator struct { - *valuesHelper -} - -var _ resources.Mutator[*v1.ClusterRoleBinding] = &clusterRoleBindingMutator{} - -func newClusterRoleBindingMutator(b *valuesHelper) resources.Mutator[*v1.ClusterRoleBinding] { - return &clusterRoleBindingMutator{valuesHelper: b} -} - -func (d *clusterRoleBindingMutator) String() string { - return fmt.Sprintf("clusterrolebinding %s", d.clusterRoleName()) -} - -func (d *clusterRoleBindingMutator) Empty() *v1.ClusterRoleBinding { - return &v1.ClusterRoleBinding{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "rbac.authorization.k8s.io/v1", - Kind: "ClusterRoleBinding", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: d.clusterRoleName(), - }, - } -} - -func (d *clusterRoleBindingMutator) Mutate(r *v1.ClusterRoleBinding) error { - r.ObjectMeta.Labels = d.deployerLabels() - r.RoleRef = v1.RoleRef{ - APIGroup: "rbac.authorization.k8s.io", - Kind: "ClusterRole", - Name: d.clusterRoleName(), - } - r.Subjects = []v1.Subject{ - { - Kind: "ServiceAccount", - Name: d.deployerFullName(), - Namespace: d.hostNamespace(), - }, - } - return nil -} diff --git a/installer/helmdeployer/rbac.go b/installer/helmdeployer/rbac.go new file mode 100644 index 000000000..577808f6d --- /dev/null +++ b/installer/helmdeployer/rbac.go @@ -0,0 +1,69 @@ +package helmdeployer + +import ( + "github.com/gardener/landscaper/installer/resources" + core "k8s.io/api/core/v1" + rbac "k8s.io/api/rbac/v1" +) + +func newServiceAccountMutator(h *valuesHelper) resources.Mutator[*core.ServiceAccount] { + return &resources.ServiceAccountMutator{ + Name: h.deployerFullName(), + Namespace: h.hostNamespace(), + Labels: h.deployerLabels(), + } +} + +func newClusterRoleBindingMutator(h *valuesHelper) resources.Mutator[*rbac.ClusterRoleBinding] { + return &resources.ClusterRoleBindingMutator{ + ClusterRoleBindingName: h.clusterRoleName(), + ClusterRoleName: h.clusterRoleName(), + ServiceAccountName: h.deployerFullName(), + ServiceAccountNamespace: h.hostNamespace(), + Labels: h.deployerLabels(), + } +} + +func newClusterRoleMutator(h *valuesHelper) resources.Mutator[*rbac.ClusterRole] { + return &resources.ClusterRoleMutator{ + Name: h.clusterRoleName(), + Labels: h.deployerLabels(), + Rules: []rbac.PolicyRule{ + { + APIGroups: []string{"landscaper.gardener.cloud"}, + Resources: []string{"deployitems", "deployitems/status"}, + Verbs: []string{"get", "list", "watch", "update"}, + }, + { + APIGroups: []string{"landscaper.gardener.cloud"}, + Resources: []string{"targets", "contexts"}, + Verbs: []string{"get", "list", "watch"}, + }, + { + APIGroups: []string{"landscaper.gardener.cloud"}, + Resources: []string{"syncobjects", "criticalproblems"}, + Verbs: []string{"*"}, + }, + { + APIGroups: []string{""}, + Resources: []string{"namespaces", "pods", "configmaps"}, + Verbs: []string{"get", "list", "watch"}, + }, + { + APIGroups: []string{""}, + Resources: []string{"secrets"}, + Verbs: []string{"get", "list", "watch", "create", "update", "delete"}, + }, + { + APIGroups: []string{""}, + Resources: []string{"serviceaccounts/token"}, + Verbs: []string{"create"}, + }, + { + APIGroups: []string{""}, + Resources: []string{"events"}, + Verbs: []string{"get", "watch", "create", "update", "patch"}, + }, + }, + } +} diff --git a/installer/helmdeployer/serviceaccount.go b/installer/helmdeployer/serviceaccount.go deleted file mode 100644 index 3a45d1cbd..000000000 --- a/installer/helmdeployer/serviceaccount.go +++ /dev/null @@ -1,40 +0,0 @@ -package helmdeployer - -import ( - "fmt" - "github.com/gardener/landscaper/installer/resources" - core "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -type serviceAccountMutator struct { - *valuesHelper -} - -var _ resources.Mutator[*core.ServiceAccount] = &serviceAccountMutator{} - -func newServiceAccountMutator(b *valuesHelper) resources.Mutator[*core.ServiceAccount] { - return &serviceAccountMutator{valuesHelper: b} -} - -func (d *serviceAccountMutator) String() string { - return fmt.Sprintf("service account %s/%s", d.hostNamespace(), d.deployerFullName()) -} - -func (d *serviceAccountMutator) Empty() *core.ServiceAccount { - return &core.ServiceAccount{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "v1", - Kind: "ServiceAccount", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: d.deployerFullName(), - Namespace: d.hostNamespace(), - }, - } -} - -func (d *serviceAccountMutator) Mutate(s *core.ServiceAccount) error { - s.ObjectMeta.Labels = d.deployerLabels() - return nil -} diff --git a/installer/manifestdeployer/clusterrole.go b/installer/manifestdeployer/clusterrole.go deleted file mode 100644 index 6a67daaca..000000000 --- a/installer/manifestdeployer/clusterrole.go +++ /dev/null @@ -1,76 +0,0 @@ -package manifestdeployer - -import ( - "fmt" - "github.com/gardener/landscaper/installer/resources" - v1 "k8s.io/api/rbac/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -type clusterRoleMutator struct { - *valuesHelper -} - -var _ resources.Mutator[*v1.ClusterRole] = &clusterRoleMutator{} - -func newClusterRoleMutator(b *valuesHelper) resources.Mutator[*v1.ClusterRole] { - return &clusterRoleMutator{valuesHelper: b} -} - -func (d *clusterRoleMutator) String() string { - return fmt.Sprintf("clusterrole %s", d.clusterRoleName()) -} - -func (d *clusterRoleMutator) Empty() *v1.ClusterRole { - return &v1.ClusterRole{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "rbac.authorization.k8s.io/v1", - Kind: "ClusterRole", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: d.clusterRoleName(), - }, - } -} - -func (b *clusterRoleMutator) Mutate(r *v1.ClusterRole) error { - r.ObjectMeta.Labels = b.deployerLabels() - r.Rules = []v1.PolicyRule{ - { - APIGroups: []string{"landscaper.gardener.cloud"}, - Resources: []string{"deployitems", "deployitems/status"}, - Verbs: []string{"get", "list", "watch", "update"}, - }, - { - APIGroups: []string{"landscaper.gardener.cloud"}, - Resources: []string{"targets", "contexts"}, - Verbs: []string{"get", "list", "watch"}, - }, - { - APIGroups: []string{"landscaper.gardener.cloud"}, - Resources: []string{"syncobjects", "criticalproblems"}, - Verbs: []string{"*"}, - }, - { - APIGroups: []string{""}, - Resources: []string{"namespaces", "pods"}, - Verbs: []string{"get", "list", "watch"}, - }, - { - APIGroups: []string{""}, - Resources: []string{"secrets"}, - Verbs: []string{"get", "list", "watch", "create", "update", "delete"}, - }, - { - APIGroups: []string{""}, - Resources: []string{"serviceaccounts/token"}, - Verbs: []string{"create"}, - }, - { - APIGroups: []string{""}, - Resources: []string{"events"}, - Verbs: []string{"get", "watch", "create", "update", "patch"}, - }, - } - return nil -} diff --git a/installer/manifestdeployer/clusterrolebinding.go b/installer/manifestdeployer/clusterrolebinding.go deleted file mode 100644 index 220c5f672..000000000 --- a/installer/manifestdeployer/clusterrolebinding.go +++ /dev/null @@ -1,51 +0,0 @@ -package manifestdeployer - -import ( - "fmt" - "github.com/gardener/landscaper/installer/resources" - v1 "k8s.io/api/rbac/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -type clusterRoleBindingMutator struct { - *valuesHelper -} - -var _ resources.Mutator[*v1.ClusterRoleBinding] = &clusterRoleBindingMutator{} - -func newClusterRoleBindingMutator(b *valuesHelper) resources.Mutator[*v1.ClusterRoleBinding] { - return &clusterRoleBindingMutator{valuesHelper: b} -} - -func (d *clusterRoleBindingMutator) String() string { - return fmt.Sprintf("clusterrolebinding %s", d.clusterRoleName()) -} - -func (d *clusterRoleBindingMutator) Empty() *v1.ClusterRoleBinding { - return &v1.ClusterRoleBinding{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "rbac.authorization.k8s.io/v1", - Kind: "ClusterRoleBinding", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: d.clusterRoleName(), - }, - } -} - -func (d *clusterRoleBindingMutator) Mutate(r *v1.ClusterRoleBinding) error { - r.ObjectMeta.Labels = d.deployerLabels() - r.RoleRef = v1.RoleRef{ - APIGroup: "rbac.authorization.k8s.io", - Kind: "ClusterRole", - Name: d.clusterRoleName(), - } - r.Subjects = []v1.Subject{ - { - Kind: "ServiceAccount", - Name: d.deployerFullName(), - Namespace: d.hostNamespace(), - }, - } - return nil -} diff --git a/installer/manifestdeployer/rbac.go b/installer/manifestdeployer/rbac.go new file mode 100644 index 000000000..c524a8bb5 --- /dev/null +++ b/installer/manifestdeployer/rbac.go @@ -0,0 +1,69 @@ +package manifestdeployer + +import ( + "github.com/gardener/landscaper/installer/resources" + core "k8s.io/api/core/v1" + rbac "k8s.io/api/rbac/v1" +) + +func newServiceAccountMutator(h *valuesHelper) resources.Mutator[*core.ServiceAccount] { + return &resources.ServiceAccountMutator{ + Name: h.deployerFullName(), + Namespace: h.hostNamespace(), + Labels: h.deployerLabels(), + } +} + +func newClusterRoleBindingMutator(h *valuesHelper) resources.Mutator[*rbac.ClusterRoleBinding] { + return &resources.ClusterRoleBindingMutator{ + ClusterRoleBindingName: h.clusterRoleName(), + ClusterRoleName: h.clusterRoleName(), + ServiceAccountName: h.deployerFullName(), + ServiceAccountNamespace: h.hostNamespace(), + Labels: h.deployerLabels(), + } +} + +func newClusterRoleMutator(h *valuesHelper) resources.Mutator[*rbac.ClusterRole] { + return &resources.ClusterRoleMutator{ + Name: h.clusterRoleName(), + Labels: h.deployerLabels(), + Rules: []rbac.PolicyRule{ + { + APIGroups: []string{"landscaper.gardener.cloud"}, + Resources: []string{"deployitems", "deployitems/status"}, + Verbs: []string{"get", "list", "watch", "update"}, + }, + { + APIGroups: []string{"landscaper.gardener.cloud"}, + Resources: []string{"targets", "contexts"}, + Verbs: []string{"get", "list", "watch"}, + }, + { + APIGroups: []string{"landscaper.gardener.cloud"}, + Resources: []string{"syncobjects", "criticalproblems"}, + Verbs: []string{"*"}, + }, + { + APIGroups: []string{""}, + Resources: []string{"namespaces", "pods"}, + Verbs: []string{"get", "list", "watch"}, + }, + { + APIGroups: []string{""}, + Resources: []string{"secrets"}, + Verbs: []string{"get", "list", "watch", "create", "update", "delete"}, + }, + { + APIGroups: []string{""}, + Resources: []string{"serviceaccounts/token"}, + Verbs: []string{"create"}, + }, + { + APIGroups: []string{""}, + Resources: []string{"events"}, + Verbs: []string{"get", "watch", "create", "update", "patch"}, + }, + }, + } +} diff --git a/installer/manifestdeployer/serviceaccount.go b/installer/manifestdeployer/serviceaccount.go deleted file mode 100644 index d85b3f834..000000000 --- a/installer/manifestdeployer/serviceaccount.go +++ /dev/null @@ -1,40 +0,0 @@ -package manifestdeployer - -import ( - "fmt" - "github.com/gardener/landscaper/installer/resources" - core "k8s.io/api/core/v1" - metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" -) - -type serviceAccountMutator struct { - *valuesHelper -} - -var _ resources.Mutator[*core.ServiceAccount] = &serviceAccountMutator{} - -func newServiceAccountMutator(b *valuesHelper) resources.Mutator[*core.ServiceAccount] { - return &serviceAccountMutator{valuesHelper: b} -} - -func (d *serviceAccountMutator) String() string { - return fmt.Sprintf("service account %s/%s", d.hostNamespace(), d.deployerFullName()) -} - -func (d *serviceAccountMutator) Empty() *core.ServiceAccount { - return &core.ServiceAccount{ - TypeMeta: metav1.TypeMeta{ - APIVersion: "v1", - Kind: "ServiceAccount", - }, - ObjectMeta: metav1.ObjectMeta{ - Name: d.deployerFullName(), - Namespace: d.hostNamespace(), - }, - } -} - -func (d *serviceAccountMutator) Mutate(s *core.ServiceAccount) error { - s.ObjectMeta.Labels = d.deployerLabels() - return nil -} diff --git a/installer/rbac/installer.go b/installer/rbac/installer.go new file mode 100644 index 000000000..d98fea926 --- /dev/null +++ b/installer/rbac/installer.go @@ -0,0 +1,99 @@ +package rbac + +import ( + "context" + "github.com/gardener/landscaper/installer/resources" + "sigs.k8s.io/controller-runtime/pkg/client" +) + +func InstallRBAC(ctx context.Context, resourceClient client.Client, values *Values) error { + + valHelper, err := newValuesHelper(values) + if err != nil { + return err + } + + if err := resources.CreateOrUpdateResource(ctx, resourceClient, resources.NewNamespaceMutator(valHelper.resourceNamespace())); err != nil { + return err + } + + if valHelper.isCreateServiceAccount() { + // Create or update RBAC objects for the landscaper controller + if err := resources.CreateOrUpdateResource(ctx, resourceClient, newControllerClusterRoleMutator(valHelper)); err != nil { + return err + } + if err := resources.CreateOrUpdateResource(ctx, resourceClient, newControllerServiceAccountMutator(valHelper)); err != nil { + return err + } + if err := resources.CreateOrUpdateResource(ctx, resourceClient, newControllerClusterRoleBindingMutator(valHelper)); err != nil { + return err + } + + // Create or update RBAC objects for the landscaper user + if err := resources.CreateOrUpdateResource(ctx, resourceClient, newUserClusterRoleMutator(valHelper)); err != nil { + return err + } + if err := resources.CreateOrUpdateResource(ctx, resourceClient, newUserServiceAccountMutator(valHelper)); err != nil { + return err + } + if err := resources.CreateOrUpdateResource(ctx, resourceClient, newUserClusterRoleBindingMutator(valHelper)); err != nil { + return err + } + + // Create or update RBAC objects for the landscaper webhooks + if err := resources.CreateOrUpdateResource(ctx, resourceClient, newWebhooksClusterRoleMutator(valHelper)); err != nil { + return err + } + if err := resources.CreateOrUpdateResource(ctx, resourceClient, newWebhooksServiceAccountMutator(valHelper)); err != nil { + return err + } + if err := resources.CreateOrUpdateResource(ctx, resourceClient, newWebhooksClusterRoleBindingMutator(valHelper)); err != nil { + return err + } + } + + return nil +} + +func UninstallManifestDeployer(ctx context.Context, resourceClient client.Client, values *Values) error { + + valHelper, err := newValuesHelper(values) + if err != nil { + return err + } + + // Delete RBAC objects for the landscaper webhooks + if err := resources.DeleteResource(ctx, resourceClient, newWebhooksClusterRoleBindingMutator(valHelper)); err != nil { + return err + } + if err := resources.DeleteResource(ctx, resourceClient, newWebhooksServiceAccountMutator(valHelper)); err != nil { + return err + } + if err := resources.DeleteResource(ctx, resourceClient, newWebhooksClusterRoleMutator(valHelper)); err != nil { + return err + } + + // Delete RBAC objects for the landscaper user + if err := resources.DeleteResource(ctx, resourceClient, newUserClusterRoleBindingMutator(valHelper)); err != nil { + return err + } + if err := resources.DeleteResource(ctx, resourceClient, newUserServiceAccountMutator(valHelper)); err != nil { + return err + } + if err := resources.DeleteResource(ctx, resourceClient, newUserClusterRoleMutator(valHelper)); err != nil { + return err + } + + // Delete RBAC objects for the landscaper controller + if err := resources.DeleteResource(ctx, resourceClient, newControllerClusterRoleBindingMutator(valHelper)); err != nil { + return err + } + if err := resources.DeleteResource(ctx, resourceClient, newControllerServiceAccountMutator(valHelper)); err != nil { + return err + } + if err := resources.DeleteResource(ctx, resourceClient, newControllerClusterRoleMutator(valHelper)); err != nil { + return err + } + + return nil +} diff --git a/installer/rbac/rbac_controller.go b/installer/rbac/rbac_controller.go new file mode 100644 index 000000000..64161db68 --- /dev/null +++ b/installer/rbac/rbac_controller.go @@ -0,0 +1,80 @@ +package rbac + +import ( + "github.com/gardener/landscaper/installer/resources" + core "k8s.io/api/core/v1" + rbac "k8s.io/api/rbac/v1" +) + +const ( + controllerServiceAccountName = "landscaper-controller" + controllerClusterRoleName = "landscaper:landscaper-controller" + controllerClusterRoleBindingName = "landscaper:landscaper-controller" +) + +func newControllerServiceAccountMutator(h *valuesHelper) resources.Mutator[*core.ServiceAccount] { + return &resources.ServiceAccountMutator{ + Name: controllerServiceAccountName, + Namespace: h.resourceNamespace(), + Labels: h.landscaperLabels(), + } +} + +func newControllerClusterRoleBindingMutator(h *valuesHelper) resources.Mutator[*rbac.ClusterRoleBinding] { + return &resources.ClusterRoleBindingMutator{ + ClusterRoleBindingName: controllerClusterRoleBindingName, + ClusterRoleName: controllerClusterRoleName, + ServiceAccountName: controllerServiceAccountName, + ServiceAccountNamespace: h.resourceNamespace(), + Labels: h.landscaperLabels(), + } +} + +func newControllerClusterRoleMutator(h *valuesHelper) resources.Mutator[*rbac.ClusterRole] { + return &resources.ClusterRoleMutator{ + Name: controllerClusterRoleName, + Labels: h.landscaperLabels(), + Rules: []rbac.PolicyRule{ + { + APIGroups: []string{"apiextensions.k8s.io"}, + Resources: []string{"customresourcedefinitions"}, + Verbs: []string{"*"}, + }, + { + APIGroups: []string{"landscaper.gardener.cloud"}, + Resources: []string{"*"}, + Verbs: []string{"*"}, + }, + { + APIGroups: []string{""}, + Resources: []string{"secrets", "configmaps"}, + Verbs: []string{"*"}, + }, + { + APIGroups: []string{""}, + Resources: []string{"serviceaccounts"}, + Verbs: []string{"get", "list", "watch", "create", "update", "delete"}, + }, + { + APIGroups: []string{""}, + Resources: []string{"serviceaccounts/token"}, + Verbs: []string{"create"}, + }, + { + APIGroups: []string{""}, + Resources: []string{"namespaces"}, + Verbs: []string{"get", "list", "watch"}, + }, + { + APIGroups: []string{"rbac.authorization.k8s.io"}, + Resources: []string{"clusterroles", "clusterrolebindings"}, + Verbs: []string{"get", "list", "watch", "create", "update", "delete"}, + }, + { + APIGroups: []string{""}, + Resources: []string{"events"}, + Verbs: []string{"get", "watch", "create", "update", "patch"}, + }, + }, + } +} diff --git a/installer/rbac/rbac_user.go b/installer/rbac/rbac_user.go new file mode 100644 index 000000000..9e377f877 --- /dev/null +++ b/installer/rbac/rbac_user.go @@ -0,0 +1,50 @@ +package rbac + +import ( + "github.com/gardener/landscaper/installer/resources" + core "k8s.io/api/core/v1" + rbac "k8s.io/api/rbac/v1" +) + +const ( + userServiceAccountName = "landscaper-user" + userClusterRoleName = "landscaper:landscaper-user" + userClusterRoleBindingName = "landscaper:landscaper-user" +) + +func newUserServiceAccountMutator(h *valuesHelper) resources.Mutator[*core.ServiceAccount] { + return &resources.ServiceAccountMutator{ + Name: userServiceAccountName, + Namespace: h.resourceNamespace(), + Labels: h.landscaperLabels(), + } +} + +func newUserClusterRoleBindingMutator(h *valuesHelper) resources.Mutator[*rbac.ClusterRoleBinding] { + return &resources.ClusterRoleBindingMutator{ + ClusterRoleBindingName: userClusterRoleBindingName, + ClusterRoleName: userClusterRoleName, + ServiceAccountName: userServiceAccountName, + ServiceAccountNamespace: h.resourceNamespace(), + Labels: h.landscaperLabels(), + } +} + +func newUserClusterRoleMutator(h *valuesHelper) resources.Mutator[*rbac.ClusterRole] { + return &resources.ClusterRoleMutator{ + Name: userClusterRoleName, + Labels: h.landscaperLabels(), + Rules: []rbac.PolicyRule{ + { + APIGroups: []string{"landscaper.gardener.cloud"}, + Resources: []string{"*"}, + Verbs: []string{"*"}, + }, + { + APIGroups: []string{""}, + Resources: []string{"namespaces", "secrets", "configmaps"}, + Verbs: []string{"*"}, + }, + }, + } +} diff --git a/installer/rbac/rbac_webhooks.go b/installer/rbac/rbac_webhooks.go new file mode 100644 index 000000000..fb259d849 --- /dev/null +++ b/installer/rbac/rbac_webhooks.go @@ -0,0 +1,55 @@ +package rbac + +import ( + "github.com/gardener/landscaper/installer/resources" + core "k8s.io/api/core/v1" + rbac "k8s.io/api/rbac/v1" +) + +const ( + webhooksServiceAccountName = "landscaper-webhooks" + webhooksClusterRoleName = "landscaper:landscaper-webhooks" + webhooksClusterRoleBindingName = "landscaper:landscaper-webhooks" +) + +func newWebhooksServiceAccountMutator(h *valuesHelper) resources.Mutator[*core.ServiceAccount] { + return &resources.ServiceAccountMutator{ + Name: webhooksServiceAccountName, + Namespace: h.resourceNamespace(), + Labels: h.landscaperLabels(), + } +} + +func newWebhooksClusterRoleBindingMutator(h *valuesHelper) resources.Mutator[*rbac.ClusterRoleBinding] { + return &resources.ClusterRoleBindingMutator{ + ClusterRoleBindingName: webhooksClusterRoleBindingName, + ClusterRoleName: webhooksClusterRoleName, + ServiceAccountName: webhooksServiceAccountName, + ServiceAccountNamespace: h.resourceNamespace(), + Labels: h.landscaperLabels(), + } +} + +func newWebhooksClusterRoleMutator(h *valuesHelper) resources.Mutator[*rbac.ClusterRole] { + return &resources.ClusterRoleMutator{ + Name: webhooksClusterRoleName, + Labels: h.landscaperLabels(), + Rules: []rbac.PolicyRule{ + { + APIGroups: []string{"landscaper.gardener.cloud"}, + Resources: []string{"installations"}, + Verbs: []string{"list"}, + }, + { + APIGroups: []string{""}, + Resources: []string{"secrets"}, + Verbs: []string{"*"}, + }, + { + APIGroups: []string{"admissionregistration.k8s.io"}, + Resources: []string{"validatingwebhookconfigurations"}, + Verbs: []string{"*"}, + }, + }, + } +} diff --git a/installer/rbac/values.go b/installer/rbac/values.go new file mode 100644 index 000000000..86b316632 --- /dev/null +++ b/installer/rbac/values.go @@ -0,0 +1,21 @@ +package rbac + +type Values struct { + Key *KeyValues `json:"key,omitempty"` + Version string `json:"version,omitempty"` + + ServiceAccount *ServiceAccountValues `json:"serviceAccount,omitempty"` +} + +// KeyValues is the key to identify the rbac installation for an update or delete operation. +type KeyValues struct { + // Name is the name of the rbac installation. + Name string `json:"name,omitempty"` + + // ResourceNamespace is the namespace on the resource cluster where the rbac objects will be installed. + ResourceNamespace string `json:"resourceNamespace,omitempty"` +} + +type ServiceAccountValues struct { + Create bool `json:"create,omitempty"` +} diff --git a/installer/rbac/values_helper.go b/installer/rbac/values_helper.go new file mode 100644 index 000000000..6f9094376 --- /dev/null +++ b/installer/rbac/values_helper.go @@ -0,0 +1,44 @@ +package rbac + +import ( + "fmt" + "maps" +) + +type valuesHelper struct { + values *Values +} + +func newValuesHelper(values *Values) (*valuesHelper, error) { + if values == nil { + return nil, fmt.Errorf("values must not be nil") + } + + return &valuesHelper{ + values: values, + }, nil +} + +func (h *valuesHelper) resourceNamespace() string { + return h.values.Key.ResourceNamespace +} + +func (h *valuesHelper) landscaperLabels() map[string]string { + labels := map[string]string{ + "app.kubernetes.io/version": h.values.Version, + "app.kubernetes.io/managed-by": "landscaper-installer", + } + maps.Copy(labels, h.selectorLabels()) + return labels +} + +func (h *valuesHelper) selectorLabels() map[string]string { + return map[string]string{ + "app.kubernetes.io/name": "landscaper-rbac", + "app.kubernetes.io/instance": h.values.Key.Name, + } +} + +func (h *valuesHelper) isCreateServiceAccount() bool { + return h.values.ServiceAccount != nil && h.values.ServiceAccount.Create +} diff --git a/installer/resources/clusterrole.go b/installer/resources/clusterrole.go new file mode 100644 index 000000000..32eabf430 --- /dev/null +++ b/installer/resources/clusterrole.go @@ -0,0 +1,37 @@ +package resources + +import ( + "fmt" + v1 "k8s.io/api/rbac/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +type ClusterRoleMutator struct { + Name string + Labels map[string]string + Rules []v1.PolicyRule +} + +var _ Mutator[*v1.ClusterRole] = &ClusterRoleMutator{} + +func (m *ClusterRoleMutator) String() string { + return fmt.Sprintf("clusterrole %s", m.Name) +} + +func (m *ClusterRoleMutator) Empty() *v1.ClusterRole { + return &v1.ClusterRole{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "rbac.authorization.k8s.io/v1", + Kind: "ClusterRole", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: m.Name, + }, + } +} + +func (m *ClusterRoleMutator) Mutate(r *v1.ClusterRole) error { + r.ObjectMeta.Labels = m.Labels + r.Rules = m.Rules + return nil +} diff --git a/installer/resources/clusterrolebinding.go b/installer/resources/clusterrolebinding.go new file mode 100644 index 000000000..37991838b --- /dev/null +++ b/installer/resources/clusterrolebinding.go @@ -0,0 +1,50 @@ +package resources + +import ( + "fmt" + v1 "k8s.io/api/rbac/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +type ClusterRoleBindingMutator struct { + ClusterRoleBindingName string + ClusterRoleName string + ServiceAccountName string + ServiceAccountNamespace string + Labels map[string]string +} + +var _ Mutator[*v1.ClusterRoleBinding] = &ClusterRoleBindingMutator{} + +func (m *ClusterRoleBindingMutator) String() string { + return fmt.Sprintf("clusterrolebinding %s", m.ClusterRoleBindingName) +} + +func (m *ClusterRoleBindingMutator) Empty() *v1.ClusterRoleBinding { + return &v1.ClusterRoleBinding{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "rbac.authorization.k8s.io/v1", + Kind: "ClusterRoleBinding", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: m.ClusterRoleBindingName, + }, + } +} + +func (m *ClusterRoleBindingMutator) Mutate(r *v1.ClusterRoleBinding) error { + r.ObjectMeta.Labels = m.Labels + r.RoleRef = v1.RoleRef{ + APIGroup: "rbac.authorization.k8s.io", + Kind: "ClusterRole", + Name: m.ClusterRoleName, + } + r.Subjects = []v1.Subject{ + { + Kind: "ServiceAccount", + Name: m.ServiceAccountName, + Namespace: m.ServiceAccountNamespace, + }, + } + return nil +} diff --git a/installer/resources/mutator.go b/installer/resources/mutator.go index 54b204250..95d1e2488 100644 --- a/installer/resources/mutator.go +++ b/installer/resources/mutator.go @@ -13,21 +13,21 @@ type Mutator[K client.Object] interface { String() string } -func CreateOrUpdateResource[K client.Object](ctx context.Context, clt client.Client, def Mutator[K]) error { - res := def.Empty() +func CreateOrUpdateResource[K client.Object](ctx context.Context, clt client.Client, m Mutator[K]) error { + res := m.Empty() _, err := controllerutil.CreateOrUpdate(ctx, clt, res, func() error { - return def.Mutate(res) + return m.Mutate(res) }) if err != nil { - return fmt.Errorf("failed to create or update %s: %w", def.String(), err) + return fmt.Errorf("failed to create or update %s: %w", m.String(), err) } return nil } -func DeleteResource[K client.Object](ctx context.Context, clt client.Client, def Mutator[K]) error { - res := def.Empty() +func DeleteResource[K client.Object](ctx context.Context, clt client.Client, m Mutator[K]) error { + res := m.Empty() if err := clt.Delete(ctx, res); client.IgnoreNotFound(err) != nil { - return fmt.Errorf("failed to delete %s: %w", def.String(), err) + return fmt.Errorf("failed to delete %s: %w", m.String(), err) } return nil } diff --git a/installer/resources/serviceaccount.go b/installer/resources/serviceaccount.go new file mode 100644 index 000000000..bae01ed81 --- /dev/null +++ b/installer/resources/serviceaccount.go @@ -0,0 +1,37 @@ +package resources + +import ( + "fmt" + core "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +type ServiceAccountMutator struct { + Name string + Namespace string + Labels map[string]string +} + +var _ Mutator[*core.ServiceAccount] = &ServiceAccountMutator{} + +func (m *ServiceAccountMutator) String() string { + return fmt.Sprintf("service account %s/%s", m.Namespace, m.Name) +} + +func (m *ServiceAccountMutator) Empty() *core.ServiceAccount { + return &core.ServiceAccount{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "v1", + Kind: "ServiceAccount", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: m.Namespace, + Namespace: m.Name, + }, + } +} + +func (m *ServiceAccountMutator) Mutate(s *core.ServiceAccount) error { + s.ObjectMeta.Labels = m.Labels + return nil +}