Skip to content

Commit

Permalink
Merge pull request #191 from NissesSenap/azureeventhub
Browse files Browse the repository at this point in the history
Add support for Azure EventHub provider
  • Loading branch information
Philip Laine authored May 6, 2021
2 parents 15d98c9 + 39596a2 commit 585fed3
Show file tree
Hide file tree
Showing 7 changed files with 329 additions and 19 deletions.
27 changes: 14 additions & 13 deletions api/v1beta1/provider_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ const (
// ProviderSpec defines the desired state of Provider
type ProviderSpec struct {
// Type of provider
// +kubebuilder:validation:Enum=slack;discord;msteams;rocket;generic;github;gitlab;bitbucket;azuredevops;googlechat;webex;sentry
// +kubebuilder:validation:Enum=slack;discord;msteams;rocket;generic;github;gitlab;bitbucket;azuredevops;googlechat;webex;sentry;azureeventhub;
// +required
Type string `json:"type"`

Expand Down Expand Up @@ -64,18 +64,19 @@ type ProviderSpec struct {
}

const (
GenericProvider string = "generic"
SlackProvider string = "slack"
DiscordProvider string = "discord"
MSTeamsProvider string = "msteams"
RocketProvider string = "rocket"
GitHubProvider string = "github"
GitLabProvider string = "gitlab"
BitbucketProvider string = "bitbucket"
AzureDevOpsProvider string = "azuredevops"
GoogleChatProvider string = "googlechat"
WebexProvider string = "webex"
SentryProvider string = "sentry"
GenericProvider string = "generic"
SlackProvider string = "slack"
DiscordProvider string = "discord"
MSTeamsProvider string = "msteams"
RocketProvider string = "rocket"
GitHubProvider string = "github"
GitLabProvider string = "gitlab"
BitbucketProvider string = "bitbucket"
AzureDevOpsProvider string = "azuredevops"
GoogleChatProvider string = "googlechat"
WebexProvider string = "webex"
SentryProvider string = "sentry"
AzureEventHubProvider string = "azureeventhub"
)

// ProviderStatus defines the observed state of Provider
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ spec:
- googlechat
- webex
- sentry
- azureeventhub
type: string
username:
description: Bot username for this provider
Expand Down
101 changes: 100 additions & 1 deletion docs/spec/v1beta1/provider.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ Notification providers:
* Google Chat
* Webex
* Sentry
* Azure Event Hub
* Generic webhook

Git commit status providers:
Expand Down Expand Up @@ -106,7 +107,7 @@ kubectl create secret generic webhook-url \

Note that the secret must contain an `address` field.

The provider type can be: `slack`, `msteams`, `rocket`, `discord`, `googlechat`, `webex`, `sentry`, `github`, `gitlab`, `bitbucket`, `azuredevops` or `generic`.
The provider type can be: `slack`, `msteams`, `rocket`, `discord`, `googlechat`, `webex`, `sentry`, `azureeventhub`, `github`, `gitlab`, `bitbucket`, `azuredevops` or `generic`.

When type `generic` is specified, the notification controller will post the
incoming [event](event.md) in JSON format to the webhook address.
Expand Down Expand Up @@ -222,3 +223,101 @@ SECRET_NAME=tls-certs
kubectl create secret generic $SECRET_NAME \
--from-file=caFile=ca.crt
```

### Azure Event Hub

The Azure Event Hub supports two authentication methods, [JWT](https://docs.microsoft.com/en-us/azure/event-hubs/authenticate-application) and [SAS](https://docs.microsoft.com/en-us/azure/event-hubs/authorize-access-shared-access-signature) based.

#### JWT based auth

In JWT we use 3 input values.

Channel, token and address. We perform the following translation to match we the data we need to communicate with Azure Event Hub.

* channel = Azure Event Hub namespace
* address = Azure Event Hub name
* token = JWT

```yaml
apiVersion: notification.toolkit.fluxcd.io/v1beta1
kind: Provider
metadata:
name: azureeventhub
spec:
type: azureeventhub
channel: fluxv2
secretRef:
name: webhook-url
---
apiVersion: v1
data:
address: Zmx1eHYy
token: QS12YWxpZC1KV1QtdG9rZW4=
kind: Secret
metadata:
name: webhook-url
namespace: default
type: Opaque
```
Notification controller doesn't take any responsibility for the JWT token to be updated.
You need to use a secondary tool to make sure that the token in the secret is renewed.
If you want to make a easy test assuming that you have setup a Azure Enterprise application and you called it event-hub you can follow most of the bellow commands.
You will need to provide the client_secret that you got when generating the Azure Enterprise Application.
```shell
export AZURE_CLIENT=$(az ad app list --filter "startswith(displayName,'event-hub')" --query '[].appId' |jq -r '.[0]')
export AZURE_SECRET='secret-client-secret-generated-at-creation'
export AZURE_TENANT=$(az account show -o tsv --query tenantId)

curl -X GET --data 'grant_type=client_credentials' --data "client_id=$AZURE_CLIENT" --data "client_secret=$AZURE_SECRET" --data 'resource=https://eventhubs.azure.net' -H 'Content-Type: application/x-www-form-urlencoded' https://login.microsoftonline.com/$AZURE_TENANT/oauth2/token |jq .access_token
```
Use the output you got from the curl and add it to your secret like bellow.
```shell
kubectl create secret generic webhook-url \
--from-literal=address="fluxv2" \
--from-literal=token='A-valid-JWT-token'
```

#### SAS based auth

In SAS we only use the `address`field in the secret.

```yaml
apiVersion: notification.toolkit.fluxcd.io/v1beta1
kind: Provider
metadata:
name: azureeventhub
spec:
type: azureeventhub
secretRef:
name: webhook-url
---
apiVersion: v1
data:
address: RW5kcG9pbnQ9c2I6Ly9mbHV4djIuc2VydmljZWJ1cy53aW5kb3dzLm5ldC87U2hhcmVkQWNjZXNzS2V5TmFtZT1Sb290TWFuYWdlU2hhcmVkQWNjZXNzS2V5O1NoYXJlZEFjY2Vzc0tleT15b3Vyc2Fza2V5Z2VuZWF0ZWRieWF6dXJlCg==
kind: Secret
metadata:
name: webhook-url
namespace: default
type: Opaque
```
Assuming that you have created Azure event hub and namespace you should be able to use a similar command to get your connection string.
This will give you the default Root SAS, it's NOT supposed to be used in production.
```shell
az eventhubs namespace authorization-rule keys list --resource-group <rg-name> --namespace-name <namespace-name> --name RootManageSharedAccessKey -o tsv --query primaryConnectionString
# The output should look something like this:
Endpoint=sb://fluxv2.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=yoursaskeygeneatedbyazure
```

To create the needed secret:

```shell
kubectl create secret generic webhook-url \
--from-literal=address="Endpoint=sb://fluxv2.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=yoursaskeygeneatedbyazure"
```
8 changes: 8 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,21 @@ go 1.15
replace github.com/fluxcd/notification-controller/api => ./api

require (
github.com/Azure/azure-amqp-common-go/v3 v3.1.0
github.com/Azure/azure-event-hubs-go/v3 v3.3.7
github.com/Azure/azure-sdk-for-go v53.4.0+incompatible // indirect
github.com/Azure/go-amqp v0.13.6 // indirect
github.com/fluxcd/notification-controller/api v0.13.0
github.com/fluxcd/pkg/apis/meta v0.9.0
github.com/fluxcd/pkg/runtime v0.11.0
github.com/getsentry/sentry-go v0.10.0
github.com/go-logr/logr v0.3.0
github.com/google/go-github/v32 v32.1.0
github.com/hashicorp/go-retryablehttp v0.6.8
github.com/jpillora/backoff v1.0.0 // indirect
github.com/ktrysmt/go-bitbucket v0.6.5
github.com/microsoft/azure-devops-go-api/azuredevops v1.0.0-b5
github.com/mitchellh/mapstructure v1.4.1 // indirect
github.com/onsi/ginkgo v1.14.1
github.com/onsi/gomega v1.10.2
github.com/sethvargo/go-limiter v0.6.0
Expand All @@ -22,6 +28,8 @@ require (
github.com/stretchr/testify v1.6.1
github.com/whilp/git-urls v1.0.0
github.com/xanzy/go-gitlab v0.38.2
golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b // indirect
golang.org/x/net v0.0.0-20210427231257-85d9c07bbe3a // indirect
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d
k8s.io/api v0.20.4
k8s.io/apimachinery v0.20.4
Expand Down
Loading

0 comments on commit 585fed3

Please sign in to comment.