Adds gcr notification webhook
Signed-off-by: Somtochi Onyekwere <somtochionyekwere@gmail.com>
This commit is contained in:
parent
9450a9a893
commit
07bca13213
|
|
@ -27,7 +27,7 @@ import (
|
||||||
type ReceiverSpec struct {
|
type ReceiverSpec struct {
|
||||||
// Type of webhook sender, used to determine
|
// Type of webhook sender, used to determine
|
||||||
// the validation procedure and payload deserialization.
|
// the validation procedure and payload deserialization.
|
||||||
// +kubebuilder:validation:Enum=generic;github;gitlab;bitbucket;harbor;dockerhub;quay
|
// +kubebuilder:validation:Enum=generic;github;gitlab;bitbucket;harbor;dockerhub;quay;gcr
|
||||||
// +required
|
// +required
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
|
|
||||||
|
|
@ -70,6 +70,7 @@ const (
|
||||||
HarborReceiver string = "harbor"
|
HarborReceiver string = "harbor"
|
||||||
DockerHubReceiver string = "dockerhub"
|
DockerHubReceiver string = "dockerhub"
|
||||||
QuayReceiver string = "quay"
|
QuayReceiver string = "quay"
|
||||||
|
GCRReceiver string = "gcr"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ReceiverReady(receiver Receiver, reason, message, url string) Receiver {
|
func ReceiverReady(receiver Receiver, reason, message, url string) Receiver {
|
||||||
|
|
|
||||||
|
|
@ -110,6 +110,7 @@ spec:
|
||||||
- harbor
|
- harbor
|
||||||
- dockerhub
|
- dockerhub
|
||||||
- quay
|
- quay
|
||||||
|
- gcr
|
||||||
type: string
|
type: string
|
||||||
required:
|
required:
|
||||||
- resources
|
- resources
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,7 @@ const (
|
||||||
HarborReceiver string = "harbor"
|
HarborReceiver string = "harbor"
|
||||||
DockerHubReceiver string = "dockerhub"
|
DockerHubReceiver string = "dockerhub"
|
||||||
QuayReceiver string = "quay"
|
QuayReceiver string = "quay"
|
||||||
|
GCRReceiver string = "gcr"
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -199,6 +200,23 @@ spec:
|
||||||
name: webapp
|
name: webapp
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### GCR receiver
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
apiVersion: notification.toolkit.fluxcd.io/v1beta1
|
||||||
|
kind: Receiver
|
||||||
|
metadata:
|
||||||
|
name: gcr-receiver
|
||||||
|
namespace: default
|
||||||
|
spec:
|
||||||
|
type: gcr
|
||||||
|
secretRef:
|
||||||
|
name: webhook-token
|
||||||
|
resources:
|
||||||
|
- kind: ImageRepository
|
||||||
|
name: webapp
|
||||||
|
```
|
||||||
|
|
||||||
### Generic receiver
|
### Generic receiver
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
|
|
|
||||||
|
|
@ -18,11 +18,13 @@ package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"encoding/base64"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1alpha1"
|
imagev1 "github.com/fluxcd/image-reflector-controller/api/v1alpha1"
|
||||||
"github.com/fluxcd/pkg/apis/meta"
|
"github.com/fluxcd/pkg/apis/meta"
|
||||||
|
|
@ -215,6 +217,54 @@ func (s *ReceiverServer) validate(ctx context.Context, receiver v1beta1.Receiver
|
||||||
fmt.Sprintf("handling event from %s for tag %s", p.Repository.URL, p.PushData.Tag),
|
fmt.Sprintf("handling event from %s for tag %s", p.Repository.URL, p.PushData.Tag),
|
||||||
"receiver", receiver.Name)
|
"receiver", receiver.Name)
|
||||||
return nil
|
return nil
|
||||||
|
case v1beta1.GCRReceiver:
|
||||||
|
const (
|
||||||
|
insert = "insert"
|
||||||
|
tokenIndex = len("Bearer ")
|
||||||
|
)
|
||||||
|
|
||||||
|
type data struct {
|
||||||
|
Action string `json:"action"`
|
||||||
|
Digest string `json:"digest"`
|
||||||
|
Tag string `json:"tag"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type payload struct {
|
||||||
|
Message struct {
|
||||||
|
Data string `json:"data"`
|
||||||
|
MessageID string `json:"messageId"`
|
||||||
|
PublishTime time.Time `json:"publishTime"`
|
||||||
|
Subscription string `json:"subscription"`
|
||||||
|
} `json:"message"`
|
||||||
|
}
|
||||||
|
|
||||||
|
err := authenticateGCRRequest(&http.Client{}, r.Header.Get("Authorization"), tokenIndex)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("cannot authenticate GCR request: %s", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var p payload
|
||||||
|
if err := json.NewDecoder(r.Body).Decode(&p); err != nil {
|
||||||
|
return fmt.Errorf("cannot decode GCR webhook payload")
|
||||||
|
}
|
||||||
|
|
||||||
|
raw, _ := base64.StdEncoding.DecodeString(p.Message.Data)
|
||||||
|
|
||||||
|
var d data
|
||||||
|
err = json.Unmarshal(raw, &d)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("cannot decode GCR webhook body")
|
||||||
|
}
|
||||||
|
|
||||||
|
if strings.ToLower(d.Action) != insert {
|
||||||
|
s.logger.Info("action is not an insert, moving on")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
s.logger.Info(
|
||||||
|
fmt.Sprintf("handling event from %s for tag %s", d.Digest, d.Tag),
|
||||||
|
"receiver", receiver.Name)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return fmt.Errorf("recevier type '%s' not supported", receiver.Spec.Type)
|
return fmt.Errorf("recevier type '%s' not supported", receiver.Spec.Type)
|
||||||
|
|
@ -307,3 +357,28 @@ func (s *ReceiverServer) annotate(ctx context.Context, resource v1beta1.CrossNam
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func authenticateGCRRequest(c *http.Client, bearer string, tokenIndex int) (err error) {
|
||||||
|
type auth struct {
|
||||||
|
Aud string `json:"aud"`
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(bearer) < tokenIndex {
|
||||||
|
return fmt.Errorf("Authorization header is missing or malformed: %v", bearer)
|
||||||
|
}
|
||||||
|
|
||||||
|
token := bearer[tokenIndex:]
|
||||||
|
url := fmt.Sprintf("https://oauth2.googleapis.com/tokeninfo?id_token=%s", token)
|
||||||
|
|
||||||
|
resp, err := c.Get(url)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("Cannot verify authenticity of payload: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var p auth
|
||||||
|
if err := json.NewDecoder(resp.Body).Decode(&p); err != nil {
|
||||||
|
return fmt.Errorf("Cannot decode auth payload: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue