Merge pull request #505 from fluxcd/tenant-sa

Add service accounts to tenant command
pull/506/head
Stefan Prodan 4 years ago committed by GitHub
commit 0db06c8962
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -38,7 +38,7 @@ var createTenantCmd = &cobra.Command{
Use: "tenant", Use: "tenant",
Short: "Create or update a tenant", Short: "Create or update a tenant",
Long: ` 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.`, reconcilers scope to the tenant namespaces.`,
Example: ` # Create a tenant with access to a namespace Example: ` # Create a tenant with access to a namespace
flux create tenant dev-team \ flux create tenant dev-team \
@ -65,7 +65,6 @@ var (
) )
func init() { func init() {
createTenantCmd.Hidden = true
createTenantCmd.Flags().StringSliceVar(&tenantNamespaces, "with-namespace", nil, "namespace belonging to this tenant") 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") createTenantCmd.Flags().StringVar(&tenantClusterRole, "cluster-role", "cluster-admin", "cluster role of the tenant role binding")
createCmd.AddCommand(createTenantCmd) createCmd.AddCommand(createTenantCmd)
@ -89,6 +88,7 @@ func createTenantCmdRun(cmd *cobra.Command, args []string) error {
} }
var namespaces []corev1.Namespace var namespaces []corev1.Namespace
var accounts []corev1.ServiceAccount
var roleBindings []rbacv1.RoleBinding var roleBindings []rbacv1.RoleBinding
for _, ns := range tenantNamespaces { for _, ns := range tenantNamespaces {
@ -111,6 +111,16 @@ func createTenantCmdRun(cmd *cobra.Command, args []string) error {
} }
namespaces = append(namespaces, namespace) namespaces = append(namespaces, namespace)
account := corev1.ServiceAccount{
ObjectMeta: metav1.ObjectMeta{
Name: tenant,
Namespace: ns,
Labels: objLabels,
},
}
accounts = append(accounts, account)
roleBinding := rbacv1.RoleBinding{ roleBinding := rbacv1.RoleBinding{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: tenantRoleBinding, Name: tenantRoleBinding,
@ -119,9 +129,12 @@ func createTenantCmdRun(cmd *cobra.Command, args []string) error {
}, },
Subjects: []rbacv1.Subject{ Subjects: []rbacv1.Subject{
{ {
APIGroup: "rbac.authorization.k8s.io", Kind: "User",
Kind: "User", Name: fmt.Sprintf("gotk:%s:reconciler", ns),
Name: fmt.Sprintf("gotk:%s:reconciler", ns), },
{
Kind: "ServiceAccount",
Name: tenant,
}, },
}, },
RoleRef: rbacv1.RoleRef{ RoleRef: rbacv1.RoleRef{
@ -135,7 +148,7 @@ func createTenantCmdRun(cmd *cobra.Command, args []string) error {
if export { if export {
for i, _ := range tenantNamespaces { 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 return err
} }
} }
@ -156,6 +169,11 @@ func createTenantCmdRun(cmd *cobra.Command, args []string) error {
return err 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) logger.Actionf("applying role binding %s", roleBindings[i].Name)
if err := upsertRoleBinding(ctx, kubeClient, roleBindings[i]); err != nil { if err := upsertRoleBinding(ctx, kubeClient, roleBindings[i]); err != nil {
return err return err
@ -195,6 +213,35 @@ func upsertNamespace(ctx context.Context, kubeClient client.Client, namespace co
return nil 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 { func upsertRoleBinding(ctx context.Context, kubeClient client.Client, roleBinding rbacv1.RoleBinding) error {
namespacedName := types.NamespacedName{ namespacedName := types.NamespacedName{
Namespace: roleBinding.GetNamespace(), Namespace: roleBinding.GetNamespace(),
@ -228,7 +275,7 @@ func upsertRoleBinding(ctx context.Context, kubeClient client.Client, roleBindin
return nil 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{ namespace.TypeMeta = metav1.TypeMeta{
APIVersion: "v1", APIVersion: "v1",
Kind: "Namespace", Kind: "Namespace",
@ -242,6 +289,19 @@ func exportTenant(namespace corev1.Namespace, roleBinding rbacv1.RoleBinding) er
data = bytes.Replace(data, []byte("spec: {}\n"), []byte(""), 1) data = bytes.Replace(data, []byte("spec: {}\n"), []byte(""), 1)
fmt.Println(resourceToString(data)) 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{ roleBinding.TypeMeta = metav1.TypeMeta{
APIVersion: "rbac.authorization.k8s.io/v1", APIVersion: "rbac.authorization.k8s.io/v1",
Kind: "RoleBinding", Kind: "RoleBinding",

@ -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 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 receiver](flux_create_receiver.md) - Create or update a Receiver resource
* [flux create source](flux_create_source.md) - Create or update sources * [flux create source](flux_create_source.md) - Create or update sources
* [flux create tenant](flux_create_tenant.md) - Create or update a tenant

@ -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

@ -95,7 +95,7 @@ nav:
- Create alert provider: cmd/flux_create_alert-provider.md - Create alert provider: cmd/flux_create_alert-provider.md
- Create alert: cmd/flux_create_alert.md - Create alert: cmd/flux_create_alert.md
- Create receiver: cmd/flux_create_receiver.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: cmd/flux_delete.md
- Delete kustomization: cmd/flux_delete_kustomization.md - Delete kustomization: cmd/flux_delete_kustomization.md
- Delete helmrelease: cmd/flux_delete_helmrelease.md - Delete helmrelease: cmd/flux_delete_helmrelease.md

Loading…
Cancel
Save