Kubernetes multi-tenancy with projectsveltos

gianlucam76

Gianluca

Posted on February 9, 2023

Kubernetes multi-tenancy with projectsveltos

Kubernetes is a complex system that relies on several components being configured correctly to have a working cluster.

Some solutions already exist to automate clusters' creation, upgrade, deletion, like for instance ClusterAPI. Such solutions require the existance of a management Kubernetes cluster from where tens of other Kubernetes clusters are then programmatically created and managed.

Managing the life-cycle of Kubernetes clusters is the first step. After a Kubernetes cluster is created, an handful number of features needs to be installed (CNI for instance). Kubernetes add-ons are used to extend the functionality of Kubernetes clusters.

So after cluster creation, the next problem that needs to be addressed is how to programmatically manage Kubernetes add-ons in each managed cluster from the management cluster. Luckily, even in this space, there are already existing solutions. For instance, Sveltos is an open source project to programmatically deploy Kubernetes add-ons in tens of Kubernetes clusters.

Summarizing, using a Kubernetes cluster to manage other clusters (creation/upgrade/deletion and add-ons deployment) provides several benefits, including:

  1. Centralized management: A cluster management cluster allows administrators to manage multiple clusters from a single place, making it easier to maintain consistency and reduce the risk of configuration issues.
  2. Scalability: A cluster management cluster can help organizations scale their infrastructure by making it easier to create, deploy, and manage multiple clusters.
  3. Better security: A cluster management cluster can be configured with security-related addons, such as network policies and secrets management, to help ensure that all managed clusters are secure.
  4. Increased automation: A cluster management cluster can be integrated with a continuous integration/continuous deployment (CI/CD) pipeline, making it easier to automate the deployment of new clusters and addons, and reducing the time and effort involved in managing the infrastructure.

Problem gets more complex when different organizations end up sharing the managed Kubernetes clusters. This scenario is commonly referred to as multi-tenancy.

Common forms of multi-tenancy are:

  1. share a cluster between multiple teams within an organization, each of whom may operate one or more workloads;
  2. one (or more) cluster(s) fully reserved for an organization.

In this scenario we need to introduce two roles:

  • platform admin: The role of a platform administrator is to manage and maintain the infrastructure of the managed Kubernetes clusters. This includes tasks such as setting up the cluster, managing nodes, installing and updating software components, and ensuring the overall health and security of the cluster. The platform administrator is also responsible for onboarding tenant admins and granting permissions to those;
  • tenant admin: Has admin access to the clusters/namespaces assigned to them by the platform admin and manages tenant applications in those clusters/namespaces.

After cluster creation/upgrade/deletion and the addons deployment, the next problem to solve is how to allow platform admin to onboard tenants and programmatically grant them permissions from the management cluster.

Sveltos addons management solution

Before we deep dive into granting permissions to tenants, lets briefly summarize Sveltos solution to manage Kubernetes addons.

Sveltos introduces a single CRD called ClusterProfile for that.

By creating a ClusterProfile instance, we can tell Sveltos:

  1. where to deploy addons (i.e, in all managed Clusters matching the ClusterSelector field);
  2. list of addons to deploy (either Helm charts or Kubernetes resource YAMLs contained in referenced ConfigMaps/Secrets).
apiVersion: config.projectsveltos.io/v1alpha1
kind: ClusterProfile
metadata:
  name: deploy-kyverno
spec:
  clusterSelector: env=fv
  syncMode: Continuous
  helmCharts:
  - repositoryURL:    https://kyverno.github.io/kyverno/
    repositoryName:   kyverno
    chartName:        kyverno/kyverno
    chartVersion:     v2.6.0
    releaseName:      kyverno-latest
    releaseNamespace: kyverno
    helmChartAction:  Install
  policyRefs:
  - name: disallow-latest-tag # referenced ConfigMap contains a Kyverno ClusterPolicy
    namespace: default
    kind: ConfigMap
Enter fullscreen mode Exit fullscreen mode

Sveltos addons management

With Sveltos configuration drift detection we don't have to worry about managed cluster states. Sveltos monitors the state of managed clusters and when it detects a configuration drift for one of the resource deployed because of a ClusterProfile, it re-syncs the cluster state back to the state described in the management cluster.

Sveltos add-ons deployment with drift detection

Sveltos multi-tenancy solution

Let's now go back to the multi-tenancy problem.

We want to:

  1. allow platform admin to programmatically grant permissions to tenant admins;
  2. allow tenant admins to manage applications from management cluster, making sure each tenant admin only deploys resources it has permissions to and only in the clusters/namespaces it has permission to.

RoleRequest is the CRD introduced by Sveltos to allow platform admin to grant permissions to various tenant admins.

apiVersion: lib.projectsveltos.io/v1alpha1
kind: RoleRequest
metadata:
  name: full-access
spec:
  clusterSelector: env=pre-production
  admin: eng
  roleRefs:
  - name: full-access
    namespace: default
    kind: ConfigMap
Enter fullscreen mode Exit fullscreen mode

where:

  1. ClusterSelector field is used to select a set of managed clusters where permissions will be granted;
  2. Admin field selects a tenant admin (later on we will cover how this identify a tenant admin);
  3. RoleRefs field references one of more ConfigMaps/Secrets. Each of those ConfigMaps/Secrets contains one or more ClusterRole/Role defining the permissions granted to the tenant admin by the platform admin.

Platform admin is the only admin in the management cluster with permissions to create/update/delete RoleRequest instances.

Tenant admin managing applications

Once RoleRequest instances have been created, tenant admins can use Sveltos ClusterProfile CRD to instruct Sveltos on what Kubernetes resources to deploy on which clusters.

Sveltos requires that following label

projectsveltos.io/admin-name: <admin>

is set on a ClusterProfile instances created by a tenant admin.
How to achieve that, is up to platform admin.

For instance, if:

  • Kyverno is present in the management cluster;
  • tenant admin are represented by Kubernetes ServiceAccount;

following Kyverno ClusterPolicy is all that is needed for label to be automatically added to each instance of a ClusterProfile:

apiVersion: kyverno.io/v1
kind: ClusterPolicy
metadata:
  name: add-labels
  annotations:
    policies.kyverno.io/title: Add Labels
    policies.kyverno.io/description: >-
      Adds projectsveltos.io/admin-name label on each ClusterProfile
      created by tenant admin. It assumes each tenant admin is
      represented in the management cluster by a ServiceAccount.
spec:
  validationFailureAction: enforce
  background: false
  rules:
  - name: add-labels
    match:
      resources:
        kinds:
        - ClusterProfile
    mutate:
      patchStrategicMerge:
        metadata:
          labels:
             projectsveltos.io/admin-name: "{{serviceAccountName}}"
Enter fullscreen mode Exit fullscreen mode

Examples

I have created management cluster on my laptop. It is a Kind cluster.
In the management cluster, I have deployed both ClusterAPI (with Kind as infrastructure provider) and Sveltos.

kubectl get pods -A
NAMESPACE                           NAME                                                             READY   STATUS    RESTARTS   AGE
capd-system                         capd-controller-manager-59b7bdbcf9-zd4xq                         1/1     Running   0          30m
capi-kubeadm-bootstrap-system       capi-kubeadm-bootstrap-controller-manager-68f975d954-9r7lm       1/1     Running   0          30m
capi-kubeadm-control-plane-system   capi-kubeadm-control-plane-controller-manager-8476fb8676-kpnkd   1/1     Running   0          30m
capi-system                         capi-controller-manager-69fd995599-67fh5                         1/1     Running   0          30m
...
projectsveltos                      access-manager-569dd6cccd-m676t                                  2/2     Running   0          59s
projectsveltos                      classifier-manager-ddc8c756-bmxc9                                2/2     Running   0          59s
projectsveltos                      fm-controller-manager-5964fb8bff-2j2gx                           2/2     Running   0          59s
projectsveltos                      sveltoscluster-manager-75ddcf7cbd-q47hp                          2/2     Running   0          58s
Enter fullscreen mode Exit fullscreen mode

I have one ClusterAPI powered cluster:

kubectl get clusters -A
NAMESPACE   NAME                          PHASE         AGE   VERSION
default     sveltos-management-workload   Provisioned   10m   v1.25.2
Enter fullscreen mode Exit fullscreen mode

and I have one GKE cluster registered with Sveltos

kubectl get sveltoscluster -A
NAMESPACE   NAME         AGE
gke         production   6s
Enter fullscreen mode Exit fullscreen mode

