DEV Community

loading...

Deploy Kubernetes resources automatically with nsinjector

blakelead profile image blakelead ・4 min read

Original post: https://blog.blakelead.com/posts/2020/10/12/nsinjector

A bit of context

I recently had the opportunity to work on the elaboration of a CI/CD pipeline based on the GitOps methodology. In this pipeline, code pushed by developers triggers the creation of namespaces for each development branch. Since several teams share the same Kubernetes cluster, RBAC rules are applied to each namespace. If the namespace is created by the front team, the back team should not have access to it. And of course, developers do not have the rights to create RBAC resources (otherwise it wouldn't be fun :D).

I then took advantage of these specific needs to learn more about the Kubernetes controller pattern in order to automate the deployment of RBAC resources when namespaces are created. nsinjector is the result of my readings.

In this article, I explain how to use nsinjector to automatically deploy Kubernetes resources (in this case a ClusterRole and a ClusterRoleBinding) when a namespace with a name beginning by dev- is created.

Prerequisite

The rest of this post assumes a base knowledge of Kubernetes. If you want to know more about Kubernetes basics take a look at this doc.

Kubernetes

We will first need a Kubernetes cluster for our tests. If you are here you probably have access to a cluster in one way or another, but if you need one, you can create it locally very quickly with minikube. And if you're on MacOS it's even simpler since Docker Desktop embeds a local Kubernetes cluster.

kubectl

In order to interact with the cluster, we will use the command line tool kubectl. Follow the official documentation for installation process.

Helm (optional)

In this article, I present the installation of nsinjector with kubectl, but if you prefer Helm, I also propose a Chart here.

Installing nsinjector

Custom Resource Definition (CRD)

I won't go into details here, but a controller is generally based on the definition of custom resources (CRD) which allow to extend the functionalities of Kubernetes beyond the native objects (Deployment, Service, Job, etc.). nsinjector therefore uses the CRD NamespaceResourcesInjector to selectively deploy resource when a namespace is created.

To install this CRD, run the following command:

> kubectl apply -f https://raw.githubusercontent.com/blakelead/nsinjector/master/deploy/k8s/crd/namespaceresourcesinjector-crd-1.16.yaml
Enter fullscreen mode Exit fullscreen mode

Controller

The second step is to deploy the controller. Since the controller needs to interact with a large number of resources, we first apply the following RBAC objects:

# rbac.yaml

apiVersion: v1
kind: Namespace
metadata:
  name: nsinjector-controller

---

apiVersion: v1
kind: ServiceAccount
metadata:
  name: nsinjector-controller
  namespace: nsinjector-controller

---

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: nsinjector-controller
rules:
- apiGroups: [""]
  resources: ["namespaces"]
  verbs: ["list", "get", "watch"]
- apiGroups: ["blakelead.com"]
  resources: ["namespaceresourcesinjectors"]
  verbs: ["list", "get", "watch", "update"]
- apiGroups: ["rbac"]
  resources: ["*"]
  verbs: ["list", "get", "watch", "update"]

---

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: nsinjector-controller
subjects:
- kind: ServiceAccount
  name: nsinjector-controller
  namespace: nsinjector-controller
roleRef:
  kind: ClusterRole
  name: nsinjector-controller
  apiGroup: rbac.authorization.k8s.io
Enter fullscreen mode Exit fullscreen mode

Then apply them:

> kubectl apply -f rbac.yaml
Enter fullscreen mode Exit fullscreen mode

We can then deploy the controller itself:

# nsinjector-controller.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nsinjector-controller
  namespace: nsinjector-controller
  labels:
    app: nsinjector-controller
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nsinjector-controller
  template:
    metadata:
      labels:
        app: nsinjector-controller
    spec:
      serviceAccountName: nsinjector-controller
      containers:
      - name: nsinjector-controller
        image: blakelead/nsinjector-controller:v0.1.0
Enter fullscreen mode Exit fullscreen mode

Apply the file:

> kubectl apply -f nsinjector-controller.yaml
Enter fullscreen mode Exit fullscreen mode

NamespaceResourcesInjector

The controller is responsible for monitoring the creation of namespaces, and applying matching NamespaceResourcesInjector objects. Here is an example of a NamespaceResourcesInjector that can be applied:

# rbac-dev-inject.yaml

kind: NamespaceResourcesInjector
apiVersion: blakelead.com/v1alpha1
metadata:
  name: nri-test
spec:
  namespaces:
  - dev-.*
  resources:
  - |
    apiVersion: rbac.authorization.k8s.io/v1
    kind: Role
    metadata:
      name: dev-role
    rules:
      - apiGroups: [""]
        resources: ["pods", "pods/portforward", "services", "deployments", "ingresses"]
        verbs: ["list", "get"]
      - apiGroups: [""]
        resources: ["pods/portforward"]
        verbs: ["create"]
      - apiGroups: [""]
        resources: ["namespaces"]
        verbs: ["list", "get"]
  - |
    apiVersion: rbac.authorization.k8s.io/v1
    kind: RoleBinding
    metadata:
      name: dev-rolebinding
    subjects:
    - kind: User
      name: dev
    roleRef:
      kind: Role
      name: dev-role
      apiGroup: rbac.authorization.k8s.io
Enter fullscreen mode Exit fullscreen mode

Apply the file :

> kubectl apply -f rbac-dev-inject.yaml
Enter fullscreen mode Exit fullscreen mode

This will instruct the controller to deploy the dev-role and dev-rolebinding objects when a namespace whose name matches the dev-.* regex is created.

Create a namespace

Now if you create a namespace, you'll see that the two resources will automatically be created:

> kubectl create namespace dev-namespace-1
namespace "dev-namespace-1" created

> kubectl get clusterroles
NAME                        CREATED AT
dev-role                    2020-10-12T16:50:53Z
...

> kubectl get clusterrolebindings
NAME                ROLE                             AGE
dev-rolebinding     ClusterRole/dev-role             1m
...
Enter fullscreen mode Exit fullscreen mode

Conclusion

That's all for me. If you wan't to dive in the code of this controller, go to https://github.com/blakelead/nsinjector. And if you want to discuss about it, I'd be happy to!

Discussion (0)

pic
Editor guide