Skip to content

Instantly share code, notes, and snippets.

@jiahuif
Last active March 20, 2024 23:49
Show Gist options
  • Save jiahuif/2653f2ce41fe6a2e5739ea7cd76b182b to your computer and use it in GitHub Desktop.
Save jiahuif/2653f2ce41fe6a2e5739ea7cd76b182b to your computer and use it in GitHub Desktop.
Minimalist Kubernetes Validating Admission Webhook
package main
import (
"encoding/json"
"flag"
"fmt"
"log"
"net/http"
admissionv1 "k8s.io/api/admission/v1"
appsv1 "k8s.io/api/apps/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/errors"
)
func verifyDeployment(deploy *appsv1.Deployment) error {
var errs []error
for i, c := range deploy.Spec.Template.Spec.Containers {
if c.Name == "" {
return fmt.Errorf("container %d has no name", i)
}
if c.SecurityContext == nil {
errs = append(errs, fmt.Errorf("container %q does not have SecurityContext", c.Name))
}
if c.SecurityContext.RunAsNonRoot == nil || !*c.SecurityContext.RunAsNonRoot {
errs = append(errs, fmt.Errorf("container %q must set RunAsNonRoot to true in its SecurityContext", c.Name))
}
if c.SecurityContext.ReadOnlyRootFilesystem == nil || !*c.SecurityContext.ReadOnlyRootFilesystem {
errs = append(errs, fmt.Errorf("container %q must set ReadOnlyRootFilesystem to true in its SecurityContext", c.Name))
}
if c.SecurityContext.AllowPrivilegeEscalation != nil && *c.SecurityContext.AllowPrivilegeEscalation {
errs = append(errs, fmt.Errorf("container %q must NOT set AllowPrivilegeEscalation to true in its SecurityContext", c.Name))
}
if c.SecurityContext.Privileged != nil && *c.SecurityContext.Privileged {
errs = append(errs, fmt.Errorf("container %q must NOT set Privileged to true in its SecurityContext", c.Name))
}
}
return errors.NewAggregate(errs)
}
func WebhookEnforceSecurePodConfiguration(rw http.ResponseWriter, req *http.Request) {
result := &admissionv1.AdmissionReview{Response: &admissionv1.AdmissionResponse{}}
err := func() error {
ar := new(admissionv1.AdmissionReview)
err := json.NewDecoder(req.Body).Decode(ar)
if err != nil {
return err
}
if ar.Request == nil {
return nil
}
result.TypeMeta = ar.TypeMeta
result.Response.UID = ar.Request.UID
if len(ar.Request.Object.Raw) == 0 {
return nil
}
deploy := new(appsv1.Deployment)
err = json.Unmarshal(ar.Request.Object.Raw, deploy)
if err != nil {
return err
}
return verifyDeployment(deploy)
}()
if err == nil {
result.Response.Allowed = true
} else {
result.Response.Allowed = false
result.Response.Result = &metav1.Status{
Code: http.StatusForbidden,
Message: err.Error(),
}
}
err = json.NewEncoder(rw).Encode(result)
if err != nil {
log.Println(err)
}
}
var _ http.HandlerFunc = WebhookEnforceSecurePodConfiguration
func main() {
http.HandleFunc("/", WebhookEnforceSecurePodConfiguration)
addr := flag.String("addr", ":8443", "address to listen on")
certFile := flag.String("cert", "cert.pem", "path to TLS certificate")
keyFile := flag.String("key", "key.pem", "path to TLS key")
flag.Parse()
log.Fatalln(http.ListenAndServeTLS(*addr, *certFile, *keyFile, nil))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment