Skip to content

Commit eb8cbb6

Browse files
committed
validation: run skipper in validation mode inside webhook
We leave webhook binary for backward combitability but use skipper in validation mode everywhere as source of truth Signed-off-by: Mustafa Abdelrahman <[email protected]>
1 parent a0858f5 commit eb8cbb6

File tree

3 files changed

+31
-79
lines changed

3 files changed

+31
-79
lines changed

cmd/webhook/main.go

Lines changed: 10 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,12 @@
11
package main
22

33
import (
4-
"context"
54
"flag"
6-
"net/http"
75
"os"
8-
"os/signal"
9-
"syscall"
10-
"time"
116

12-
"github.com/zalando/skipper/dataclients/kubernetes/admission"
7+
"github.com/zalando/skipper"
138

14-
"github.com/prometheus/client_golang/prometheus/promhttp"
159
log "github.com/sirupsen/logrus"
16-
"github.com/zalando/skipper/dataclients/kubernetes/definitions"
1710
)
1811

1912
const (
@@ -35,16 +28,6 @@ func (c *config) parse() {
3528
flag.StringVar(&c.address, "address", defaultHTTPSAddress, "The address to listen on")
3629
flag.Parse()
3730

38-
if (c.certFile != "" || c.keyFile != "") && !(c.certFile != "" && c.keyFile != "") {
39-
log.Fatal("Config parse error: both of TLS cert & key must be provided or neither (for testing )")
40-
return
41-
}
42-
43-
// support non-HTTPS for local testing
44-
if (c.certFile == "" && c.keyFile == "") && c.address == defaultHTTPSAddress {
45-
c.address = defaultHTTPAddress
46-
}
47-
4831
if c.debug {
4932
log.SetLevel(log.DebugLevel)
5033
}
@@ -54,62 +37,17 @@ func main() {
5437
var cfg = &config{}
5538
cfg.parse()
5639

57-
rgAdmitter := &admission.RouteGroupAdmitter{
58-
RouteGroupValidator: &definitions.RouteGroupValidator{
59-
EnableAdvancedValidation: false, // can't start advanced validation in the webhook binary
60-
},
61-
}
62-
ingressAdmitter := &admission.IngressAdmitter{
63-
IngressValidator: &definitions.IngressV1Validator{
64-
EnableAdvancedValidation: false, // can't start advanced validation in the webhook binary
65-
},
66-
}
67-
handler := http.NewServeMux()
68-
handler.Handle("/routegroups", admission.Handler(rgAdmitter))
69-
handler.Handle("/ingresses", admission.Handler(ingressAdmitter))
70-
handler.Handle("/metrics", promhttp.Handler())
71-
handler.HandleFunc("/healthz", healthCheck)
72-
73-
// One can use generate_cert.go in https://golang.org/pkg/crypto/tls
74-
// to generate cert.pem and key.pem.
75-
serve(cfg, handler)
76-
}
77-
78-
func healthCheck(writer http.ResponseWriter, _ *http.Request) {
79-
writer.WriteHeader(http.StatusOK)
80-
if _, err := writer.Write([]byte("ok")); err != nil {
81-
log.Errorf("Failed to write health check: %v", err)
82-
}
83-
84-
}
85-
86-
func serve(cfg *config, handler http.Handler) {
87-
server := &http.Server{
88-
Addr: cfg.address,
89-
Handler: handler,
90-
ReadTimeout: 1 * time.Minute,
91-
ReadHeaderTimeout: 1 * time.Minute,
40+
skpOptions := skipper.Options{
41+
ValidationWebhookEnabled: true,
42+
ValidationWebhookCertFile: cfg.certFile,
43+
ValidationWebhookKeyFile: cfg.keyFile,
44+
ValidationWebhookAddress: cfg.address,
45+
EnableAdvancedValidation: false,
9246
}
9347

94-
log.Infof("Starting server on %s", cfg.address)
95-
96-
sig := make(chan os.Signal, 1)
97-
signal.Notify(sig, syscall.SIGTERM)
98-
go func() {
99-
<-sig
100-
log.Info("Shutting down...")
101-
server.Shutdown(context.Background())
102-
}()
103-
104-
var err error
105-
if cfg.certFile != "" && cfg.keyFile != "" {
106-
err = server.ListenAndServeTLS(cfg.certFile, cfg.keyFile)
107-
} else {
108-
// support non-HTTPS for local testing
109-
err = server.ListenAndServe()
48+
if err := skipper.Run(skpOptions); err != nil {
49+
log.Fatalf("Failed to start skipper binary in validation mode %v", err)
50+
return
11051
}
11152

112-
if err != nil && err != http.ErrServerClosed {
113-
log.Fatalf("Failed to listen: %v", err)
114-
}
11553
}

config/config.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
"github.com/zalando/skipper/otel"
2525
"github.com/zalando/skipper/proxy"
2626
"github.com/zalando/skipper/swarm"
27+
"github.com/zalando/skipper/validation"
2728
)
2829

2930
type Config struct {
@@ -543,7 +544,7 @@ func NewConfig() *Config {
543544
flag.BoolVar(&cfg.Oauth2GrantInsecure, "oauth2-grant-insecure", false, "omits Secure attribute of the token cookie and uses http scheme for callback url")
544545
flag.DurationVar(&cfg.WebhookTimeout, "webhook-timeout", 2*time.Second, "sets the webhook request timeout duration")
545546
flag.BoolVar(&cfg.ValidationWebhookEnabled, "validation-webhook-enabled", false, "enables validation webhook for incoming requests")
546-
flag.StringVar(&cfg.ValidationWebhookAddress, "validation-webhook-address", ":9000", "address of the validation webhook service")
547+
flag.StringVar(&cfg.ValidationWebhookAddress, "validation-webhook-address", validation.DefaultHTTPSAddress, "address of the validation webhook service")
547548
flag.StringVar(&cfg.ValidationWebhookCertFile, "validation-webhook-cert-file", "", "path to the certificate file for the validation webhook")
548549
flag.StringVar(&cfg.ValidationWebhookKeyFile, "validation-webhook-key-file", "", "path to the key file for the validation webhook")
549550
flag.BoolVar(&cfg.EnableAdvancedValidation, "enable-advanced-validation", false, "enables advanced validation logic for Kubernetes resources")

validation/validation.go

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,19 +19,27 @@ import (
1919
)
2020

2121
const (
22-
readTimeout = time.Minute
23-
readHeaderTimeout = time.Minute
22+
readTimeout = time.Minute
23+
readHeaderTimeout = time.Minute
24+
DefaultHTTPSAddress = ":9443"
25+
DefaultHTTPAddress = ":9080"
2426
)
2527

2628
// StartValidation launches the validation webhook server and keeps serving until the
2729
// returned listener encounters an unrecoverable error, or the process shuts down.
2830
func StartValidation(address, certFile, keyFile string, enableAdvancedValidation bool, filterRegistry filters.Registry, predicateSpecs []routing.PredicateSpec, mtr metrics.Metrics) error {
29-
if certFile == "" || keyFile == "" {
30-
err := errors.New("validation webhook requires TLS: cert file or key file not provided")
31+
32+
if (certFile != "" || keyFile != "") && !(certFile != "" && keyFile != "") {
33+
err := errors.New("config parse error: both of TLS cert & key must be provided or neither (for testing)")
3134
log.Fatal(err)
3235
return err
3336
}
3437

38+
// support non-HTTPS for local testing
39+
if (certFile == "" && keyFile == "") && address != DefaultHTTPAddress {
40+
address = DefaultHTTPAddress
41+
}
42+
3543
handler := newValidationHandler(enableAdvancedValidation, filterRegistry, predicateSpecs, mtr)
3644

3745
server := &http.Server{
@@ -53,8 +61,13 @@ func StartValidation(address, certFile, keyFile string, enableAdvancedValidation
5361
return
5462
}
5563
}()
56-
57-
err := server.ListenAndServeTLS(certFile, keyFile)
64+
var err error
65+
if certFile != "" && keyFile != "" {
66+
err = server.ListenAndServeTLS(certFile, keyFile)
67+
} else {
68+
// support non-HTTPS for local testing
69+
err = server.ListenAndServe()
70+
}
5871

5972
if err != nil && !errors.Is(err, http.ErrServerClosed) {
6073
log.Fatalf("Failed to listen: %v", err)

0 commit comments

Comments
 (0)