/brigade-acr-gateway

A Brigade 2 compatible gateway for events originating from Azure Container Registry

Primary LanguageGoApache License 2.0Apache-2.0

Brigade ACR Gateway

build codecov Go Report Card

This is a work-in-progress Brigade 2 compatible gateway that receives events (webhooks) from Azure Container Registry and propagates them into Brigade 2's event bus.


Installation

Prerequisites:

  • A Kubernetes cluster:

    • For which you have the admin cluster role
    • That is already running Brigade 2
    • Capable of provisioning a public IP address for a service of type LoadBalancer. (This means you won't have much luck running the gateway locally in the likes of kind or minikube unless you're able and willing to mess with port forwarding settings on your router, which we won't be covering here.)
  • kubectl, helm (commands below require Helm 3.7.0+), and brig (the Brigade 2 CLI)

1. Create a Service Account for the Gateway

Note: To proceed beyond this point, you'll need to be logged into Brigade 2 as the "root" user (not recommended) or (preferably) as a user with the ADMIN role. Further discussion of this is beyond the scope of this documentation. Please refer to Brigade's own documentation.

Using Brigade 2's brig CLI, create a service account for the gateway to use:

$ brig service-account create \
    --id brigade-acr-gateway \
    --description brigade-acr-gateway

Make note of the token returned. This value will be used in another step. It is your only opportunity to access this value, as Brigade does not save it.

Authorize this service account to create new events:

$ brig role grant EVENT_CREATOR \
    --service-account brigade-acr-gateway \
    --source brigade.sh/acr

Note: The --source brigade.sh/acr option specifies that this service account can be used only to create events having a value of brigade.sh/acr in the event's source field. This is a security measure that prevents the gateway from using this token for impersonating other gateways.

2. Install the ACR Gateway

For now, we're using the GitHub Container Registry (which is an OCI registry) to host our Helm chart. Helm 3.7 has experimental support for OCI registries. In the event that the Helm 3.7 dependency proves troublesome for users, or in the event that this experimental feature goes away, or isn't working like we'd hope, we will revisit this choice before going GA.

First, be sure you are using Helm 3.7.0 or greater and enable experimental OCI support:

$ export HELM_EXPERIMENTAL_OCI=1

As this chart requires custom configuration as described above to function properly, we'll need to create a chart values file with said config.

Use the following command to extract the full set of configuration options into a file you can modify:

$ helm inspect values oci://ghcr.io/brigadecore/brigade-acr-gateway \
    --version v0.2.1 > ~/brigade-acr-gateway-values.yaml

Edit ~/brigade-acr-gateway-values.yaml, making the following changes:

  • host: Set this to the host name where you'd like the gateway to be accessible.

  • brigade.apiAddress: Address of the Brigade API server, beginning with https://

  • brigade.apiToken: Service account token from step 2

  • tokens: This field should define tokens that can be used by clients to send events (webhooks) to this gateway. Note that keys are completely ignored by the gateway and only the values (tokens) matter. The keys only serve as recognizable token identifiers for human operators.

Save your changes to ~/brigade-acr-gateway-values.yaml and use the following command to install the gateway using the above customizations:

$ helm install brigade-acr-gateway \
    oci://ghcr.io/brigadecore/brigade-acr-gateway \
    --version v0.2.1 \
    --create-namespace \
    --namespace brigade-acr-gateway \
    --values ~/brigade-acr-gateway-values.yaml

3. (RECOMMENDED) Create a DNS Entry

If you installed the gateway without enabling support for an ingress controller, this command should help you find the gateway's public IP address:

$ kubectl get svc brigade-acr-gateway \
    --namespace brigade-acr-gateway \
    --output jsonpath='{.status.loadBalancer.ingress[0].ip}'

If you overrode defaults and enabled support for an ingress controller, you probably know what you're doing well enough to track down the correct IP without our help. 😉

With this public IP in hand, edit your name servers and add an A record pointing your domain to the public IP.

4. Create Webhooks

In your browser, visit the Azure Portal and navigate to the Azure Container Registry for which you'd like to send webhooks to this gateway. From the Services section, select Webhooks and click Add.

Here, you can add webhooks for the entire registry or for specific repositories within the registry.

  • In the Webhook name field, add a meaningful name for the webhook.

  • If your registry is replicated across regions, select the applicable Location.

  • In the Service URI field, use a value of the form https://<DNS hostname or publicIP>/events.

  • In the Custom headers field, add Authorization: Bearer <token>, where <token> is any of the tokens that were specified in my-values.yaml at the time of gateway installation. This will enable authentication to this gateway.

  • In the Actions field, select the actions that should trigger a webhook. Note that chart_push and chart_delete are not supported by this gateway.

  • The Status field can be used to enable or disable the webhook. It is enabled by default.

  • The Scope field can be used to make this webhook be triggered only by the selected action (Actions field) on a specific repository within the registry. If Scope is left blank, selected actions on any repository within the registry will trigger the webhook.

  • Click Create

5. Add a Brigade Project

You can create any number of Brigade projects (or modify an existing one) to listen for events that were sent from an ACR repository to your gateway and, in turn, emitted into Brigade's event bus. You can subscribe to all event types emitted by the gateway, or just specific ones.

In the example project definition below, we subscribe to all events emitted by the gateway, provided they've originated from the fictitious example.azurecr.io ACR registry and the fictitious example-repo repository (see the registry qualifier and repo label).

apiVersion: brigade.sh/v2-beta
kind: Project
metadata:
  id: acr-demo
description: A project that demonstrates integration with ACR
spec:
  eventSubscriptions:
  - source: brigade.sh/acr
    types:
    - *
    qualifiers:
      registry: example.azurecr.io
    labels:
      repo: example-repo
  workerTemplate:
    defaultConfigFiles:
      brigade.js: |-
        const { events } = require("@brigadecore/brigadier");

        events.on("brigade.sh/acr", "push", () => {
          console.log("Someone pushed an image to example.azurecr.io/example-repo!");
        });

        events.process();

In the alternative example below, we subscribe only to push events:

apiVersion: brigade.sh/v2-beta
kind: Project
metadata:
  id: acr-demo
description: A project that demonstrates integration with ACR
spec:
  eventSubscriptions:
  - source: brigade.sh/acr
    types:
    - push
    qualifiers:
      registry: example.azurecr.io
    labels:
      repo: example-repo
  workerTemplate:
    defaultConfigFiles:
      brigade.js: |-
        const { events } = require("@brigadecore/brigadier");

        events.on("brigade.sh/acr", "push", () => {
          console.log("Someone pushed an image to example.azurecr.io/example-repo!");
        });

        events.process();

Assuming this file were named project.yaml, you can create the project like so:

$ brig project create --file project.yaml

Push an image to the ACR repo for which you configured webhooks to send an event (webhook) to your gateway. The gateway, in turn, will emit the event into Brigade's event bus. Brigade should initialize a worker (containerized event handler) for every project that has subscribed to the event, and the worker should execute the brigade.js script that was embedded in the example project definition.

List the events for the acr-demo project to confirm this:

$ brig event list --project acr-demo

Full coverage of brig commands is beyond the scope of this documentation, but at this point, additional brig commands can be applied to monitor the event's status and view logs produced in the course of handling the event.

Events Received and Emitted by this Gateway

A subset of events received by this gateway from ACR are, in turn, emitted into Brigade's event bus.

ACR supports the following events:

  • push
  • delete
  • chart_push
  • chart_delete

According to ACR documentation, push and delete are triggered when OCI images are, respectively, pushed to or deleted from a repository in ACR. Again, according to ACR documentation, chart_push and chart_delete are triggered when Helm charts are, respectively, pushed to or delete from a repository in ACR. However chart_push and chart_delete are only triggered when using the Azure CLI's az acr commands to push and delete charts from ACR and these commands are deprecated in favor of Helm 3's built in support. When pushing or deleting via helm commands, regular push and delete webhooks are triggered.

Moreover, chart_push and chart_delete webhook payloads lack critical information (namely the affected registry) that is present in the push and delete webhook payloads. This makes it impossible for this gateway to effectively qualify and label events emitted into Brigade in a manner that is compatible with Brigade's event subscription model.

Due to these constraints, only push and delete webhooks are supported.

All push and delete events emitted into Brigade's event bus will be qualified by the registry of origin (registry qualifier) and labeled with the repository of origin (repo label). Subscribers must match on the registry qualifier to receive events originating from a given registry and may optionally match on the repo label to narrow their subscription to only originating from a specific repository. Refer back to examples in previous sections to see this in action.

Examples Projects

See examples/ for complete Brigade projects that demonstrate various scenarios.

Contributing

The Brigade project accepts contributions via GitHub pull requests. The Contributing document outlines the process to help get your contribution accepted.

Support & Feedback

We have a slack channel! Kubernetes/#brigade Feel free to join for any support questions or feedback, we are happy to help. To report an issue or to request a feature open an issue here

Code of Conduct

Participation in the Brigade project is governed by the CNCF Code of Conduct.