Cluster labels are set as follow:

Cluster Label
default/sveltos-management-workload env:development
gke/production env:production

Fully reserve set of cluster to a tenant

apiVersion: v1
kind: ConfigMap
metadata:
  name: full-access
  namespace: default
data:
  role.yaml: |
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRole
    metadata:
      name: system-admin-full-access
    rules:
    - apiGroups: ["*"]
      resources: ["*"]
      verbs: ["*"]

---

apiVersion: lib.projectsveltos.io/v1alpha1
kind: RoleRequest
metadata:
  name: full-access
spec:
  clusterSelector: env=production
  admin: system-admin
  roleRefs:
  - name: full-access
    namespace: default
    kind: ConfigMap
Enter fullscreen mode Exit fullscreen mode

By referencing ConfigMap default/full-access, above RoleRequest is reserving any cluster matching clusterSelector env=production to admin system-admin.

Using sveltosctl we can verify Sveltos is aware system-admin has full access to managed cluster with label env:production

./bin/sveltosctl show admin-rbac       
+-------------------------------+--------------+-----------+------------+-----------+----------------+-------+
|            CLUSTER            |    ADMIN     | NAMESPACE | API GROUPS | RESOURCES | RESOURCE NAMES | VERBS |
+-------------------------------+--------------+-----------+------------+-----------+----------------+-------+
| SveltosCluster:gke/production | system-admin | *         | *          | *         | *              | *     |
+-------------------------------+--------------+-----------+------------+-----------+----------------+-------+
Enter fullscreen mode Exit fullscreen mode

If system-admin tries to deploy addons to such cluster, that operation will go through.

For instance, if system-admin posts following ClusterProfile

apiVersion: config.projectsveltos.io/v1alpha1
kind: ClusterProfile
metadata:
  name: deploy-kyverno
  labels:
    projectsveltos.io/admin-name: system-admin
spec:
  clusterSelector: env=production
  syncMode: Continuous
  helmCharts:
  - repositoryURL:    https://kyverno.github.io/kyverno/
    repositoryName:   kyverno
    chartName:        kyverno/kyverno
    chartVersion:     v2.6.0
    releaseName:      kyverno-latest
    releaseNamespace: kyverno
    helmChartAction:  Install
Enter fullscreen mode Exit fullscreen mode

we can verify Kyverno is deployed by Sveltos on behalf of system-admin:

./bin/sveltosctl show features 
+----------------+---------------+-----------+----------------+---------+-------------------------------+------------------+
|    CLUSTER     | RESOURCE TYPE | NAMESPACE |      NAME      | VERSION |             TIME              | CLUSTER PROFILES |
+----------------+---------------+-----------+----------------+---------+-------------------------------+------------------+
| gke/production | helm chart    | kyverno   | kyverno-latest | 2.6.0   | 2023-02-03 14:06:48 -0800 PST | deploy-kyverno   |
+----------------+---------------+-----------+----------------+---------+-------------------------------+------------------+
Enter fullscreen mode Exit fullscreen mode

If system-admin tries to deploy same add-ons on clusters matching clusterSelector env:development that operation will fail.

Share cluster between tenants

Platform admin here is granting following permissions in all clusters matching ClusterSelector env=development

  1. Admin eng full access to namespace eng and some read permission in namespace shared-service-access;
  2. Admin hr full access to namespace human-resource.
# ConfigMap contains a Role which gives
# service read access to namespace shared-services
apiVersion: v1
kind: ConfigMap
metadata:
  name: shared-service-access
  namespace: default
data:
  role.yaml: |
    apiVersion: rbac.authorization.k8s.io/v1
    kind: Role
    metadata:
      name: service-read-role
      namespace: shared-services
    rules:
    - apiGroups: [""]
      resources: ["services"]
      verbs: ["get,list"]

---

# ConfigMap contains a Role which gives
# full access to namespace eng
apiVersion: v1
kind: ConfigMap
metadata:
  name: eng-full-access
  namespace: default
data:
  role.yaml: |
    apiVersion: rbac.authorization.k8s.io/v1
    kind: Role
    metadata:
      name: edit-role
      namespace: eng
    rules:
    - apiGroups: ["*"]
      resources: ["*"]
      verbs: ["*"]

---

# RoleRequest gives admin 'eng':
# - full access to namespace eng
# - some read permission in namespace shared-service-access
# in all clusters matching the label
# selector env=development
apiVersion: lib.projectsveltos.io/v1alpha1
kind: RoleRequest
metadata:
  name: eng-access
spec:
  clusterSelector: env=development
  admin: eng
  roleRefs:
  - name: eng-full-access
    namespace: default
    kind: ConfigMap
  - name: shared-service-access
    namespace: default
    kind: ConfigMap

# ConfigMap contains a Role which gives
# full access to namespace human-resource
apiVersion: v1
kind: ConfigMap
metadata:
  name: hr-full-access
  namespace: default
data:
  role.yaml: |
    apiVersion: rbac.authorization.k8s.io/v1
    kind: Role
    metadata:
      name: edit-role
      namespace: human-resource
    rules:
    - apiGroups: ["*"]
      resources: ["*"]
      verbs: ["*"]

---

# RoleRequest gives admin 'hr' access to namespace
# 'human-resource' in all clusters matching the label
# selector env=development
apiVersion: lib.projectsveltos.io/v1alpha1
kind: RoleRequest
metadata:
  name: hr-access
spec:
  clusterSelector: env=development
  admin: hr
  roleRefs:
  - name: hr-full-access
    namespace: default
    kind: ConfigMap
Enter fullscreen mode Exit fullscreen mode

As before, we can use sveltosctl to verify granted permission:

./bin/sveltosctl show admin-rbac --namespace=default
+---------------------------------------------+-------+-----------------+------------+-----------+----------------+----------+
|                   CLUSTER                   | ADMIN |    NAMESPACE    | API GROUPS | RESOURCES | RESOURCE NAMES |  VERBS   |
+---------------------------------------------+-------+-----------------+------------+-----------+----------------+----------+
| Cluster:default/sveltos-management-workload | eng   | eng             | *          | *         | *              | *        |
| Cluster:default/sveltos-management-workload | eng   | shared-services |            | services  | services       | get,list |
| Cluster:default/sveltos-management-workload | hr    | human-resource  | *          | *         | *              | *        |
+---------------------------------------------+-------+-----------------+------------+-----------+----------------+----------+
Enter fullscreen mode Exit fullscreen mode

If eng admin tries to deploy nginx in eng namespace, that will succeed.

apiVersion: v1
kind: ConfigMap
metadata:
  name: nginx
  namespace: default
data:
  nginx.yaml: |
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: nginx-deployment
      namespace: eng
      labels:
        app: nginx
    spec:
      replicas: 3
      selector:
        matchLabels:
          app: nginx
      template:
        metadata:
          labels:
            app: nginx
        spec:
          containers:
          - name: nginx
            image: nginx:1.14.2
            ports:
            - containerPort: 80

---

apiVersion: config.projectsveltos.io/v1alpha1
kind: ClusterProfile
metadata:
  name: deploy-nginx
  labels:
    projectsveltos.io/admin-name: eng
spec:
  clusterSelector: env=development
  syncMode: Continuous
  policyRefs:
  - name: nginx
    namespace: default
    kind: ConfigMap

Enter fullscreen mode Exit fullscreen mode

nginx is deployed

./bin/sveltosctl show features     
+-------------------------------------+-----------------+-----------+------------------+---------+-------------------------------+------------------+
|               CLUSTER               |  RESOURCE TYPE  | NAMESPACE |       NAME       | VERSION |             TIME              | CLUSTER PROFILES |
+-------------------------------------+-----------------+-----------+------------------+---------+-------------------------------+------------------+
| default/sveltos-management-workload | apps:Deployment | eng       | nginx-deployment | N/A     | 2023-02-03 14:40:19 -0800 PST | deploy-nginx     |
+-------------------------------------+-----------------+-----------+------------------+---------+-------------------------------+------------------+
Enter fullscreen mode Exit fullscreen mode

Sveltos multi-tenancy summarized

Contribute

Sveltos

Sveltos is an open source project. Contributions are more welcome 🤗

If you would like to know more about it or would like to see a new feature added to sveltos, please reach to us on slack. Any feedback is very much appreciated ❤️

Documentation can be found here

💖 💪 🙅 🚩
gianlucam76
Gianluca

Posted on February 9, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related