@@ -4,13 +4,6 @@ import (
4
4
"bytes"
5
5
"encoding/json"
6
6
"fmt"
7
- "log"
8
- "net/http"
9
- "os"
10
- "os/exec"
11
- "strings"
12
- "time"
13
-
14
7
"github.com/joho/godotenv"
15
8
"github.com/manzil-infinity180/k8s-custom-controller/controller"
16
9
admissionv1 "k8s.io/api/admission/v1"
@@ -22,6 +15,11 @@ import (
22
15
"k8s.io/client-go/rest"
23
16
"k8s.io/client-go/tools/clientcmd"
24
17
"k8s.io/client-go/tools/clientcmd/api"
18
+ "log"
19
+ "net/http"
20
+ "os"
21
+ "strings"
22
+ "time"
25
23
)
26
24
27
25
// homeDir retrieves the user's home directory
@@ -134,16 +132,7 @@ func main() {
134
132
fmt .Errorf ("%s" , err .Error ())
135
133
}
136
134
137
- // Start the webhook server in a goroutine
138
- go func () {
139
- http .HandleFunc ("/validate" , ValidateDeployment )
140
- log .Println ("Starting webhook server on :8000..." )
141
- // local go for certs/tls.crt and certs/tls.key
142
- err := http .ListenAndServeTLS (":8000" , "/certs/tls.crt" , "/certs/tls.key" , nil ) // k8s
143
- if err != nil {
144
- log .Fatalf ("Failed to start webhook server: %v" , err )
145
- }
146
- }()
135
+ http .HandleFunc ("/validate" , ValidateDeployment )
147
136
148
137
ch := make (chan struct {})
149
138
// factory
@@ -153,13 +142,6 @@ func main() {
153
142
c .Run (ch )
154
143
fmt .Println (factory )
155
144
factory .Apps ().V1 ().Deployments ().Informer ()
156
-
157
- // Block forever
158
- select {}
159
- }
160
-
161
- type Admitter struct {
162
- Request * admissionv1.AdmissionRequest
163
145
}
164
146
165
147
func parseRequest (r * http.Request ) (* admissionv1.AdmissionReview , error ) {
@@ -184,138 +166,45 @@ func parseRequest(r *http.Request) (*admissionv1.AdmissionReview, error) {
184
166
return & a , nil
185
167
}
186
168
187
- func scanImageWithTrivy (image string ) (bool , string , error ) {
188
- // cmd := exec.Command("trivy", "image", "--quiet", "--severity", "HIGH,CRITICAL", "--format", "json", image)
189
- // out, err := cmd.Output()
190
- cmd := exec .Command (
191
- "trivy" ,
192
- "image" ,
193
- "--scanners" , "vuln" ,
194
- "--server" , "http://trivy-server-service.default.svc:8080" , // [service_name].[namespace].svc:[port] (if not port 80)
195
- "--format" , "json" ,
196
- image ,
197
- )
198
- out , err := cmd .Output ()
199
- if err != nil {
200
- return false , "" , fmt .Errorf ("trivy scan failed for %s: %v" , image , err )
201
- }
202
- var result map [string ]interface {}
203
- if err := json .Unmarshal (out , & result ); err != nil {
204
- return false , "" , fmt .Errorf ("failed to parse trivy output: %v" , err )
205
- }
206
- // Check if vulnerabilities found
207
- vulns := []string {}
208
- log .Println ("❗CVEs Found: " )
209
- if results , ok := result ["Results" ].([]interface {}); ok {
210
- for _ , r := range results {
211
- rmap := r .(map [string ]interface {})
212
- if vlist , ok := rmap ["Vulnerabilities" ].([]interface {}); ok {
213
- for _ , v := range vlist {
214
- vmap := v .(map [string ]interface {})
215
- severity := vmap ["Severity" ].(string )
216
- if severity == "HIGH" || severity == "CRITICAL" {
217
- msg := fmt .Sprintf (" - 🔥 %s\n " , vmap ["VulnerabilityID" ].(string ))
218
- //vulns = append(vulns, vmap["VulnerabilityID"].(string))
219
- vulns = append (vulns , msg )
220
- }
221
- }
222
- }
223
- }
224
- }
225
- if len (vulns ) > 0 {
226
- return false , strings .Join (vulns , "," ), nil
227
- }
228
- return true , "" , nil
169
+ type Admitter struct {
170
+ Request * admissionv1.AdmissionRequest
229
171
}
172
+
230
173
func ValidateDeployment (w http.ResponseWriter , r * http.Request ) {
231
- log .Println ("Received /validate request" )
232
174
in , err := parseRequest (r )
233
175
if err != nil {
234
- log .Printf ("Error parsing admission request: %v" , err )
235
176
http .Error (w , err .Error (), http .StatusBadRequest )
236
177
return
237
178
}
238
179
180
+ //adm := Admitter{
181
+ // Request: in.Request,
182
+ //}
239
183
var dep appsv1.Deployment
240
184
if err := json .Unmarshal (in .Request .Object .Raw , & dep ); err != nil {
241
- log .Printf ("Failed to unmarshal deployment: %v" , err )
242
185
http .Error (w , fmt .Sprintf ("could not unmarshal deployment: %v" , err ), http .StatusBadRequest )
243
186
return
244
187
}
245
188
images := []string {}
246
- denied := false
247
- var reasons []string
248
- BYPASS_CVE_DENIED := false
249
- // InitContainers
250
- for _ , c := range dep .Spec .Template .Spec .InitContainers {
251
- for _ , e := range c .Env {
252
- if e .Name == "BYPASS_CVE_DENIED" && (e .Value == "yes" || e .Value == "true" ) {
253
- BYPASS_CVE_DENIED = true
254
- }
255
- }
256
- images = append (images , c .Image )
257
- }
258
- // Containers
259
189
for _ , c := range dep .Spec .Template .Spec .Containers {
260
- for _ , e := range c .Env {
261
- if e .Name == "BYPASS_CVE_DENIED" && (e .Value == "yes" || e .Value == "true" ) {
262
- BYPASS_CVE_DENIED = true
263
- }
264
- }
265
190
images = append (images , c .Image )
266
191
}
267
- for _ , image := range images {
268
- log .Println ("────────────────────────────────────────────────────" )
269
- log .Printf ("🛡️ Deployment Image Scanning Started : %s\n " , image )
270
- if BYPASS_CVE_DENIED {
271
- log .Println ("📦 BYPASS_CVE_DENIED: true/yes" )
272
- } else {
273
- log .Println ("📦 BYPASS_CVE_DENIED: default(false/no)" )
274
- }
275
- ok , vulns , err := scanImageWithTrivy (image )
276
- if err != nil {
277
- log .Printf ("Error scanning image %s: %v" , image , err )
278
- continue
279
- }
280
- log .Println ("────────────────────────────────────────────────────" )
281
- if ! ok {
282
- denied = true
283
- reasons = append (reasons , fmt .Sprintf ("%s (CVE: %s)" , image , vulns ))
284
- }
285
- }
286
- message := "Images allowed"
287
- if denied {
288
- message = fmt .Sprintf ("Denied images due to total CVEs across %v images: %v" , len (images ), reasons )
289
- log .Printf ("Denied images due to CVEs: %v" , reasons )
290
- }
291
-
292
- // look for BYPASS_CVE env - you need to skip
293
- if BYPASS_CVE_DENIED {
294
- log .Printf ("It have CVE across all the %v images, but we are skipping as BYPASS_CVE_DENIED set true" , len (images ))
295
- denied = false
296
- }
297
-
298
- log .Printf ("Validating Deployment: %s, Images: %v" , dep .Name , images )
299
192
response := admissionv1.AdmissionReview {
300
193
TypeMeta : in .TypeMeta ,
301
194
Response : & admissionv1.AdmissionResponse {
302
195
UID : in .Request .UID ,
303
- Allowed : ! denied ,
196
+ Allowed : false ,
304
197
Result : & metav1.Status {
305
- Message : message ,
198
+ Message : fmt . Sprintf ( "Denied images: %v" , images ) ,
306
199
},
307
200
},
308
201
}
309
202
w .Header ().Set ("Content-Type" , "application/json" )
310
203
jout , err := json .Marshal (response )
311
204
if err != nil {
312
205
e := fmt .Sprintf ("could not parse admission response: %v" , err )
313
- log .Println (e )
314
206
http .Error (w , e , http .StatusInternalServerError )
315
207
return
316
208
}
317
- if _ , err := w .Write (jout ); err != nil {
318
- log .Printf ("Failed to write response: %v" , err )
319
- }
320
- log .Println ("Admission response sent" )
209
+ w .Write (jout )
321
210
}
0 commit comments