From 57727d30b62a4eb4718896aae3e89011e9e0e701 Mon Sep 17 00:00:00 2001 From: gunishmatta Date: Mon, 15 Aug 2022 05:28:56 +0000 Subject: [PATCH] final changes - add flag to enable/disable http parent 921ebc02f53da104c5fe87826302b935e53c9779 author gunishmatta 1660541336 +0000 committer gunishmatta 1668423536 +0000 added flag to disable http Signed-off-by: gunishmatta added flag Signed-off-by: gunishmatta revert mistakenly pushed binaries Signed-off-by: gunishmatta PR changes Signed-off-by: gunishmatta Update Kubernetes packages to v1.25.0 Signed-off-by: Stefan Prodan Fix context cancel defer Signed-off-by: Philip Laine Release v0.25.2 Signed-off-by: Stefan Prodan update to new doc links structure Signed-off-by: Daniel Holbach Add .spec.timeout to Provider Signed-off-by: Somtochi Onyekwere Update pkg and controller-runtime Signed-off-by: Somtochi Onyekwere fuzz: Ensure latest base images are used Latest base image should contain Go 1.18, removing the need of updating that ourselves, apart from benefiting from latest changes upstream. Signed-off-by: Paulo Gomes fuzz: Reuse go cache from host Signed-off-by: Paulo Gomes fuzz: Use Go 1.18 on CI and fix cache path Signed-off-by: Paulo Gomes fuzz: Refactor Fuzzers based on Go native fuzzing The existing fuzzers were converted into the Go native format. Based on how the code was structured on this project, the fuzzers can be quite effective, allowing for entire E2E fuzzing in some cases, but with very low execution cost. Signed-off-by: Paulo Gomes Add finalizers to all the CRDs Signed-off-by: Somtochi Onyekwere Release v0.26.0 Signed-off-by: Stefan Prodan api: add custom validation for v1.Duration types Signed-off-by: Stefan Prodan Fix table with git commit status providers Signed-off-by: Andrey Ivashchenko Update dependencies - k8s.io/* v0.25.2 - controller-runtime v0.13.0 - fluxcd/pkg/runtime v0.19.0 Signed-off-by: Stefan Prodan Update Go to 1.19 Signed-off-by: Stefan Prodan Dockerfile: Build with Go 1.19 Signed-off-by: Stefan Prodan Release v0.27.0 Signed-off-by: Stefan Prodan Add "generic-hmac" Provider This commit adds the "generic-hmac" Provider type for authenticating webhook requests coming from notification-controller. I extended the `Forwarder` notifier to accept an optional key used for generating the HMAC. If the key is nil or empty no HMAC header is generated and the forwarder behaves as before. If it is provided an `X-Signature` HTTP header is added to the request carrying the HMAC. I transformed the `TestForwarder_Post` test into a table-driven test so that we can use the same setup and testing code for testing HMAC and non-HMAC forwarder instances. Any existing `X-Signature` header value set through a `Provider.spec.secretRef` Secret's `header` field will be overwritten. closes #99 Signed-off-by: Max Jonas Werner Update dependencies Includes a fix for CVE-2022-32149 of `golang.org/x/text` Signed-off-by: Stefan Prodan Release v0.28.0 Signed-off-by: Stefan Prodan http scheme updates Signed-off-by: Gunish Matta <33680363+gunishmatta@users.noreply.github.com> improved tests Signed-off-by: Gunish Matta <33680363+gunishmatta@users.noreply.github.com> http scheme updates Signed-off-by: Gunish Matta <33680363+gunishmatta@users.noreply.github.com> Update controllers/event_handling_test.go Co-authored-by: Max Jonas Werner Signed-off-by: Gunish Matta <33680363+gunishmatta@users.noreply.github.com> Update controllers/event_handling_test.go Co-authored-by: Paulo Gomes Signed-off-by: Gunish Matta <33680363+gunishmatta@users.noreply.github.com> revert mistakenly pushed binaries Signed-off-by: gunishmatta Update controllers/event_handling_test.go Co-authored-by: Paulo Gomes Signed-off-by: Gunish Matta <33680363+gunishmatta@users.noreply.github.com> Signed-off-by: gunishmatta minor formatter changes Signed-off-by: gunishmatta --- controllers/event_handling_test.go | 70 +++++++++++++++++++++++++++++- internal/server/event_handlers.go | 17 ++++++++ internal/server/event_server.go | 4 +- main.go | 4 +- 4 files changed, 92 insertions(+), 3 deletions(-) diff --git a/controllers/event_handling_test.go b/controllers/event_handling_test.go index 8890b98cf..70826aa96 100644 --- a/controllers/event_handling_test.go +++ b/controllers/event_handling_test.go @@ -7,6 +7,7 @@ import ( "fmt" "net/http" "net/http/httptest" + "net/url" "testing" "time" @@ -52,7 +53,69 @@ func TestEventHandler(t *testing.T) { t.Fatalf("failed to create memory storage") } - eventServer := server.NewEventServer("127.0.0.1:56789", logf.Log, k8sClient, true) + httpScheme := "http" + + eventServerTests := []struct { + name string + isHttpEnabled bool + url string + }{ + { + name: "http scheme is enabled", + isHttpEnabled: true, + }, { + name: "http scheme is disabled", + isHttpEnabled: false, + }, + } + for _, eventServerTest := range eventServerTests { + t.Run(eventServerTest.name, func(t *testing.T) { + + eventServer := server.NewEventServer("127.0.0.1:56789", logf.Log, k8sClient, true, eventServerTest.isHttpEnabled) + + stopCh := make(chan struct{}) + go eventServer.ListenAndServe(stopCh, eventMdlw, store) + requestsReceived := 0 + rcvServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + requestsReceived = requestsReceived + 1 + req = r + w.WriteHeader(200) + })) + defer rcvServer.Close() + defer close(stopCh) + + providerKey := types.NamespacedName{ + Name: fmt.Sprintf("provider-%s", randStringRunes(5)), + Namespace: namespace, + } + provider = ¬ifyv1.Provider{ + ObjectMeta: metav1.ObjectMeta{ + Name: providerKey.Name, + Namespace: providerKey.Namespace, + }, + Spec: notifyv1.ProviderSpec{ + Type: "generic", + Address: rcvServer.URL, + }, + } + + webhook_url, err := url.Parse(provider.Spec.Address) + + g.Expect(err).ToNot(HaveOccurred()) + + if eventServerTest.isHttpEnabled { + g.Expect(webhook_url.Scheme).To(Equal(httpScheme)) + g.Expect(requestsReceived).To(Equal(1)) + } else { + g.Expect(webhook_url.Scheme).ToNot(Equal(httpScheme)) + g.Expect(requestsReceived).To(Equal(0)) + } + + }) + } + + eventServer := server.NewEventServer("127.0.0.1:56789", logf.Log, k8sClient, true, true) + stopCh := make(chan struct{}) go eventServer.ListenAndServe(stopCh, eventMdlw, store) @@ -77,6 +140,9 @@ func TestEventHandler(t *testing.T) { Address: rcvServer.URL, }, } + + g.Expect(err).ToNot(HaveOccurred()) + g.Expect(k8sClient.Create(context.Background(), provider)).To(Succeed()) g.Eventually(func() bool { var obj notifyv1.Provider @@ -173,6 +239,7 @@ func TestEventHandler(t *testing.T) { res, err := http.Post("http://localhost:56789/", "application/json", buf) g.Expect(err).ToNot(HaveOccurred()) g.Expect(res.StatusCode).To(Equal(202)) // event_server responds with 202 Accepted + } testForwarded := func() { @@ -294,4 +361,5 @@ func TestEventHandler(t *testing.T) { req = nil }) } + } diff --git a/internal/server/event_handlers.go b/internal/server/event_handlers.go index 3f94c77d0..cbf0ea768 100644 --- a/internal/server/event_handlers.go +++ b/internal/server/event_handlers.go @@ -24,6 +24,7 @@ import ( "fmt" "io" "net/http" + "net/url" "regexp" "strings" "time" @@ -243,6 +244,22 @@ func (s *EventServer) handleEvent() func(w http.ResponseWriter, r *http.Request) continue } + webhookUrl, err := url.Parse(webhook) + if err != nil { + s.logger.Error(nil, "Error parsing webhook url", + "reconciler kind", v1beta1.ProviderKind, + "name", providerName.Name, + "namespace", providerName.Namespace) + continue + } + + if !s.supportHttpScheme && webhookUrl.Scheme == "http" { + s.logger.Error(nil, "http scheme is blocked", + "reconciler kind", v1beta1.ProviderKind, + "name", providerName.Name, + "namespace", providerName.Namespace) + continue + } factory := notifier.NewFactory(webhook, proxy, username, provider.Spec.Channel, token, headers, certPool, password) sender, err := factory.Notifier(provider.Spec.Type) if err != nil { diff --git a/internal/server/event_server.go b/internal/server/event_server.go index 96f0ea54b..bfeae7df5 100644 --- a/internal/server/event_server.go +++ b/internal/server/event_server.go @@ -44,15 +44,17 @@ type EventServer struct { logger logr.Logger kubeClient client.Client noCrossNamespaceRefs bool + supportHttpScheme bool } // NewEventServer returns an HTTP server that handles events -func NewEventServer(port string, logger logr.Logger, kubeClient client.Client, noCrossNamespaceRefs bool) *EventServer { +func NewEventServer(port string, logger logr.Logger, kubeClient client.Client, noCrossNamespaceRefs bool, supportHttpScheme bool) *EventServer { return &EventServer{ port: port, logger: logger.WithName("event-server"), kubeClient: kubeClient, noCrossNamespaceRefs: noCrossNamespaceRefs, + supportHttpScheme: supportHttpScheme, } } diff --git a/main.go b/main.go index 666309416..7db5c5f56 100644 --- a/main.go +++ b/main.go @@ -72,6 +72,7 @@ func main() { leaderElectionOptions leaderelection.Options aclOptions acl.Options rateLimiterOptions helper.RateLimiterOptions + insecureAllowHTTP bool ) flag.StringVar(&metricsAddr, "metrics-addr", ":8080", "The address the metric endpoint binds to.") @@ -82,6 +83,7 @@ func main() { flag.BoolVar(&watchAllNamespaces, "watch-all-namespaces", true, "Watch for custom resources in all namespaces, if set to false it will only watch the runtime namespace.") flag.DurationVar(&rateLimitInterval, "rate-limit-interval", 5*time.Minute, "Interval in which rate limit has effect.") + flag.BoolVar(&insecureAllowHTTP, "insecure-allow-http", true, "Enable the use of HTTP Scheme (no HTTPS) across all controller level objects. This is not recommended for production environments") clientOptions.BindFlags(flag.CommandLine) logOptions.BindFlags(flag.CommandLine) leaderElectionOptions.BindFlags(flag.CommandLine) @@ -169,7 +171,7 @@ func main() { Registry: crtlmetrics.Registry, }), }) - eventServer := server.NewEventServer(eventsAddr, log, mgr.GetClient(), aclOptions.NoCrossNamespaceRefs) + eventServer := server.NewEventServer(eventsAddr, log, mgr.GetClient(), aclOptions.NoCrossNamespaceRefs, insecureAllowHTTP) go eventServer.ListenAndServe(ctx.Done(), eventMdlw, store) setupLog.Info("starting webhook receiver server", "addr", receiverAddr)