From 8273851b73fd99a5d699f61981073fe2da0113ff Mon Sep 17 00:00:00 2001 From: Stefan Prodan Date: Wed, 25 Nov 2020 16:38:10 +0200 Subject: [PATCH 1/2] Add service accounts to tenant command Signed-off-by: Stefan Prodan --- cmd/flux/create_tenant.go | 73 +++++++++++++++++++++++++++++++++++---- 1 file changed, 67 insertions(+), 6 deletions(-) diff --git a/cmd/flux/create_tenant.go b/cmd/flux/create_tenant.go index c3031dd8..51c7de55 100644 --- a/cmd/flux/create_tenant.go +++ b/cmd/flux/create_tenant.go @@ -38,7 +38,7 @@ var createTenantCmd = &cobra.Command{ Use: "tenant", Short: "Create or update a tenant", Long: ` -The create tenant command generates namespaces and role bindings to limit the +The create tenant command generates namespaces, service accounts and role bindings to limit the reconcilers scope to the tenant namespaces.`, Example: ` # Create a tenant with access to a namespace flux create tenant dev-team \ @@ -89,6 +89,7 @@ func createTenantCmdRun(cmd *cobra.Command, args []string) error { } var namespaces []corev1.Namespace + var accounts []corev1.ServiceAccount var roleBindings []rbacv1.RoleBinding for _, ns := range tenantNamespaces { @@ -111,6 +112,16 @@ func createTenantCmdRun(cmd *cobra.Command, args []string) error { } namespaces = append(namespaces, namespace) + account := corev1.ServiceAccount{ + ObjectMeta: metav1.ObjectMeta{ + Name: tenant, + Namespace: ns, + Labels: objLabels, + }, + } + + accounts = append(accounts, account) + roleBinding := rbacv1.RoleBinding{ ObjectMeta: metav1.ObjectMeta{ Name: tenantRoleBinding, @@ -119,9 +130,12 @@ func createTenantCmdRun(cmd *cobra.Command, args []string) error { }, Subjects: []rbacv1.Subject{ { - APIGroup: "rbac.authorization.k8s.io", - Kind: "User", - Name: fmt.Sprintf("gotk:%s:reconciler", ns), + Kind: "User", + Name: fmt.Sprintf("gotk:%s:reconciler", ns), + }, + { + Kind: "ServiceAccount", + Name: tenant, }, }, RoleRef: rbacv1.RoleRef{ @@ -135,7 +149,7 @@ func createTenantCmdRun(cmd *cobra.Command, args []string) error { if export { for i, _ := range tenantNamespaces { - if err := exportTenant(namespaces[i], roleBindings[i]); err != nil { + if err := exportTenant(namespaces[i], accounts[i], roleBindings[i]); err != nil { return err } } @@ -156,6 +170,11 @@ func createTenantCmdRun(cmd *cobra.Command, args []string) error { return err } + logger.Actionf("applying service account %s", accounts[i].Name) + if err := upsertServiceAccount(ctx, kubeClient, accounts[i]); err != nil { + return err + } + logger.Actionf("applying role binding %s", roleBindings[i].Name) if err := upsertRoleBinding(ctx, kubeClient, roleBindings[i]); err != nil { return err @@ -195,6 +214,35 @@ func upsertNamespace(ctx context.Context, kubeClient client.Client, namespace co return nil } +func upsertServiceAccount(ctx context.Context, kubeClient client.Client, account corev1.ServiceAccount) error { + namespacedName := types.NamespacedName{ + Namespace: account.GetNamespace(), + Name: account.GetName(), + } + + var existing corev1.ServiceAccount + err := kubeClient.Get(ctx, namespacedName, &existing) + if err != nil { + if errors.IsNotFound(err) { + if err := kubeClient.Create(ctx, &account); err != nil { + return err + } else { + return nil + } + } + return err + } + + if !equality.Semantic.DeepDerivative(account.Labels, existing.Labels) { + existing.Labels = account.Labels + if err := kubeClient.Update(ctx, &existing); err != nil { + return err + } + } + + return nil +} + func upsertRoleBinding(ctx context.Context, kubeClient client.Client, roleBinding rbacv1.RoleBinding) error { namespacedName := types.NamespacedName{ Namespace: roleBinding.GetNamespace(), @@ -228,7 +276,7 @@ func upsertRoleBinding(ctx context.Context, kubeClient client.Client, roleBindin return nil } -func exportTenant(namespace corev1.Namespace, roleBinding rbacv1.RoleBinding) error { +func exportTenant(namespace corev1.Namespace, account corev1.ServiceAccount, roleBinding rbacv1.RoleBinding) error { namespace.TypeMeta = metav1.TypeMeta{ APIVersion: "v1", Kind: "Namespace", @@ -242,6 +290,19 @@ func exportTenant(namespace corev1.Namespace, roleBinding rbacv1.RoleBinding) er data = bytes.Replace(data, []byte("spec: {}\n"), []byte(""), 1) fmt.Println(resourceToString(data)) + account.TypeMeta = metav1.TypeMeta{ + APIVersion: "", + Kind: "ServiceAccount", + } + data, err = yaml.Marshal(account) + if err != nil { + return err + } + + fmt.Println("---") + data = bytes.Replace(data, []byte("spec: {}\n"), []byte(""), 1) + fmt.Println(resourceToString(data)) + roleBinding.TypeMeta = metav1.TypeMeta{ APIVersion: "rbac.authorization.k8s.io/v1", Kind: "RoleBinding", From a8e5876b2ecc672f587673d67690e992f67d12d2 Mon Sep 17 00:00:00 2001 From: Stefan Prodan Date: Wed, 25 Nov 2020 16:42:52 +0200 Subject: [PATCH 2/2] Add create tenant to CLI docs Signed-off-by: Stefan Prodan --- cmd/flux/create_tenant.go | 1 - docs/cmd/flux_create.md | 1 + docs/cmd/flux_create_tenant.md | 55 ++++++++++++++++++++++++++++++++++ mkdocs.yml | 2 +- 4 files changed, 57 insertions(+), 2 deletions(-) create mode 100644 docs/cmd/flux_create_tenant.md diff --git a/cmd/flux/create_tenant.go b/cmd/flux/create_tenant.go index 51c7de55..ee8dde41 100644 --- a/cmd/flux/create_tenant.go +++ b/cmd/flux/create_tenant.go @@ -65,7 +65,6 @@ var ( ) func init() { - createTenantCmd.Hidden = true createTenantCmd.Flags().StringSliceVar(&tenantNamespaces, "with-namespace", nil, "namespace belonging to this tenant") createTenantCmd.Flags().StringVar(&tenantClusterRole, "cluster-role", "cluster-admin", "cluster role of the tenant role binding") createCmd.AddCommand(createTenantCmd) diff --git a/docs/cmd/flux_create.md b/docs/cmd/flux_create.md index 48acbae7..06522300 100644 --- a/docs/cmd/flux_create.md +++ b/docs/cmd/flux_create.md @@ -34,4 +34,5 @@ The create sub-commands generate sources and resources. * [flux create kustomization](flux_create_kustomization.md) - Create or update a Kustomization resource * [flux create receiver](flux_create_receiver.md) - Create or update a Receiver resource * [flux create source](flux_create_source.md) - Create or update sources +* [flux create tenant](flux_create_tenant.md) - Create or update a tenant diff --git a/docs/cmd/flux_create_tenant.md b/docs/cmd/flux_create_tenant.md new file mode 100644 index 00000000..7e61e9ab --- /dev/null +++ b/docs/cmd/flux_create_tenant.md @@ -0,0 +1,55 @@ +## flux create tenant + +Create or update a tenant + +### Synopsis + + +The create tenant command generates namespaces, service accounts and role bindings to limit the +reconcilers scope to the tenant namespaces. + +``` +flux create tenant [flags] +``` + +### Examples + +``` + # Create a tenant with access to a namespace + flux create tenant dev-team \ + --with-namespace=frontend \ + --label=environment=dev + + # Generate tenant namespaces and role bindings in YAML format + flux create tenant dev-team \ + --with-namespace=frontend \ + --with-namespace=backend \ + --export > dev-team.yaml + +``` + +### Options + +``` + --cluster-role string cluster role of the tenant role binding (default "cluster-admin") + -h, --help help for tenant + --with-namespace strings namespace belonging to this tenant +``` + +### Options inherited from parent commands + +``` + --context string kubernetes context to use + --export export in YAML format to stdout + --interval duration source sync interval (default 1m0s) + --kubeconfig string path to the kubeconfig file (default "~/.kube/config") + --label strings set labels on the resource (can specify multiple labels with commas: label1=value1,label2=value2) + -n, --namespace string the namespace scope for this operation (default "flux-system") + --timeout duration timeout for this operation (default 5m0s) + --verbose print generated objects +``` + +### SEE ALSO + +* [flux create](flux_create.md) - Create or update sources and resources + diff --git a/mkdocs.yml b/mkdocs.yml index 9c4cafd0..a9771d90 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -95,7 +95,7 @@ nav: - Create alert provider: cmd/flux_create_alert-provider.md - Create alert: cmd/flux_create_alert.md - Create receiver: cmd/flux_create_receiver.md - #- Create tenant: cmd/flux_create_tenant.md + - Create tenant: cmd/flux_create_tenant.md - Delete: cmd/flux_delete.md - Delete kustomization: cmd/flux_delete_kustomization.md - Delete helmrelease: cmd/flux_delete_helmrelease.md