Skip to content

Commit 31479e4

Browse files
Merge pull request #28 from manzil-infinity180/webhook-helm-docs
wip: Webhook helm docs
2 parents e1f821a + 2945d69 commit 31479e4

19 files changed

+484
-198
lines changed

Readme.md

Lines changed: 74 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,92 @@
1-
## The Architecture of Controllers
2-
Since controllers are in charge of meeting the desired state of the resources in Kubernetes, they somehow need to be informed about the changes on the resources and perform certain operations if needed. For this, controllers follow a special architecture to
1+
<div align="center">
2+
<p align="center">
3+
<img width="960" height="309" alt="final-k8s" src="https://github.com/user-attachments/assets/e5ef535e-a07a-4cd5-9fbd-926a0c62cf39" />
4+
</p>
35

4-
1) observe the resources,
5-
2) inform any events (updating, deleting, adding) done on the resources,
6-
3) keep a local cache to decrease the load on API Server,
7-
4) keep a work queue to pick up events,
8-
5) run workers to perform reconciliation on resources picked up from work queue.
6+
[![Watch the demo video](https://github.com/user-attachments/assets/4ba51960-d9d2-4ac4-9272-c4ee3c5cf262)](https://www.youtube.com/watch?v=mAr62XBVbmg)
7+
</div>
98

10-
<a href="https://www.nakamasato.com/kubernetes-training/kubernetes-operator/client-go/informer/" >
11-
<h4 class="text-yellow-300 text-lg">Ref: Official Docs</h4>
12-
</a>
13-
<a href="https://github.com/kubernetes/community/blob/8cafef897a22026d42f5e5bb3f104febe7e29830/contributors/devel/controllers.md">
14-
<h4 class="text-yellow-300 text-lg">Writing Controllers (Imp)</h4>
15-
</a>
9+
> 📽️ Click the image above to watch the full 25-minute walkthrough on YouTube.
10+
> It includes setup, explanation, CVE scan demo, and auto resource creation.
1611
17-
# Factory & Informers
1812

19-
![image](https://github.com/user-attachments/assets/bb09fdaf-a1d8-4f9b-bfd4-a7914ebe6eba)
13+
# 🛡️ Kubernetes CVE Scanner with Custom Controller + Admission Webhook
2014

21-
# Single Informer
15+
This project includes a **Kubernetes custom controller** that:
16+
- Automatically creates **Services** and **Ingresses** for every `Deployment`.
17+
- Integrates with a **Validating Admission Webhook** to scan container images using **Trivy**.
18+
- Optionally allows skipping CVE checks with an environment variable.
2219

23-
![image](https://github.com/user-attachments/assets/bfc1720a-aab4-4595-bb4b-9559a3e98d74)
20+
---
2421

25-
![image](https://github.com/user-attachments/assets/1af2d969-5b93-40f4-b375-219342c16041)
22+
## 🚀 Installation Guide
2623

24+
### 1️⃣ Create a Kubernetes Cluster
2725

28-
[//]: # (https://github.com/user-attachments/assets/851d2b2b-d268-4894-a15a-dbe8b501b3cc)
26+
Make sure you have a running Kubernetes cluster (like KinD, Minikube, or EKS).
2927

30-
## Definition : Informer
3128

32-
Informer monitors the changes of target resource. An informer is created for each of the target resources if you need to handle multiple resources (e.g. podInformer, deploymentInformer).
29+
### 2️⃣ Install `cert-manager`
3330

31+
```bash
32+
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.18.2/cert-manager.yaml
33+
```
34+
This will install the necessary CRDs and controllers for certificate management.
3435

36+
### 3️⃣ Deploy Trivy as a Service
37+
```bash
38+
kubectl apply -f docs/trivy-manifest/deployment.yml
39+
kubectl apply -f docs/trivy-manifest/service.yml
40+
```
41+
Trivy will act as the backend scanner for your webhook.
42+
> Note: We are running using trivy client you can see the command [here](https://github.com/aquasecurity/trivy/discussions/2119)
3543
36-
```md
37-
1) Initialize the Controller
38-
* The NewController function sets up the Kubernetes controller with a work queue, informer, and WebSocket connection.
39-
* It listens for Deployment events (Add, Update, Delete) and enqueues them.
44+
### 4️⃣ Create Cluster Role & Bindings
45+
* Grant required permissions for:
46+
- Deployments
47+
- Services
48+
- Secrets
49+
- Ingresses
50+
- ValidatingWebhookConfigurations
51+
```bash
52+
kubectl apply -f manifest/cluster-permission.yaml
4053

41-
2) Run the Controller
42-
* The Run method waits for cache synchronization and starts the worker loop.
43-
* It continuously processes events from the work queue.
54+
```
4455

45-
3) Process Deployment Events
46-
* The processItem method retrieves Deployment events from the queue and determines the necessary action.
47-
* It fetches the Deployment details and handles errors, deletions, and updates.
56+
### 5️⃣ Deploy Controller + Webhook
57+
* This manifest includes:
58+
- Namespace
59+
- Deployment
60+
- Service
61+
- TLS Issuers + Certs
62+
- ValidatingWebhookConfiguration
4863

49-
4) Handle Deployment Changes
50-
* `handleAdd`, `handleUpdate`, and `handleDel` respond to Deployment changes.
51-
* Updates track Replica count and Image changes and send logs via WebSocket.
64+
```ts
65+
kubectl apply -f manifest/k8s-controller-webhook.yaml
66+
```
67+
### 6️⃣ Test Webhook
68+
```ts
69+
# contain cve
70+
$ kubectl apply -f manifest/webhook-example/initContainerDeployment.yml
71+
# look for first time it might fail (look at the logs of the application (k8s-custom-controller) and
72+
# see if they return a long list of CVE -> then start creating again (Working on to optimize)
5273

53-
5) Send Updates via WebSocket
54-
* The updateLogs function logs and sends JSON messages about Deployment changes.
55-
* The WebSocket connection ensures real-time updates for external systems.
74+
# pure zero cve (does not contain cve)
75+
$ kubectl apply -f manifest/webhook-example/pureZeroCVE.yml
76+
77+
# contain cve but bypass (i mean create the deployment even after having CVE)
78+
# due to this parameter `name: BYPASS_CVE_DENIED` set as yes or true
79+
$ kubectl apply -f manifest/webhook-example/ZeroInitCVE.yml
80+
```
81+
> Todo:
82+
> Better docs and guide
83+
84+
<p align="center">
85+
<img width="450" height="450" alt="image" src="https://github.com/user-attachments/assets/92fe17a5-bffe-469d-beb3-0769bb85d4a5" />
86+
</p>
87+
88+
## Author
89+
90+
Built with 💙 by **Rahul Vishwakarma**
91+
92+
> Happy Scan-ing!

chart/templates/cert-manager.yaml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# for running this you need to have cert-manager install on your cluster
2+
# Installation: https://cert-manager.io/docs/installation/
3+
---
4+
apiVersion: cert-manager.io/v1
5+
kind: Issuer
6+
metadata:
7+
name: selfsigned
8+
namespace: {{ .Values.image.namespace }}
9+
spec:
10+
selfSigned: {}
11+
---
12+
apiVersion: cert-manager.io/v1
13+
kind: Certificate
14+
metadata:
15+
name: "{{ .Values.webhook.name }}-certificate" #webhook1-certificate
16+
namespace: {{ .Values.image.namespace }}
17+
spec:
18+
secretName: "{{ .Chart.Name }}-tls" # Secret mounted in deployment
19+
dnsNames:
20+
- "{{ include "chart.fullname" . }}.{{ .Values.image.namespace }}.svc"
21+
- "{{ include "chart.fullname" . }}.{{ .Values.image.namespace }}.svc.cluster.local"
22+
issuerRef:
23+
name: selfsigned
24+
---

chart/templates/clusterrole.yaml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,16 @@ metadata:
55
rules:
66
- apiGroups: ["apps"]
77
resources: ["deployments"]
8-
verbs: ["get", "list", "watch"]
8+
verbs: [ "get", "list", "watch", "create", "update", "patch" ]
99
- apiGroups: [""]
1010
resources: ["services"]
1111
verbs: ["get", "list", "watch", "create", "update"]
1212
- apiGroups: ["networking.k8s.io"]
1313
resources: ["ingresses"]
1414
verbs: ["get", "list", "watch", "create", "update"]
15+
- apiGroups: [ "admissionregistration.k8s.io" ]
16+
resources: [ "validatingwebhookconfigurations" ]
17+
verbs: [ "get", "list", "watch", "create", "update", "patch" ]
18+
- apiGroups: [ "" ]
19+
resources: [ "secrets" ]
20+
verbs: [ "get", "list", "watch", "create", "update", "patch" ]

chart/templates/clusterrolebinding.yaml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ metadata:
44
name: {{ include "chart.fullname" . }}
55
subjects:
66
- kind: ServiceAccount
7-
name: {{ include "chart.serviceAccountName" . }}
8-
namespace: {{ .Release.Namespace }}
7+
name: default
8+
namespace: {{ .Values.image.namespace }}
99
roleRef:
1010
kind: ClusterRole
1111
name: {{ include "chart.fullname" . }}
12-
apiGroup: rbac.authorization.k8s.io
12+
apiGroup: rbac.authorization.k8s.io

chart/templates/deployment.yaml

Lines changed: 16 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -2,72 +2,32 @@ apiVersion: apps/v1
22
kind: Deployment
33
metadata:
44
name: {{ include "chart.fullname" . }}
5-
labels:
6-
{{- include "chart.labels" . | nindent 4 }}
5+
namespace: {{ .Values.image.namespace }}
76
spec:
8-
{{- if not .Values.autoscaling.enabled }}
9-
replicas: {{ .Values.replicaCount }}
10-
{{- end }}
7+
replicas: 1
118
selector:
129
matchLabels:
13-
{{- include "chart.selectorLabels" . | nindent 6 }}
10+
k8s.custom.controller: k8s-custom-controller
1411
template:
1512
metadata:
16-
{{- with .Values.podAnnotations }}
17-
annotations:
18-
{{- toYaml . | nindent 8 }}
19-
{{- end }}
2013
labels:
21-
{{- include "chart.labels" . | nindent 8 }}
22-
{{- with .Values.podLabels }}
23-
{{- toYaml . | nindent 8 }}
24-
{{- end }}
14+
k8s.custom.controller: k8s-custom-controller
2515
spec:
26-
{{- with .Values.imagePullSecrets }}
27-
imagePullSecrets:
28-
{{- toYaml . | nindent 8 }}
29-
{{- end }}
30-
serviceAccountName: {{ include "chart.serviceAccountName" . }}
31-
{{- with .Values.podSecurityContext }}
32-
securityContext:
33-
{{- toYaml . | nindent 8 }}
34-
{{- end }}
3516
containers:
3617
- name: {{ .Chart.Name }}
37-
{{- with .Values.securityContext }}
38-
securityContext:
39-
{{- toYaml . | nindent 12 }}
40-
{{- end }}
4118
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
19+
volumeMounts:
20+
- name: {{ .Values.webhook.volumeMounts }}
21+
mountPath: /certs
22+
readOnly: true
4223
env:
24+
- name: TLS_CERT_FILE
25+
value: "/certs/tls.crt"
26+
- name: TLS_KEY_FILE
27+
value: "/certs/tls.key"
4328
- name: CONTEXT
44-
value: {{ .Values.context | quote }}
45-
imagePullPolicy: {{ .Values.image.pullPolicy }}
46-
ports:
47-
- name: http
48-
containerPort: {{ .Values.service.port }}
49-
protocol: TCP
50-
{{- with .Values.resources }}
51-
resources:
52-
{{- toYaml . | nindent 12 }}
53-
{{- end }}
54-
{{- with .Values.volumeMounts }}
55-
volumeMounts:
56-
{{- toYaml . | nindent 12 }}
57-
{{- end }}
58-
{{- with .Values.volumes }}
29+
value: "kind-practice"
5930
volumes:
60-
{{- toYaml . | nindent 8 }}
61-
{{- end }}
62-
{{- with .Values.nodeSelector }}
63-
nodeSelector:
64-
{{- toYaml . | nindent 8 }}
65-
{{- end }}
66-
{{- with .Values.affinity }}
67-
affinity:
68-
{{- toYaml . | nindent 8 }}
69-
{{- end }}
70-
{{- with .Values.tolerations }}
71-
tolerations:
72-
{{- toYaml . | nindent 8 }}
73-
{{- end }}
31+
- name: {{ .Values.webhook.volumeMounts }}
32+
secret:
33+
secretName: "{{ .Chart.Name }}-tls"

chart/templates/ingress.yaml

Lines changed: 0 additions & 43 deletions
This file was deleted.

chart/templates/namespace.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
apiVersion: v1
2+
kind: Namespace
3+
metadata:
4+
name: {{ .Values.image.namespace }}

chart/templates/service.yaml

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,12 @@ apiVersion: v1
22
kind: Service
33
metadata:
44
name: {{ include "chart.fullname" . }}
5-
labels:
6-
{{- include "chart.labels" . | nindent 4 }}
5+
namespace: {{ .Values.image.namespace }}
76
spec:
8-
type: {{ .Values.service.type }}
9-
ports:
10-
- port: {{ .Values.service.port }}
11-
targetPort: 8000 #http
12-
protocol: TCP
13-
name: http
147
selector:
15-
{{- include "chart.selectorLabels" . | nindent 4 }}
8+
k8s.custom.controller: k8s-custom-controller
9+
ports:
10+
- protocol: TCP
11+
port: {{ .Values.service.port }}
12+
targetPort: 8000
13+
type: ClusterIP

chart/templates/trivy-deployment.yaml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
apiVersion: apps/v1
2+
kind: Deployment
3+
metadata:
4+
name: {{ .Values.trivy.name }}
5+
labels:
6+
app: {{ .Values.trivy.name }}
7+
spec:
8+
replicas: 1 # You can adjust the number of replicas for high availability
9+
selector:
10+
matchLabels:
11+
app: {{ .Values.trivy.name }}
12+
template:
13+
metadata:
14+
labels:
15+
app: {{ .Values.trivy.name }}
16+
spec:
17+
containers:
18+
- name: {{ .Values.trivy.name }}
19+
image: "{{ .Values.trivy.image }}:{{ .Values.trivy.tag }}"# aquasec/trivy:latest # Use a specific version instead of latest in production
20+
args: ["server", "--listen", "0.0.0.0:8080"] # Listen on all interfaces
21+
ports:
22+
- containerPort: 8080
23+
name: http
24+
# volumeMounts:
25+
# - name: trivy-cache
26+
# mountPath: /root/.cache/trivy
27+
# volumes:
28+
# - name: trivy-cache
29+
# persistentVolumeClaim:
30+
# claimName: trivy-cache-pvc

chart/templates/trivy-service.yaml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
apiVersion: v1
2+
kind: Service
3+
metadata:
4+
name: "{{ .Values.trivy.name }}-service"
5+
labels:
6+
app: {{ .Values.trivy.name }}
7+
spec:
8+
selector:
9+
app: {{ .Values.trivy.name }}
10+
ports:
11+
- protocol: TCP
12+
port: 8080
13+
targetPort: 8080
14+
type: ClusterIP

0 commit comments

Comments
 (0)