Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add disableTls option for webhooks request #1709

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions artifacts/flagger/crd.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1135,6 +1135,9 @@ spec:
retries:
description: Number of retries for this webhook
type: number
disableTls:
description: Disable TLS verification for this webhook
type: boolean
metadata:
description: Metadata (key-value pairs) for this webhook
type: object
Expand Down
3 changes: 3 additions & 0 deletions charts/flagger/crds/crd.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1135,6 +1135,9 @@ spec:
retries:
description: Number of retries for this webhook
type: number
disableTls:
description: Disable TLS verification for this webhook
type: boolean
metadata:
description: Metadata (key-value pairs) for this webhook
type: object
Expand Down
5 changes: 4 additions & 1 deletion docs/gitbook/usage/webhooks.md
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,10 @@ Event payload (HTTP POST):
The event receiver can create alerts based on the received phase
(possible values: `Initialized`, `Waiting`, `Progressing`, `Promoting`, `Finalising`, `Succeeded` or `Failed`).

The webhook request can be retried by specifying a positive integer in the `retries` field.
Options:
* retries: The webhook request can be retried by specifying a positive integer in the `retries` field. This helps ensure reliability if the webhook fails due to transient network issues.

* disableTls: Set `disableTls` to `true` in the webhook spec to bypass TLS verification. This is useful in cases where the target service uses self-signed certificates, or you need to connect to an insecure service for testing purposes.

## Load Testing

Expand Down
3 changes: 3 additions & 0 deletions kustomize/base/flagger/crd.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1135,6 +1135,9 @@ spec:
retries:
description: Number of retries for this webhook
type: number
disableTls:
description: Disable TLS verification for this webhook
type: boolean
metadata:
description: Metadata (key-value pairs) for this webhook
type: object
Expand Down
4 changes: 4 additions & 0 deletions pkg/apis/flagger/v1beta1/canary.go
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,10 @@ type CanaryWebhook struct {
// Number of retries for this webhook
// +optional
Retries int `json:"retries,omitempty"`

// Disable TLS verification for this webhook
// +optional
DisableTls bool `json:"disableTls,omitempty"`
}

// CanaryWebhookPayload holds the deployment info and metadata sent to webhooks
Expand Down
42 changes: 27 additions & 15 deletions pkg/controller/webhook.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@ package controller

import (
"bytes"
"crypto/tls"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"net/url"
"strconv"
"time"
Expand All @@ -32,28 +34,32 @@ import (
"github.com/fluxcd/flagger/pkg/canary"
)

func callWebhook(webhook string, payload interface{}, timeout string, retries int) error {
payloadBin, err := json.Marshal(payload)
if err != nil {
return err
func newHTTPClient(retries int, timeout time.Duration, disableTls bool) *retryablehttp.Client {
httpClient := retryablehttp.NewClient()
httpClient.RetryMax = retries
httpClient.Logger = nil
httpClient.HTTPClient.Timeout = timeout

if disableTls {
httpClient.HTTPClient.Transport = &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
}

hook, err := url.Parse(webhook)
return httpClient
}

func callWebhook(webhook string, payload interface{}, timeout string, retries int, disableTls bool) error {
payloadBin, err := json.Marshal(payload)
if err != nil {
return err
}

httpClient := retryablehttp.NewClient()
httpClient.RetryMax = retries
httpClient.Logger = nil

req, err := retryablehttp.NewRequest("POST", hook.String(), bytes.NewBuffer(payloadBin))
hook, err := url.Parse(webhook)
if err != nil {
return err
}

req.Header.Set("Content-Type", "application/json")

if timeout == "" {
timeout = "10s"
}
Expand All @@ -62,7 +68,13 @@ func callWebhook(webhook string, payload interface{}, timeout string, retries in
return err
}

httpClient.HTTPClient.Timeout = t
httpClient := newHTTPClient(retries, t, disableTls)

req, err := retryablehttp.NewRequest("POST", hook.String(), bytes.NewBuffer(payloadBin))
if err != nil {
return err
}
req.Header.Set("Content-Type", "application/json")

r, err := httpClient.Do(req)
if err != nil {
Expand Down Expand Up @@ -100,7 +112,7 @@ func CallWebhook(canary flaggerv1.Canary, phase flaggerv1.CanaryPhase, w flagger
w.Timeout = "10s"
}

return callWebhook(w.URL, payload, w.Timeout, w.Retries)
return callWebhook(w.URL, payload, w.Timeout, w.Retries, w.DisableTls)
}

func CallEventWebhook(r *flaggerv1.Canary, w flaggerv1.CanaryWebhook, message, eventtype string) error {
Expand All @@ -126,7 +138,7 @@ func CallEventWebhook(r *flaggerv1.Canary, w flaggerv1.CanaryWebhook, message, e
payload.Metadata[key] = value
}
}
return callWebhook(w.URL, payload, "5s", w.Retries)
return callWebhook(w.URL, payload, "5s", w.Retries, w.DisableTls)
}

func canaryChecksum(c flaggerv1.Canary) string {
Expand Down
19 changes: 19 additions & 0 deletions pkg/controller/webhook_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -289,3 +289,22 @@ func TestCallWebhook_Retries(t *testing.T) {
flaggerv1.CanaryPhaseProgressing, hook)
require.NoError(t, err)
}

func TestCallWebhook_DisableTLS(t *testing.T) {
ts := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusAccepted)
}))
defer ts.Close()
hook := flaggerv1.CanaryWebhook{
Name: "validation",
URL: ts.URL,
DisableTls: true,
}

err := CallWebhook(
flaggerv1.Canary{
ObjectMeta: metav1.ObjectMeta{
Name: "podinfo", Namespace: corev1.NamespaceDefault}},
flaggerv1.CanaryPhaseProgressing, hook)
require.NoError(t, err)
}