Skip to content

Commit fb0f681

Browse files
wip: version2 working demo - but it takes alot of time
1 parent c751b76 commit fb0f681

File tree

6 files changed

+65
-16
lines changed

6 files changed

+65
-16
lines changed

.gitignore

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,4 @@ vendor\
55
.DS_Store
66
vendor
77
.env
8-
results.json
9-
certs
8+
results.json

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
APP_NAME = k8s-custom-controller
22
DOCKER_USER = manzilrahul
3-
VERSION ?= 1.0.9
3+
VERSION ?= 1.0.11
44
IMAGE_NAME = $(DOCKER_USER)/$(APP_NAME)
55

66
# 🖼️ Logo banner

main.go

Lines changed: 60 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"log"
1919
"net/http"
2020
"os"
21+
"os/exec"
2122
"strings"
2223
"time"
2324
)
@@ -155,6 +156,10 @@ func main() {
155156
select {}
156157
}
157158

159+
type Admitter struct {
160+
Request *admissionv1.AdmissionRequest
161+
}
162+
158163
func parseRequest(r *http.Request) (*admissionv1.AdmissionReview, error) {
159164
if r.Header.Get("Content-Type") != "application/json" {
160165
return nil, fmt.Errorf("Content-Type: %q should be %q",
@@ -177,10 +182,37 @@ func parseRequest(r *http.Request) (*admissionv1.AdmissionReview, error) {
177182
return &a, nil
178183
}
179184

180-
type Admitter struct {
181-
Request *admissionv1.AdmissionRequest
185+
func scanImageWithTrivy(image string) (bool, string, error) {
186+
cmd := exec.Command("trivy", "image", "--quiet", "--severity", "HIGH,CRITICAL", "--format", "json", image)
187+
out, err := cmd.Output()
188+
if err != nil {
189+
return false, "", fmt.Errorf("trivy scan failed for %s: %v", image, err)
190+
}
191+
var result map[string]interface{}
192+
if err := json.Unmarshal(out, &result); err != nil {
193+
return false, "", fmt.Errorf("failed to parse trivy output: %v", err)
194+
}
195+
// Check if vulnerabilities found
196+
vulns := []string{}
197+
if results, ok := result["Results"].([]interface{}); ok {
198+
for _, r := range results {
199+
rmap := r.(map[string]interface{})
200+
if vlist, ok := rmap["Vulnerabilities"].([]interface{}); ok {
201+
for _, v := range vlist {
202+
vmap := v.(map[string]interface{})
203+
severity := vmap["Severity"].(string)
204+
if severity == "HIGH" || severity == "CRITICAL" {
205+
vulns = append(vulns, vmap["VulnerabilityID"].(string))
206+
}
207+
}
208+
}
209+
}
210+
}
211+
if len(vulns) > 0 {
212+
return false, strings.Join(vulns, ","), nil
213+
}
214+
return true, "", nil
182215
}
183-
184216
func ValidateDeployment(w http.ResponseWriter, r *http.Request) {
185217
log.Println("Received /validate request")
186218
in, err := parseRequest(r)
@@ -190,27 +222,47 @@ func ValidateDeployment(w http.ResponseWriter, r *http.Request) {
190222
return
191223
}
192224

193-
//adm := Admitter{
194-
// Request: in.Request,
195-
//}
196225
var dep appsv1.Deployment
197226
if err := json.Unmarshal(in.Request.Object.Raw, &dep); err != nil {
198227
log.Printf("Failed to unmarshal deployment: %v", err)
199228
http.Error(w, fmt.Sprintf("could not unmarshal deployment: %v", err), http.StatusBadRequest)
200229
return
201230
}
202231
images := []string{}
232+
denied := false
233+
var reasons []string
234+
// InitContainers
235+
for _, c := range dep.Spec.Template.Spec.InitContainers {
236+
images = append(images, c.Image)
237+
}
238+
// Containers
203239
for _, c := range dep.Spec.Template.Spec.Containers {
204240
images = append(images, c.Image)
205241
}
242+
for _, image := range images {
243+
ok, vulns, err := scanImageWithTrivy(image)
244+
if err != nil {
245+
log.Printf("Error scanning image %s: %v", image, err)
246+
continue
247+
}
248+
if !ok {
249+
denied = true
250+
reasons = append(reasons, fmt.Sprintf("%s (CVE: %s)", image, vulns))
251+
}
252+
}
253+
message := "Images allowed"
254+
if denied {
255+
message = fmt.Sprintf("Denied images due to CVEs: %v", reasons)
256+
}
257+
206258
log.Printf("Validating Deployment: %s, Images: %v", dep.Name, images)
207259
response := admissionv1.AdmissionReview{
208260
TypeMeta: in.TypeMeta,
209261
Response: &admissionv1.AdmissionResponse{
210262
UID: in.Request.UID,
211-
Allowed: false,
263+
Allowed: !denied,
212264
Result: &metav1.Status{
213-
Message: fmt.Sprintf("Denied images: %v", images),
265+
Message: message,
214266
},
215267
},
216268
}

manifest/k8s-controller-webhook.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ webhooks:
3535
admissionReviewVersions:
3636
- v1
3737
sideEffects: None
38+
timeoutSeconds: 30
3839
clientConfig:
3940
service:
4041
name: k8s-custom-controller-service
@@ -66,7 +67,7 @@ spec:
6667
spec:
6768
containers:
6869
- name: k8s-controller
69-
image: manzilrahul/k8s-custom-controller:1.0.9
70+
image: manzilrahul/k8s-custom-controller:1.0.11
7071
volumeMounts:
7172
- name: webhook-certs
7273
mountPath: /certs

manifest/webhook-example/ZeroInitCVE.yml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,3 @@ spec:
2222
image: nginx:1.19 # Will have CVEs
2323
ports:
2424
- containerPort: 80
25-
env:
26-
- name: BYPASS_CVE_DENIED
27-
value: "yes" # yes or true (lowercase)

manifest/webhook-example/initContainerDeployment.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,6 @@ spec:
1919
command: ["sh", "-c", "echo Init container with CVEs"]
2020
containers:
2121
- name: main-vulnerable
22-
image: cgr.dev/chainguard/nginx:latest # Main container with CVEs
22+
image: nginx:1.19 # Main container with CVEs
2323
ports:
2424
- containerPort: 80

0 commit comments

Comments
 (0)