Last active
May 13, 2023 15:50
-
-
Save theodesp/74c2b86c119c5ddaf1e1750429193cef to your computer and use it in GitHub Desktop.
Custom Admission Controller K8s
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
apiVersion: apps/v1 | |
kind: Deployment | |
metadata: | |
name: webhook-server | |
namespace: webhook-demo | |
labels: | |
app: webhook-server | |
spec: | |
replicas: 1 | |
selector: | |
matchLabels: | |
app: webhook-server | |
template: | |
metadata: | |
labels: | |
app: webhook-server | |
spec: | |
containers: | |
- name: server | |
image: localhost:5001/webhook:latest | |
imagePullPolicy: Always | |
ports: | |
- containerPort: 8443 | |
name: webhook-api | |
volumeMounts: | |
- name: webhook-tls-certs | |
mountPath: /run/secrets/tls | |
readOnly: true | |
volumes: | |
- name: webhook-tls-certs | |
secret: | |
secretName: webhook-server-tls | |
--- | |
apiVersion: v1 | |
kind: Service | |
metadata: | |
name: webhook-server | |
namespace: webhook-demo | |
spec: | |
selector: | |
app: webhook-server | |
ports: | |
- port: 443 | |
targetPort: webhook-api | |
--- | |
apiVersion: admissionregistration.k8s.io/v1 | |
kind: ValidatingWebhookConfiguration | |
metadata: | |
name: demo-webhook | |
webhooks: | |
- name: webhook-server.webhook-demo.svc | |
clientConfig: | |
service: | |
name: webhook-server | |
namespace: webhook-demo | |
path: "/validate" | |
caBundle: "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUMyakNDQWNJQ0NRQ1RxM3EvWGJTRUV6QU5CZ2txaGtpRzl3MEJBUXNGQURBdk1TMHdLd1lEVlFRRERDUkIKWkcxcGMzTnBiMjRnUTI5dWRISnZiR3hsY2lCWFpXSm9iMjlySUVSbGJXOGdRMEV3SGhjTk1qTXdOVEV6TVRRMApOalE1V2hjTk1qTXdOakV5TVRRME5qUTVXakF2TVMwd0t3WURWUVFERENSQlpHMXBjM05wYjI0Z1EyOXVkSEp2CmJHeGxjaUJYWldKb2IyOXJJRVJsYlc4Z1EwRXdnZ0VpTUEwR0NTcUdTSWIzRFFFQkFRVUFBNElCRHdBd2dnRUsKQW9JQkFRQ3dneVZhWTdFdzZoK09TTk5KV1hjdmFLVWt5RGtuVEx6RzFOWjcwK256N3N6U0YyWUMxOFFPMm1GegovalJOZnRPbU4zQTFaWFhCcFFBcGVScWdsWTl4dHYwV1BKdzlvcWlDY1AvdGVybDdmdzZNNStzTnBEN0h3Y3hxClkzOFFQUWF0dlQrcnhWb2VPRnlSM0NQYmRDMmxpSE9SbE9zU0g3UThybldadXNSaGV3ZFVkQ1R1Q3VSaEdpNmMKTUJRSU84dHZKNmlqTFU3b3VXSmxwckU4T0xqV3lGeFVWeFBnMzlUWFZyK2duZ2tDQ2xWakwvSHNHOGZHUE9KMApSdWI5WXRPK0FKNDhIblFHaHUrRURZNTcwdHIwK3hUY09JZXcrQTVOTktzY0VQNjI5eXc1VWcwMEp4YmNKNkszCndrSWp3UjQ4NFpTc1ZWd0VIemZXdlNQYUJJMUxBZ01CQUFFd0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQkFCR3gKODBvc2d3SXdQT1pELzEzY3BlQWtFaGNKKzRlbHlnb09IbWxkbFNJRkVtcFdjQ01FWkxkTG9rSnNDNklqWU05NApwRVgwRTVxelR3aDBOZEVwelR2eHB3RjRPMHQyZDFzSG5hU0QvT1czVjNsdDJTdXFWREp0YlNSeXdpTks1YS9RCk5ac2RKbkM2N3FEV01rY2xEZ0NpWjZBMU4xRUxWVm5OU1dzN0psSkVGM1FaRDFmSldoNy9ycmszdmhVTm5yT1oKTnhyeDI3amVuNGdWK1VZNnJOT2FkOEkzaG9HcEMrYnVMMTBTUEJNRGxXbHBKZStlM0I1WWdqbVFyQmNFeEtQTgpzMjVsVHBvNVpZVjhKeHJJTFJyaDJOdGdBVWdhYkxxR1BIQk9nZ0prMEJMWC8vYnZMQWx5RFRFZWppcWczVTJFClJxUGR5N2IwZWpGYjlGT1dmb1U9Ci0tLS0tRU5EIENFUlRJRklDQVRFLS0tLS0K" | |
rules: | |
- operations: [ "CREATE", "UPDATE" ] | |
apiGroups: [""] | |
apiVersions: ["v1"] | |
resources: ["pods"] | |
admissionReviewVersions: ["v1"] | |
sideEffects: None |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# build stage | |
FROM golang:1.20 AS build-env | |
RUN mkdir -p /app | |
WORKDIR /app | |
COPY . . | |
RUN useradd -u 10001 webhook | |
RUN CGO_ENABLED=0 GOOS=linux go build -a -ldflags '-extldflags "-static"' -o webhook | |
FROM scratch | |
COPY --from=build-env /app . | |
COPY --from=build-env /etc/passwd /etc/passwd | |
USER webhook | |
ENTRYPOINT ["/webhook"] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"context" | |
"crypto/tls" | |
"encoding/json" | |
"flag" | |
"fmt" | |
"io/ioutil" | |
"net/http" | |
"os" | |
"os/signal" | |
"syscall" | |
"github.com/golang/glog" | |
"k8s.io/api/admission/v1" | |
v1 "k8s.io/api/core/v1" | |
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | |
) | |
var ( | |
tlscert, tlskey string | |
) | |
func main() { | |
flag.StringVar(&tlscert, "tlsCertFile", "/etc/certs/ca.crt", "File containing the x509 Certificate for HTTPS.") | |
flag.StringVar(&tlskey, "tlsKeyFile", "/etc/certs/ca.key", "File containing the x509 private key to --tlsCertFile.") | |
flag.Parse() | |
certs, err := tls.LoadX509KeyPair(tlscert, tlskey) | |
if err != nil { | |
glog.Errorf("Filed to load key pair: %v", err) | |
} | |
server := &http.Server{ | |
Addr: ":8443", | |
TLSConfig: &tls.Config{Certificates: []tls.Certificate{certs}}, | |
} | |
web := WebhookServerHandler{} | |
mux := http.NewServeMux() | |
mux.HandleFunc("/validate", web.serve) | |
server.Handler = mux | |
go func() { | |
if err := server.ListenAndServeTLS("", ""); err != nil { | |
glog.Errorf("Failed to listen and serve webhook server: %v", err) | |
} | |
}() | |
signalChan := make(chan os.Signal, 1) | |
signal.Notify(signalChan, syscall.SIGINT, syscall.SIGTERM) | |
<-signalChan | |
server.Shutdown(context.Background()) | |
} | |
type WebhookServerHandler struct { | |
} | |
func (web *WebhookServerHandler) serve(w http.ResponseWriter, r *http.Request) { | |
var body []byte | |
if r.Body != nil { | |
if data, err := ioutil.ReadAll(r.Body); err == nil { | |
body = data | |
} | |
} | |
if len(body) == 0 { | |
http.Error(w, "empty body", http.StatusBadRequest) | |
return | |
} | |
if r.URL.Path != "/validate" { | |
http.Error(w, "no validate", http.StatusBadRequest) | |
return | |
} | |
req := v1beta1.AdmissionReview{} | |
if err := json.Unmarshal(body, &req := v1beta1.AdmissionReview{}); err != nil { | |
http.Error(w, "incorrect body", http.StatusBadRequest) | |
} | |
raw := req.Request.Object.Raw | |
pod := v1.Pod{} | |
if err := json.Unmarshal(raw, &pod); err != nil { | |
return | |
} | |
// perform validation check here | |
if _, ok := pod.Labels["foo"]; ok { | |
return | |
} | |
review := v1beta1.AdmissionReview{ | |
Response: &v1beta1.AdmissionResponse{ | |
Allowed: false, | |
Result: &metav1.Status{ | |
Message: "Missing Pod Label!", | |
}, | |
}, | |
} | |
resp, err := json.Marshal(review) | |
if err != nil { | |
http.Error(w, fmt.Sprintf("could not encode response: %v", err), http.StatusInternalServerError) | |
} | |
if _, err := w.Write(resp); err != nil { | |
http.Error(w, fmt.Sprintf("could not write response: %v", err), http.StatusInternalServerError) | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment