Skip to content

Commit

Permalink
Feature require auth (#24)
Browse files Browse the repository at this point in the history
Co-authored-by: Yuzhou Liu <[email protected]>
  • Loading branch information
whwalter and yuzhouliu9 authored Feb 5, 2024
1 parent 01509c4 commit 23efc51
Show file tree
Hide file tree
Showing 6 changed files with 237 additions and 4 deletions.
8 changes: 8 additions & 0 deletions examples/testers/demo-secret.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
apiVersion: v1
data:
token: dGhpc2lzYW5leGFtcGxl
kind: Secret
metadata:
name: argoslower-examples
namespace: devops
type: Opaque
17 changes: 13 additions & 4 deletions examples/testers/es-github.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,17 @@ spec:
ports:
- port: 80
targetPort: 8080
webhook:
github:
example:
endpoint: /example
method: POST
port: "8080"
webhook:
endpoint: /example
method: POST
port: "8080"
repositories:
- owner: kanopy-platform
names:
- argoslower
webhookSecret:
name: argoslower-examples
key: token
optional: true
3 changes: 3 additions & 0 deletions examples/testers/es-jira.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,6 @@ spec:
endpoint: /example
method: POST
port: "8080"
authSecret:
name: argoslower-examples
key: token
4 changes: 4 additions & 0 deletions examples/testers/es-officeips.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,7 @@ spec:
endpoint: /example
method: POST
port: "8080"
authSecret:
name: argoslower-examples
key: token
optional: true
68 changes: 68 additions & 0 deletions internal/admission/eventsource/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package eventsource
import (
"context"
"encoding/json"
"errors"
"fmt"
"net/http"

Expand All @@ -11,6 +12,8 @@ import (
"sigs.k8s.io/controller-runtime/pkg/webhook"
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"

perrs "github.com/kanopy-platform/argoslower/pkg/errors"

common "github.com/argoproj/argo-events/pkg/apis/common"
esv1alpha1 "github.com/argoproj/argo-events/pkg/apis/eventsource/v1alpha1"
)
Expand Down Expand Up @@ -76,6 +79,11 @@ func (h *Handler) Handle(ctx context.Context, req admission.Request) admission.R
return admission.Denied(fmt.Sprintf("Namespace %s is not opted into the mesh. Please contact your cluster administrator and try again", out.Namespace))
}

err = ValidateEventSource(out)
if err != nil {
return admission.Denied(err.Error())
}

out.Spec.Template = setIstioLabel(out.Spec.Template)

bytes, err := json.Marshal(out)
Expand Down Expand Up @@ -110,3 +118,63 @@ func setIstioLabel(in *esv1alpha1.Template) *esv1alpha1.Template {
type MeshChecker interface {
OnMesh(namespace string) (bool, error)
}

func ValidateEventSource(es *esv1alpha1.EventSource) error {

if len(es.Spec.Webhook) == 0 && len(es.Spec.Github) == 0 {
return perrs.NewUnretryableError(fmt.Errorf("EventSource %s/%s has no supported webhook configuration", es.Namespace, es.Name))
}

if es.Spec.Webhook != nil {
var err error

for hook, spec := range es.Spec.Webhook {
e := validateWebhookEventSource(&spec)
if e != nil {
err = perrs.NewUnretryableError(errors.Join(err, fmt.Errorf("Webhook %s misconfigured: %w", hook, e)))
}
}

if err != nil {
return err
}
}

if es.Spec.Github != nil {
var err error

for hook, spec := range es.Spec.Github {
e := validateGithubEventSource(&spec)
if e != nil {
err = perrs.NewUnretryableError(errors.Join(err, fmt.Errorf("Github webhook %s misconfigured: %w", hook, e)))
}
}

if err != nil {
return err
}

}

return nil
}

func validateWebhookEventSource(spec *esv1alpha1.WebhookEventSource) error {
// This is Bearer token authentication provided by argo-events
if spec.AuthSecret == nil {
return perrs.NewUnretryableError(fmt.Errorf("Webhook EventSources require auth tokens. Ensure an authSecret secret selector configured."))
}

return nil
}

func validateGithubEventSource(spec *esv1alpha1.GithubEventSource) error {
// Github webhooks provide signed messages for validation of the message payload.
// verification is implemented by argo-events
// https://github.com/argoproj/argo-events/blob/e948d7337aec619dd48fb2a065126b025ed9281d/eventsources/sources/github/start.go#L383
if spec.WebhookSecret == nil {
return perrs.NewUnretryableError(fmt.Errorf("Github webhook EventSources require HMAC signing validation for ingress. Ensure a webhookSecret secret selector is provided."))
}

return nil
}
141 changes: 141 additions & 0 deletions internal/admission/eventsource/handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
admissionv1 "k8s.io/api/admission/v1"
corev1 "k8s.io/api/core/v1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
Expand Down Expand Up @@ -65,6 +66,11 @@ func TestEventSourceHandler(t *testing.T) {
},
},
Spec: esv1alpha1.EventSourceSpec{
Github: map[string]esv1alpha1.GithubEventSource{
"ghs": esv1alpha1.GithubEventSource{
WebhookSecret: &corev1.SecretKeySelector{},
},
},
Template: &esv1alpha1.Template{
Metadata: &common.Metadata{
Labels: map[string]string{
Expand All @@ -83,6 +89,13 @@ func TestEventSourceHandler(t *testing.T) {
eventsource.DefaultAnnotationKey: "false",
},
},
Spec: esv1alpha1.EventSourceSpec{
Github: map[string]esv1alpha1.GithubEventSource{
"ghs": esv1alpha1.GithubEventSource{
WebhookSecret: &corev1.SecretKeySelector{},
},
},
},
},
},
{
Expand Down Expand Up @@ -155,3 +168,131 @@ func TestEventSourceHandler(t *testing.T) {

}
}

func TestValidateEventSource(t *testing.T) {

tests := map[string]struct {
spec *esv1alpha1.EventSource
err bool
}{

"no sources": {
spec: &esv1alpha1.EventSource{
ObjectMeta: v1.ObjectMeta{
Name: "empty",
Namespace: "testing",
},
},
err: true,
},
"github no secret": {
spec: &esv1alpha1.EventSource{
ObjectMeta: v1.ObjectMeta{
Name: "nosecret",
Namespace: "testing",
},
Spec: esv1alpha1.EventSourceSpec{
Github: map[string]esv1alpha1.GithubEventSource{},
},
},
err: true,
},
"github secret": {
spec: &esv1alpha1.EventSource{
ObjectMeta: v1.ObjectMeta{
Name: "valid",
Namespace: "testing",
},
Spec: esv1alpha1.EventSourceSpec{
Github: map[string]esv1alpha1.GithubEventSource{
"ghs": esv1alpha1.GithubEventSource{
WebhookSecret: &corev1.SecretKeySelector{},
},
},
},
},
},
"github mixed": {
spec: &esv1alpha1.EventSource{
ObjectMeta: v1.ObjectMeta{
Name: "nosecret",
Namespace: "testing",
},
Spec: esv1alpha1.EventSourceSpec{
Github: map[string]esv1alpha1.GithubEventSource{
"ghs": esv1alpha1.GithubEventSource{
WebhookSecret: &corev1.SecretKeySelector{},
},
"nos": esv1alpha1.GithubEventSource{},
},
},
},
err: true,
},
"webhook no secret": {
spec: &esv1alpha1.EventSource{
ObjectMeta: v1.ObjectMeta{
Name: "nosecret",
Namespace: "testing",
},
Spec: esv1alpha1.EventSourceSpec{
Webhook: map[string]esv1alpha1.WebhookEventSource{
"nos": esv1alpha1.WebhookEventSource{
WebhookContext: esv1alpha1.WebhookContext{},
},
},
},
},
err: true,
},
"webhook valid": {
spec: &esv1alpha1.EventSource{
ObjectMeta: v1.ObjectMeta{
Name: "valid",
Namespace: "testing",
},
Spec: esv1alpha1.EventSourceSpec{
Webhook: map[string]esv1alpha1.WebhookEventSource{
"ws": esv1alpha1.WebhookEventSource{
WebhookContext: esv1alpha1.WebhookContext{
AuthSecret: &corev1.SecretKeySelector{},
},
},
},
},
},
},
"webhook mixed": {
spec: &esv1alpha1.EventSource{
ObjectMeta: v1.ObjectMeta{
Name: "nosecret",
Namespace: "testing",
},
Spec: esv1alpha1.EventSourceSpec{
Webhook: map[string]esv1alpha1.WebhookEventSource{
"ws": esv1alpha1.WebhookEventSource{
WebhookContext: esv1alpha1.WebhookContext{
AuthSecret: &corev1.SecretKeySelector{},
},
},
"nos": esv1alpha1.WebhookEventSource{
WebhookContext: esv1alpha1.WebhookContext{},
},
},
},
},
err: true,
},
}

for name, test := range tests {
e := eventsource.ValidateEventSource(test.spec)

if test.err {
assert.Error(t, e, name)
} else {
assert.NoError(t, e, name)
}
}

}

0 comments on commit 23efc51

Please sign in to comment.