Merge pull request #184 from fluxcd/feature/self-signed-certs

Add self signed cert to provider
This commit is contained in:
Stefan Prodan 2021-04-21 14:24:49 +03:00 committed by GitHub
commit 490c9550c9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
30 changed files with 291 additions and 58 deletions

View File

@ -56,6 +56,11 @@ type ProviderSpec struct {
// using "address" as data key
// +optional
SecretRef *meta.LocalObjectReference `json:"secretRef,omitempty"`
// CertSecretRef can be given the name of a secret containing
// a PEM-encoded CA certificate (`caFile`)
// +optional
CertSecretRef *meta.LocalObjectReference `json:"certSecretRef,omitempty"`
}
const (

View File

@ -215,6 +215,11 @@ func (in *ProviderSpec) DeepCopyInto(out *ProviderSpec) {
*out = new(meta.LocalObjectReference)
**out = **in
}
if in.CertSecretRef != nil {
in, out := &in.CertSecretRef, &out.CertSecretRef
*out = new(meta.LocalObjectReference)
**out = **in
}
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProviderSpec.

View File

@ -50,6 +50,16 @@ spec:
description: HTTP/S webhook address of this provider
pattern: ^(http|https)://
type: string
certSecretRef:
description: CertSecretRef can be given the name of a secret containing
a PEM-encoded CA certificate (`caFile`)
properties:
name:
description: Name of the referent
type: string
required:
- name
type: object
channel:
description: Alert channel for this provider
type: string

View File

@ -18,6 +18,7 @@ package controllers
import (
"context"
"crypto/x509"
"fmt"
"time"
@ -121,7 +122,28 @@ func (r *ProviderReconciler) validate(ctx context.Context, provider v1beta1.Prov
return fmt.Errorf("no address found in 'spec.address' nor in `spec.secretRef`")
}
factory := notifier.NewFactory(address, provider.Spec.Proxy, provider.Spec.Username, provider.Spec.Channel, token)
var certPool *x509.CertPool
if provider.Spec.CertSecretRef != nil {
var secret corev1.Secret
secretName := types.NamespacedName{Namespace: provider.Namespace, Name: provider.Spec.CertSecretRef.Name}
if err := r.Get(ctx, secretName, &secret); err != nil {
return fmt.Errorf("failed to read secret, error: %w", err)
}
caFile, ok := secret.Data["caFile"]
if !ok {
return fmt.Errorf("no caFile found in secret %s", provider.Spec.CertSecretRef.Name)
}
certPool = x509.NewCertPool()
ok = certPool.AppendCertsFromPEM(caFile)
if !ok {
return fmt.Errorf("could not append to cert pool: invalid CA found in %s", provider.Spec.CertSecretRef.Name)
}
}
factory := notifier.NewFactory(address, provider.Spec.Proxy, provider.Spec.Username, provider.Spec.Channel, token, certPool)
if _, err := factory.Notifier(provider.Spec.Type); err != nil {
return fmt.Errorf("failed to initialise provider, error: %w", err)
}

View File

@ -298,6 +298,21 @@ github.com/fluxcd/pkg/apis/meta.LocalObjectReference
using &ldquo;address&rdquo; as data key</p>
</td>
</tr>
<tr>
<td>
<code>certSecretRef</code><br>
<em>
<a href="https://godoc.org/github.com/fluxcd/pkg/apis/meta#LocalObjectReference">
github.com/fluxcd/pkg/apis/meta.LocalObjectReference
</a>
</em>
</td>
<td>
<em>(Optional)</em>
<p>CertSecretRef can be given the name of a secret containing
a PEM-encoded CA certificate (<code>caFile</code>)</p>
</td>
</tr>
</table>
</td>
</tr>
@ -761,6 +776,21 @@ github.com/fluxcd/pkg/apis/meta.LocalObjectReference
using &ldquo;address&rdquo; as data key</p>
</td>
</tr>
<tr>
<td>
<code>certSecretRef</code><br>
<em>
<a href="https://godoc.org/github.com/fluxcd/pkg/apis/meta#LocalObjectReference">
github.com/fluxcd/pkg/apis/meta.LocalObjectReference
</a>
</em>
</td>
<td>
<em>(Optional)</em>
<p>CertSecretRef can be given the name of a secret containing
a PEM-encoded CA certificate (<code>caFile</code>)</p>
</td>
</tr>
</tbody>
</table>
</div>

View File

@ -209,3 +209,16 @@ The body of the request looks like this:
```
The `involvedObject` key contains the object that triggered the event.
### Self signed certificates
The `certSecretRef` field names a secret with TLS certificate data. This is for the purpose
of enabling a provider to communicate with a server using a self signed cert.
To use the field create a secret, containing a CA file, in the same namespace and reference
it from the provider.
```shell
SECRET_NAME=tls-certs
kubectl create secret generic $SECRET_NAME \
--from-file=caFile=ca.crt
```

View File

@ -18,12 +18,15 @@ package notifier
import (
"context"
"crypto/tls"
"crypto/x509"
"errors"
"fmt"
"github.com/fluxcd/pkg/runtime/events"
"strings"
"time"
"github.com/fluxcd/pkg/runtime/events"
"github.com/microsoft/azure-devops-go-api/azuredevops"
"github.com/microsoft/azure-devops-go-api/azuredevops/git"
)
@ -38,7 +41,7 @@ type AzureDevOps struct {
}
// NewAzureDevOps creates and returns a new AzureDevOps notifier.
func NewAzureDevOps(addr string, token string) (*AzureDevOps, error) {
func NewAzureDevOps(addr string, token string, certPool *x509.CertPool) (*AzureDevOps, error) {
if len(token) == 0 {
return nil, errors.New("azure devops token cannot be empty")
}
@ -58,6 +61,11 @@ func NewAzureDevOps(addr string, token string) (*AzureDevOps, error) {
orgURL := fmt.Sprintf("%v/%v", host, org)
connection := azuredevops.NewPatConnection(orgURL, token)
if certPool != nil {
connection.TlsConfig = &tls.Config{
RootCAs: certPool,
}
}
client := connection.GetClientByUrl(orgURL)
gitClient := &git.ClientImpl{
Client: *client,

View File

@ -24,19 +24,19 @@ import (
)
func TestNewAzureDevOpsBasic(t *testing.T) {
a, err := NewAzureDevOps("https://dev.azure.com/foo/bar/_git/baz", "foo")
a, err := NewAzureDevOps("https://dev.azure.com/foo/bar/_git/baz", "foo", nil)
assert.Nil(t, err)
assert.Equal(t, a.Project, "bar")
assert.Equal(t, a.Repo, "baz")
}
func TestNewAzureDevOpsInvalidUrl(t *testing.T) {
_, err := NewAzureDevOps("https://dev.azure.com/foo/bar/baz", "foo")
_, err := NewAzureDevOps("https://dev.azure.com/foo/bar/baz", "foo", nil)
assert.NotNil(t, err)
}
func TestNewAzureDevOpsMissingToken(t *testing.T) {
_, err := NewAzureDevOps("https://dev.azure.com/foo/bar/baz", "")
_, err := NewAzureDevOps("https://dev.azure.com/foo/bar/baz", "", nil)
assert.NotNil(t, err)
}

View File

@ -17,8 +17,11 @@ limitations under the License.
package notifier
import (
"crypto/tls"
"crypto/x509"
"errors"
"fmt"
"net/http"
"strings"
"github.com/fluxcd/pkg/runtime/events"
@ -33,7 +36,7 @@ type Bitbucket struct {
}
// NewBitbucket creates and returns a new Bitbucket notifier.
func NewBitbucket(addr string, token string) (*Bitbucket, error) {
func NewBitbucket(addr string, token string, certPool *x509.CertPool) (*Bitbucket, error) {
if len(token) == 0 {
return nil, errors.New("bitbucket token cannot be empty")
}
@ -57,10 +60,21 @@ func NewBitbucket(addr string, token string) (*Bitbucket, error) {
owner := comp[0]
repo := comp[1]
client := bitbucket.NewBasicAuth(username, password)
if certPool != nil {
tr := &http.Transport{
TLSClientConfig: &tls.Config{
RootCAs: certPool,
},
}
hc := &http.Client{Transport: tr}
client.HttpClient = hc
}
return &Bitbucket{
Owner: owner,
Repo: repo,
Client: bitbucket.NewBasicAuth(username, password),
Client: client,
}, nil
}

View File

@ -23,18 +23,18 @@ import (
)
func TestNewBitbucketBasic(t *testing.T) {
b, err := NewBitbucket("https://bitbucket.org/foo/bar", "foo:bar")
b, err := NewBitbucket("https://bitbucket.org/foo/bar", "foo:bar", nil)
assert.Nil(t, err)
assert.Equal(t, b.Owner, "foo")
assert.Equal(t, b.Repo, "bar")
}
func TestNewBitbucketInvalidUrl(t *testing.T) {
_, err := NewBitbucket("https://bitbucket.org/foo/bar/baz", "foo:bar")
_, err := NewBitbucket("https://bitbucket.org/foo/bar/baz", "foo:bar", nil)
assert.NotNil(t, err)
}
func TestNewBitbucketInvalidToken(t *testing.T) {
_, err := NewBitbucket("https://bitbucket.org/foo/bar", "bar")
_, err := NewBitbucket("https://bitbucket.org/foo/bar", "bar", nil)
assert.NotNil(t, err)
}

View File

@ -17,6 +17,8 @@ limitations under the License.
package notifier
import (
"crypto/tls"
"crypto/x509"
"encoding/json"
"fmt"
"net"
@ -30,16 +32,30 @@ import (
type requestOptFunc func(*retryablehttp.Request)
func postMessage(address, proxy string, payload interface{}, reqOpts ...requestOptFunc) error {
func postMessage(address, proxy string, certPool *x509.CertPool, payload interface{}, reqOpts ...requestOptFunc) error {
httpClient := retryablehttp.NewClient()
if certPool != nil {
httpClient.HTTPClient.Transport = &http.Transport{
TLSClientConfig: &tls.Config{
RootCAs: certPool,
},
}
}
if proxy != "" {
proxyURL, err := url.Parse(proxy)
if err != nil {
return fmt.Errorf("unable to parse proxy URL '%s', error: %w", proxy, err)
}
var tlsConfig *tls.Config
if certPool != nil {
tlsConfig = &tls.Config{
RootCAs: certPool,
}
}
httpClient.HTTPClient.Transport = &http.Transport{
Proxy: http.ProxyURL(proxyURL),
Proxy: http.ProxyURL(proxyURL),
TLSClientConfig: tlsConfig,
DialContext: (&net.Dialer{
Timeout: 15 * time.Second,
KeepAlive: 30 * time.Second,

View File

@ -17,6 +17,7 @@ limitations under the License.
package notifier
import (
"crypto/x509"
"encoding/json"
"io/ioutil"
"net/http"
@ -42,7 +43,28 @@ func Test_postMessage(t *testing.T) {
require.Equal(t, "success", payload["status"])
}))
defer ts.Close()
err := postMessage(ts.URL, "", map[string]string{"status": "success"})
err := postMessage(ts.URL, "", nil, map[string]string{"status": "success"})
require.NoError(t, err)
}
func Test_postSelfSignedCert(t *testing.T) {
ts := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
b, err := ioutil.ReadAll(r.Body)
require.NoError(t, err)
var payload = make(map[string]string)
err = json.Unmarshal(b, &payload)
require.NoError(t, err)
require.Equal(t, "success", payload["status"])
}))
defer ts.Close()
cert, err := x509.ParseCertificate(ts.TLS.Certificates[0].Certificate[0])
require.NoError(t, err)
certpool := x509.NewCertPool()
certpool.AddCert(cert)
err = postMessage(ts.URL, "", certpool, map[string]string{"status": "success"})
require.NoError(t, err)
}

View File

@ -99,7 +99,7 @@ func (s *Discord) Post(event events.Event) error {
payload.Attachments = []SlackAttachment{a}
err := postMessage(s.URL, s.ProxyURL, payload)
err := postMessage(s.URL, s.ProxyURL, nil, payload)
if err != nil {
return fmt.Errorf("postMessage failed: %w", err)
}

View File

@ -17,6 +17,7 @@ limitations under the License.
package notifier
import (
"crypto/x509"
"fmt"
"github.com/fluxcd/notification-controller/api/v1beta1"
@ -28,15 +29,17 @@ type Factory struct {
Username string
Channel string
Token string
CertPool *x509.CertPool
}
func NewFactory(url string, proxy string, username string, channel string, token string) *Factory {
func NewFactory(url string, proxy string, username string, channel string, token string, certPool *x509.CertPool) *Factory {
return &Factory{
URL: url,
ProxyURL: proxy,
Channel: channel,
Username: username,
Token: token,
CertPool: certPool,
}
}
@ -49,29 +52,29 @@ func (f Factory) Notifier(provider string) (Interface, error) {
var err error
switch provider {
case v1beta1.GenericProvider:
n, err = NewForwarder(f.URL, f.ProxyURL)
n, err = NewForwarder(f.URL, f.ProxyURL, f.CertPool)
case v1beta1.SlackProvider:
n, err = NewSlack(f.URL, f.ProxyURL, f.Username, f.Channel)
case v1beta1.DiscordProvider:
n, err = NewDiscord(f.URL, f.ProxyURL, f.Username, f.Channel)
case v1beta1.RocketProvider:
n, err = NewRocket(f.URL, f.ProxyURL, f.Username, f.Channel)
n, err = NewRocket(f.URL, f.ProxyURL, f.CertPool, f.Username, f.Channel)
case v1beta1.MSTeamsProvider:
n, err = NewMSTeams(f.URL, f.ProxyURL)
case v1beta1.GitHubProvider:
n, err = NewGitHub(f.URL, f.Token)
n, err = NewGitHub(f.URL, f.Token, f.CertPool)
case v1beta1.GitLabProvider:
n, err = NewGitLab(f.URL, f.Token)
n, err = NewGitLab(f.URL, f.Token, f.CertPool)
case v1beta1.BitbucketProvider:
n, err = NewBitbucket(f.URL, f.Token)
n, err = NewBitbucket(f.URL, f.Token, f.CertPool)
case v1beta1.AzureDevOpsProvider:
n, err = NewAzureDevOps(f.URL, f.Token)
n, err = NewAzureDevOps(f.URL, f.Token, f.CertPool)
case v1beta1.GoogleChatProvider:
n, err = NewGoogleChat(f.URL, f.ProxyURL)
case v1beta1.WebexProvider:
n, err = NewWebex(f.URL, f.ProxyURL)
n, err = NewWebex(f.URL, f.ProxyURL, f.CertPool)
case v1beta1.SentryProvider:
n, err = NewSentry(f.URL)
n, err = NewSentry(f.CertPool, f.URL)
default:
err = fmt.Errorf("provider %s not supported", provider)
}

View File

@ -17,10 +17,12 @@ limitations under the License.
package notifier
import (
"crypto/x509"
"fmt"
"github.com/fluxcd/pkg/runtime/events"
"net/url"
"github.com/fluxcd/pkg/runtime/events"
"github.com/hashicorp/go-retryablehttp"
)
@ -33,9 +35,10 @@ const NotificationHeader = "gotk-component"
type Forwarder struct {
URL string
ProxyURL string
CertPool *x509.CertPool
}
func NewForwarder(hookURL string, proxyURL string) (*Forwarder, error) {
func NewForwarder(hookURL string, proxyURL string, certPool *x509.CertPool) (*Forwarder, error) {
if _, err := url.ParseRequestURI(hookURL); err != nil {
return nil, fmt.Errorf("invalid hook URL %s: %w", hookURL, err)
}
@ -47,7 +50,7 @@ func NewForwarder(hookURL string, proxyURL string) (*Forwarder, error) {
}
func (f *Forwarder) Post(event events.Event) error {
err := postMessage(f.URL, f.ProxyURL, event, func(req *retryablehttp.Request) {
err := postMessage(f.URL, f.ProxyURL, f.CertPool, event, func(req *retryablehttp.Request) {
req.Header.Set(NotificationHeader, event.ReportingController)
})

View File

@ -18,12 +18,13 @@ package notifier
import (
"encoding/json"
"github.com/fluxcd/pkg/runtime/events"
"io/ioutil"
"net/http"
"net/http/httptest"
"testing"
"github.com/fluxcd/pkg/runtime/events"
"github.com/stretchr/testify/require"
)
@ -41,7 +42,7 @@ func TestForwarder_Post(t *testing.T) {
}))
defer ts.Close()
forwarder, err := NewForwarder(ts.URL, "")
forwarder, err := NewForwarder(ts.URL, "", nil)
require.NoError(t, err)
err = forwarder.Post(testEvent())

View File

@ -18,13 +18,17 @@ package notifier
import (
"context"
"crypto/tls"
"crypto/x509"
"errors"
"fmt"
"github.com/fluxcd/pkg/runtime/events"
"net/http"
"net/url"
"strings"
"time"
"github.com/fluxcd/pkg/runtime/events"
"github.com/google/go-github/v32/github"
"golang.org/x/oauth2"
)
@ -35,7 +39,7 @@ type GitHub struct {
Client *github.Client
}
func NewGitHub(addr string, token string) (*GitHub, error) {
func NewGitHub(addr string, token string, certPool *x509.CertPool) (*GitHub, error) {
if len(token) == 0 {
return nil, errors.New("github token cannot be empty")
}
@ -59,6 +63,17 @@ func NewGitHub(addr string, token string) (*GitHub, error) {
tc := oauth2.NewClient(context.Background(), ts)
client := github.NewClient(tc)
if baseUrl.Host != "github.com" {
if certPool != nil {
tr := &http.Transport{
TLSClientConfig: &tls.Config{
RootCAs: certPool,
},
}
hc := &http.Client{Transport: tr}
ctx := context.WithValue(context.Background(), oauth2.HTTPClient, hc)
tc = oauth2.NewClient(ctx, ts)
}
client, err = github.NewEnterpriseClient(host, host, tc)
if err != nil {
return nil, fmt.Errorf("could not create enterprise GitHub client: %v", err)

View File

@ -24,7 +24,7 @@ import (
)
func TestNewGitHubBasic(t *testing.T) {
g, err := NewGitHub("https://github.com/foo/bar", "foobar")
g, err := NewGitHub("https://github.com/foo/bar", "foobar", nil)
assert.Nil(t, err)
assert.Equal(t, g.Owner, "foo")
assert.Equal(t, g.Repo, "bar")
@ -32,7 +32,7 @@ func TestNewGitHubBasic(t *testing.T) {
}
func TestNewEmterpriseGitHubBasic(t *testing.T) {
g, err := NewGitHub("https://foobar.com/foo/bar", "foobar")
g, err := NewGitHub("https://foobar.com/foo/bar", "foobar", nil)
assert.Nil(t, err)
assert.Equal(t, g.Owner, "foo")
assert.Equal(t, g.Repo, "bar")
@ -40,12 +40,12 @@ func TestNewEmterpriseGitHubBasic(t *testing.T) {
}
func TestNewGitHubInvalidUrl(t *testing.T) {
_, err := NewGitHub("https://github.com/foo/bar/baz", "foobar")
_, err := NewGitHub("https://github.com/foo/bar/baz", "foobar", nil)
assert.NotNil(t, err)
}
func TestNewGitHubEmptyToken(t *testing.T) {
_, err := NewGitHub("https://github.com/foo/bar", "")
_, err := NewGitHub("https://github.com/foo/bar", "", nil)
assert.NotNil(t, err)
}

View File

@ -17,7 +17,10 @@ limitations under the License.
package notifier
import (
"crypto/tls"
"crypto/x509"
"errors"
"net/http"
"github.com/fluxcd/pkg/runtime/events"
"github.com/xanzy/go-gitlab"
@ -28,7 +31,7 @@ type GitLab struct {
Client *gitlab.Client
}
func NewGitLab(addr string, token string) (*GitLab, error) {
func NewGitLab(addr string, token string, certPool *x509.CertPool) (*GitLab, error) {
if len(token) == 0 {
return nil, errors.New("gitlab token cannot be empty")
}
@ -38,8 +41,17 @@ func NewGitLab(addr string, token string) (*GitLab, error) {
return nil, err
}
opt := gitlab.WithBaseURL(host)
client, err := gitlab.NewClient(token, opt)
opts := []gitlab.ClientOptionFunc{gitlab.WithBaseURL(host)}
if certPool != nil {
tr := &http.Transport{
TLSClientConfig: &tls.Config{
RootCAs: certPool,
},
}
hc := &http.Client{Transport: tr}
opts = append(opts, gitlab.WithHTTPClient(hc))
}
client, err := gitlab.NewClient(token, opts...)
if err != nil {
return nil, err
}

View File

@ -23,25 +23,25 @@ import (
)
func TestNewGitLabBasic(t *testing.T) {
g, err := NewGitLab("https://gitlab.com/foo/bar", "foobar")
g, err := NewGitLab("https://gitlab.com/foo/bar", "foobar", nil)
assert.Nil(t, err)
assert.Equal(t, g.Id, "foo/bar")
}
func TestNewGitLabSubgroups(t *testing.T) {
g, err := NewGitLab("https://gitlab.com/foo/bar/baz", "foobar")
g, err := NewGitLab("https://gitlab.com/foo/bar/baz", "foobar", nil)
assert.Nil(t, err)
assert.Equal(t, g.Id, "foo/bar/baz")
}
func TestNewGitLabSelfHosted(t *testing.T) {
g, err := NewGitLab("https://example.com/foo/bar", "foo:bar")
g, err := NewGitLab("https://example.com/foo/bar", "foo:bar", nil)
assert.Nil(t, err)
assert.Equal(t, g.Id, "foo/bar")
assert.Equal(t, g.Client.BaseURL().Host, "example.com")
}
func TestNewGitLabEmptyToken(t *testing.T) {
_, err := NewGitLab("https://gitlab.com/foo/bar", "")
_, err := NewGitLab("https://gitlab.com/foo/bar", "", nil)
assert.NotNil(t, err)
}

View File

@ -141,7 +141,7 @@ func (s *GoogleChat) Post(event events.Event) error {
Cards: []GoogleChatCard{card},
}
err := postMessage(s.URL, s.ProxyURL, payload)
err := postMessage(s.URL, s.ProxyURL, nil, payload)
if err != nil {
return fmt.Errorf("postMessage failed: %w", err)
}

View File

@ -17,6 +17,7 @@ limitations under the License.
package notifier
import (
"crypto/x509"
"errors"
"fmt"
"net/url"
@ -31,10 +32,11 @@ type Rocket struct {
ProxyURL string
Username string
Channel string
CertPool *x509.CertPool
}
// NewRocket validates the Rocket URL and returns a Rocket object
func NewRocket(hookURL string, proxyURL string, username string, channel string) (*Rocket, error) {
func NewRocket(hookURL string, proxyURL string, certPool *x509.CertPool, username string, channel string) (*Rocket, error) {
_, err := url.ParseRequestURI(hookURL)
if err != nil {
return nil, fmt.Errorf("invalid Rocket hook URL %s", hookURL)
@ -53,6 +55,7 @@ func NewRocket(hookURL string, proxyURL string, username string, channel string)
URL: hookURL,
ProxyURL: proxyURL,
Username: username,
CertPool: certPool,
}, nil
}
@ -88,7 +91,7 @@ func (s *Rocket) Post(event events.Event) error {
payload.Attachments = []SlackAttachment{a}
err := postMessage(s.URL, s.ProxyURL, payload)
err := postMessage(s.URL, s.ProxyURL, s.CertPool, payload)
if err != nil {
return fmt.Errorf("postMessage failed: %w", err)
}

View File

@ -39,7 +39,7 @@ func TestRocket_Post(t *testing.T) {
}))
defer ts.Close()
rocket, err := NewRocket(ts.URL, "", "test", "test")
rocket, err := NewRocket(ts.URL, "", nil, "test", "test")
require.NoError(t, err)
err = rocket.Post(testEvent())

View File

@ -17,7 +17,11 @@ limitations under the License.
package notifier
import (
"crypto/tls"
"crypto/x509"
"fmt"
"net/http"
"github.com/fluxcd/pkg/runtime/events"
"github.com/getsentry/sentry-go"
)
@ -28,9 +32,18 @@ type Sentry struct {
}
// NewSentry creates a Sentry client from the provided Data Source Name (DSN)
func NewSentry(dsn string) (*Sentry, error) {
func NewSentry(certPool *x509.CertPool, dsn string) (*Sentry, error) {
var tr *http.Transport
if certPool != nil {
tr = &http.Transport{
TLSClientConfig: &tls.Config{
RootCAs: certPool,
},
}
}
client, err := sentry.NewClient(sentry.ClientOptions{
Dsn: dsn,
Dsn: dsn,
HTTPTransport: tr,
})
if err != nil {
return nil, err

View File

@ -17,19 +17,20 @@ limitations under the License.
package notifier
import (
"testing"
"time"
"github.com/fluxcd/pkg/runtime/events"
"github.com/getsentry/sentry-go"
"github.com/stretchr/testify/assert"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"testing"
"time"
"github.com/stretchr/testify/require"
)
func TestNewSentry(t *testing.T) {
s, err := NewSentry("https://test@localhost/1")
s, err := NewSentry(nil, "https://test@localhost/1")
require.NoError(t, err)
assert.Equal(t, s.Client.Options().Dsn, "https://test@localhost/1")
}

View File

@ -112,7 +112,7 @@ func (s *Slack) Post(event events.Event) error {
payload.Attachments = []SlackAttachment{a}
err := postMessage(s.URL, s.ProxyURL, payload)
err := postMessage(s.URL, s.ProxyURL, nil, payload)
if err != nil {
return fmt.Errorf("postMessage failed: %w", err)
}

View File

@ -98,7 +98,7 @@ func (s *MSTeams) Post(event events.Event) error {
payload.ThemeColor = "FF0000"
}
err := postMessage(s.URL, s.ProxyURL, payload)
err := postMessage(s.URL, s.ProxyURL, nil, payload)
if err != nil {
return fmt.Errorf("postMessage failed: %w", err)
}

View File

@ -17,6 +17,7 @@ limitations under the License.
package notifier
import (
"crypto/x509"
"fmt"
"net/url"
"strings"
@ -28,6 +29,7 @@ import (
type Webex struct {
URL string
ProxyURL string
CertPool *x509.CertPool
}
// WebexPayload holds the message text
@ -37,7 +39,7 @@ type WebexPayload struct {
}
// NewWebex validates the Webex URL and returns a Webex object
func NewWebex(hookURL, proxyURL string) (*Webex, error) {
func NewWebex(hookURL, proxyURL string, certPool *x509.CertPool) (*Webex, error) {
_, err := url.ParseRequestURI(hookURL)
if err != nil {
return nil, fmt.Errorf("invalid Webex hook URL %s", hookURL)
@ -71,7 +73,7 @@ func (s *Webex) Post(event events.Event) error {
Markdown: markdown,
}
if err := postMessage(s.URL, s.ProxyURL, payload); err != nil {
if err := postMessage(s.URL, s.ProxyURL, s.CertPool, payload); err != nil {
return fmt.Errorf("postMessage failed: %w", err)
}
return nil

View File

@ -39,7 +39,7 @@ func TestWebex_Post(t *testing.T) {
}))
defer ts.Close()
webex, err := NewWebex(ts.URL, "")
webex, err := NewWebex(ts.URL, "", nil)
require.NoError(t, err)
err = webex.Post(testEvent())
@ -47,7 +47,7 @@ func TestWebex_Post(t *testing.T) {
}
func TestWebex_PostUpdate(t *testing.T) {
webex, err := NewWebex("http://localhost", "")
webex, err := NewWebex("http://localhost", "", nil)
require.NoError(t, err)
event := testEvent()

View File

@ -18,6 +18,7 @@ package server
import (
"context"
"crypto/x509"
"encoding/json"
"fmt"
"io/ioutil"
@ -156,6 +157,40 @@ func (s *EventServer) handleEvent() func(w http.ResponseWriter, r *http.Request)
}
}
var certPool *x509.CertPool
if provider.Spec.CertSecretRef != nil {
var secret corev1.Secret
secretName := types.NamespacedName{Namespace: alert.Namespace, Name: provider.Spec.CertSecretRef.Name}
err = s.kubeClient.Get(ctx, secretName, &secret)
if err != nil {
s.logger.Error(err, "failed to read secret",
"reconciler kind", v1beta1.ProviderKind,
"name", providerName.Name,
"namespace", providerName.Namespace)
continue
}
caFile, ok := secret.Data["caFile"]
if !ok {
s.logger.Error(err, "failed to read secret key caFile",
"reconciler kind", v1beta1.ProviderKind,
"name", providerName.Name,
"namespace", providerName.Namespace)
continue
}
certPool = x509.NewCertPool()
ok = certPool.AppendCertsFromPEM(caFile)
if !ok {
s.logger.Error(err, "could not append to cert pool",
"reconciler kind", v1beta1.ProviderKind,
"name", providerName.Name,
"namespace", providerName.Namespace)
continue
}
}
if webhook == "" {
s.logger.Error(nil, "provider has no address",
"reconciler kind", v1beta1.ProviderKind,
@ -164,7 +199,7 @@ func (s *EventServer) handleEvent() func(w http.ResponseWriter, r *http.Request)
continue
}
factory := notifier.NewFactory(webhook, provider.Spec.Proxy, provider.Spec.Username, provider.Spec.Channel, token)
factory := notifier.NewFactory(webhook, provider.Spec.Proxy, provider.Spec.Username, provider.Spec.Channel, token, certPool)
sender, err := factory.Notifier(provider.Spec.Type)
if err != nil {
s.logger.Error(err, "failed to initialise provider",