Setup EventListener

TIP

For an in-depth understanding of EventListener concepts, architecture, and principles, please refer to the In-Depth Understanding of EventListener document.

TOC

Overview

EventListener is a core resource in Tekton Triggers, responsible for receiving and processing external events (such as Webhooks). When an external system triggers an event, the EventListener creates Kubernetes resources (such as PipelineRun) based on the configured triggers.

Key Features

EventListener has the following key features:

  • Event Listening: Provides an HTTP endpoint to receive Webhook events from external systems
  • Event Filtering: Validates and filters received events using interceptors
  • Resource Creation: Automatically creates Kubernetes resources based on trigger definitions
  • Extensibility: Supports custom interceptors and various event sources
  • Security: Built-in multiple security mechanisms such as Webhook validation

Configuration Instructions

Basic Structure

apiVersion: triggers.tekton.dev/v1beta1
kind: EventListener
metadata:
  name: eventlistener
spec:
  serviceAccountName: triggers-default-sa
  resources:
    kubernetesResource:
      serviceType: NodePort  # Service type
      servicePort: 80       # Service port
      spec:
        template:
          spec:
            containers:
              - resources:    # Resource limits
                  requests:
                    memory: "64Mi"
                    cpu: "250m"
                  limits:
                    memory: "128Mi"
                    cpu: "500m"
  triggers:                  # Trigger configuration
    - name: trigger-1       # Trigger name
      interceptors:         # Interceptor configuration
        - ref:
            name: "cel"
          params:
            - name: "filter"
              value: "header.match('X-GitHub-Event', 'pull_request')"
      bindings:            # Trigger bindings
        - ref: pipeline-binding
      template:            # Trigger template
        ref: pipeline-template

Main Field Descriptions

spec.resources.kubernetesResource

Used to configure the Kubernetes resources for the EventListener:

  • serviceType: Service type (NodePort/ClusterIP/LoadBalancer)
  • servicePort: Service port
  • spec: Pod template configuration

spec.triggers

Defines a set of trigger configurations:

  • name: Trigger name
  • interceptors: List of interceptor configurations
  • bindings: Trigger binding configurations
  • template: Trigger template configurations

Security Configurations

EventListener supports multiple security configurations:

  1. ServiceAccount:
    • Default ServiceAccount (triggers-default-sa): If spec.serviceAccountName is not specified, EventListener will automatically use the triggers-default-sa ServiceAccount in the namespace. This ServiceAccount is automatically granted the necessary namespace-scoped permissions required for EventListeners to handle triggers within the same namespace. The permissions are automatically bound to the namespace where the ServiceAccount exists.
    • Custom ServiceAccount: When you need to handle triggers across multiple namespaces (e.g., when namespaceSelector is configured), you must specify a custom ServiceAccount with cluster-scoped permissions. Ensure that the specified ServiceAccount is configured with the corresponding permissions (see Permission Guidelines below).
  2. Interceptor Validation: Use CEL interceptors for event validation.
  3. TLS: Supports configuring HTTPS certificates.

Permission Guidelines

Default ServiceAccount vs Custom ServiceAccount

  • Default ServiceAccount (triggers-default-sa): When spec.serviceAccountName is not specified, EventListener automatically uses the triggers-default-sa ServiceAccount in the namespace. This ServiceAccount is automatically granted the necessary namespace-scoped permissions required for EventListeners to handle triggers within the same namespace. The permissions are automatically bound to the namespace where the ServiceAccount exists, so you don't need to manually configure Role or RoleBinding.

  • Custom ServiceAccount with Cluster Permissions: When you configure namespaceSelector to listen to triggers from multiple namespaces (including '*' for all namespaces), you must specify a custom ServiceAccount with cluster-scoped permissions. The triggers-default-sa ServiceAccount only has namespace-scoped permissions and does not have the necessary cluster-scoped permissions to access resources across namespaces.

Required Permissions

To trigger pipeline and tasks properly, the ServiceAccount used by EventListener needs the following permissions:

PermissionResourceDescription
get, list, watchconfigmapsRead ConfigMaps
get, list, watchsecretsRead Secrets
get, list, watchserviceaccountsRead ServiceAccounts
create, get, list, watch, patch, updatedeploymentsManage Deployments
create, get, list, watch, patch, updateservicesManage Services
create, get, list, watch, patch, updatepodsManage Pods
create, get, list, watch, patch, updateeventsManage Events
createpipelinerunsCreate PipelineRuns
createtaskrunsCreate TaskRuns
get, list, watchclustertriggerbindingsRead ClusterTriggerBindings
get, list, watchtriggerbindingsRead TriggerBindings
get, list, watchclusterinterceptorsRead ClusterInterceptors
get, list, watchinterceptorsRead Interceptors
get, list, watchtriggersRead Triggers
get, list, watchtriggertemplatesRead TriggerTemplates
get, list, watcheventlistenersRead EventListeners

Referable ClusterRole:

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: eventlistener-role
rules:
- apiGroups: [""]
  resources: ["configmaps", "secrets", "serviceaccounts"]
  verbs: ["get", "list", "watch"]
- apiGroups: ["apps"]
  resources: ["deployments"]
  verbs: ["create", "get", "list", "watch", "patch", "update"]
- apiGroups: [""]
  resources: ["services", "pods", "events"]
  verbs: ["create", "get", "list", "watch", "patch", "update"]
- apiGroups: ["tekton.dev"]
  resources: ["pipelineruns", "taskruns"]
  verbs: ["create"]
- apiGroups: ["triggers.tekton.dev"]
  resources:
    - "clustertriggerbindings"
    - "triggerbindings"
    - "clusterinterceptors"
    - "interceptors"
    - "triggers"
    - "triggertemplates"
    - "eventlisteners"
  verbs: ["get", "list", "watch"]

User Guide

Deploying the EventListener needs to be planned according to the scale and the actual network situation of the environment, as described below on how to configure differently based on planning:

EventListener Trigger Configuration Scenarios

EventListener supports three different scenarios for configuring triggers, each suitable for different use cases:

1. Namespace-Level EventListener

A namespace-level EventListener binds to specific triggers within the same namespace by explicitly configuring the triggers field in the EventListener spec. This is the simplest scenario and is suitable for single-namespace deployments.

Use Cases and Recommendations:

  • Use Cases:

    • Independent deployment and management for a single project or team
    • Requires explicit resource isolation and permission control
    • Teams have in-depth understanding of EventListener configuration and need fine-grained control over each trigger
    • Different namespaces require different EventListener configurations or resource limits
    • High requirements for performance and fault isolation
  • Recommended For:

    • Experienced DevOps teams or scenarios requiring high customization
    • When different projects need different EventListener configurations, resource quotas, or security policies
    • Multi-tenant environments requiring complete isolation between tenants
    • When different namespaces need different replica counts, resource limits, or network policies

Example Configuration:

spec:
  # serviceAccountName is optional, defaults to triggers-default-sa
  triggers:
    - name: trigger-1
      bindings:
        - ref: gitlab-push
          kind: ClusterTriggerBinding
      template:
        ref: pipeline-template
    - name: trigger-2
      bindings:
        - ref: github-pullrequest
          kind: ClusterTriggerBinding
      template:
        ref: pipeline-template

2. Project-Level EventListener

A project-level EventListener uses namespaceSelector to bind to triggers across multiple specified namespaces. This is suitable for managing triggers across a set of related namespaces (e.g., a project or team).

Use Cases and Recommendations:

  • Use Cases:

    • Multiple related projects or namespaces need to share the same EventListener
    • Unified event handling at the project group or department level
    • Need to share resources across multiple namespaces without covering the entire cluster
    • Some performance isolation requirements, but can accept resource sharing within the project group
  • Recommended For:

    • Medium-sized teams or project groups that need unified trigger management across multiple related namespaces
    • When multiple projects use similar configurations and resource requirements, reducing operational costs
    • When centralized management of Webhook events for a group of related projects is needed
    • Teams with some understanding of EventListener who can configure and manage cross-namespace permissions

Example Configuration:

spec:
  serviceAccountName: eventlistener  # Custom SA with cluster permissions
  namespaceSelector:
    matchNames:
      - project-a
      - project-b
      - project-c

3. Global-Level EventListener

A global-level EventListener uses namespaceSelector with a wildcard ('*') to bind to triggers from all namespaces in the cluster. This is suitable for centralized event handling across the entire cluster.

Use Cases and Recommendations:

  • Use Cases:

    • Cluster-wide unified event processing and management
    • Users have no strict requirements for performance isolation and can accept resource sharing
    • One-time configuration enables all users to use it out-of-the-box without separate configuration in each namespace
    • Users don't need in-depth knowledge of EventListener, managed uniformly by the platform
    • Small to medium-sized clusters with relatively controllable event volumes
  • Recommended For:

    • Platform scenarios where platform administrators configure and manage uniformly
    • When cluster scale is small and all users need to use the same EventListener configuration
    • Simplifying user workflows and reducing learning costs and configuration complexity
    • Centralized operational management for unified monitoring and troubleshooting
    • Note: In large-scale clusters or high-concurrency scenarios, performance impact and fault isolation should be considered

Example Configuration:

spec:
  serviceAccountName: eventlistener  # Custom SA with cluster permissions
  namespaceSelector:
    matchNames:
      - '*'  # Wildcard for all namespaces

Comparison Table:

ScenarioNamespace ScopeServiceAccountConfiguration ComplexityUse Case
Namespace-LevelSingle namespacetriggers-default-sa (auto)SimpleSingle project/team
Project-LevelMultiple specified namespacesCustom SA (cluster permissions)ModerateMultiple related projects
Global-LevelAll namespaces (*)Custom SA (cluster permissions)ComplexCluster-wide management

Scale

In different planning scenarios, different configurations can be used to meet varying requirements.

ScaleTrigger CountResource Settings
Small Scale2 (triggers) * 100 (namespaces) * 10 (pipelines) = 2,000 triggers/clusterModerate, more than two replicas
Medium Scale2 (triggers) * 1,000 (namespaces) * 10 (pipelines) = 20,000 triggers/clusterModerate, more than two replicas, deploy different EventListeners by namespace

Network Configuration

Depending on the priority of the environment and the available network resources, different network configurations can be chosen.

Network ConfigurationProtocolDescription
Official Domain and CertificatehttpsSet up TLS certificates via ClusterIP + Ingress
Custom Domain and CertificatehttpsUse self-signed certificates for TLS. Note: There is a risk in the tool-side configuration, not all tools/platforms support skipping or ignoring TLS validation.
NodePorthttpSet accessible addresses via NodePort + Cluster / Node IP

Small Scale + HTTPS + ALB Ingress Configuration Example

Prerequisites

  1. The domain name is configured correctly, and corresponding certificates are in place.
  2. ALB is deployed and configured properly.

Configuration Example

Create Namespace (Optional)

Ensure there is a Namespace for easy management of EventListener and other permissions; here we use tekton-webhooks as an example.

kubectl create namespace tekton-webhooks

Create ClusterRole and ServiceAccount and Set Permissions

  • Default ServiceAccount (triggers-default-sa): When spec.serviceAccountName is not specified, EventListener automatically uses the triggers-default-sa ServiceAccount in the namespace. This ServiceAccount is automatically granted the necessary namespace-scoped permissions required for EventListeners to handle triggers within the same namespace. The permissions are automatically bound to the namespace where the ServiceAccount exists, so you don't need to manually configure Role or RoleBinding.

  • Custom ServiceAccount with Cluster Permissions: When you configure namespaceSelector to listen to triggers from multiple namespaces (including '*' for all namespaces), you must specify a custom ServiceAccount with cluster-scoped permissions. The triggers-default-sa ServiceAccount only has namespace-scoped permissions and does not have the necessary cluster-scoped permissions to access resources across namespaces.

WARNING

Required for namespaceSelector: The following steps are only required when using namespaceSelector to listen to triggers across multiple namespaces. If your EventListener only handles triggers within the same namespace, you can skip these steps and use the default triggers-default-sa ServiceAccount, which will automatically have the required permissions.

The following YAML is for eventlistener-role.yaml.

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: eventlistener-role
rules:
- apiGroups: [""]
  resources: ["configmaps", "secrets", "serviceaccounts"]
  verbs: ["get", "list", "watch"]
- apiGroups: ["apps"]
  resources: ["deployments"]
  verbs: ["create", "get", "list", "watch", "patch", "update"]
- apiGroups: [""]
  resources: ["services", "pods", "events"]
  verbs: ["create", "get", "list", "watch", "patch", "update"]
- apiGroups: ["tekton.dev"]
  resources: ["pipelineruns", "taskruns"]
  verbs: ["create"]
- apiGroups: ["triggers.tekton.dev"]
  resources:
    - "clustertriggerbindings"
    - "triggerbindings"
    - "clusterinterceptors"
    - "interceptors"
    - "triggers"
    - "triggertemplates"
    - "eventlisteners"
  verbs: ["get", "list", "watch"]
kubectl apply -f eventlistener-role.yaml

Create a binding using the ClusterRole and ServiceAccount above.

kubectl -n tekton-webhooks create serviceaccount eventlistener
kubectl create clusterrolebinding tekton-webhooks:eventlistener:eventlistener-role --clusterrole=eventlistener-role --serviceaccount=tekton-webhooks:eventlistener

Create EventListener

Save the following YAML as eventlistener.yaml.

INFO

ServiceAccount Selection:

  • If you only need to handle triggers within the same namespace, you can omit spec.serviceAccountName to use the default triggers-default-sa ServiceAccount, which will automatically have the required namespace-scoped permissions.
  • Since this example uses namespaceSelector with '*' to listen to triggers from all namespaces, a custom ServiceAccount with cluster-scoped permissions is required. Therefore, serviceAccountName: "eventlistener" is specified here.
apiVersion: triggers.tekton.dev/v1beta1
kind: EventListener
metadata:
  name: eventlistener
  namespace: tekton-webhooks
  labels:
    el.tekton.dev/namespaces: all
    el.tekton.dev/size: small
spec:
  serviceAccountName: "eventlistener" # Required: Custom SA with cluster permissions needed for namespaceSelector
  # Listen to triggers from all NS
  namespaceSelector:
    matchNames:
    - '*'
  # Declare Kubernetes resource, default is Deployment
  resources:
    kubernetesResource:
      serviceType: ClusterIP # ClusterIP service type
      servicePort: 80  # Service port (container port)
      replicas: 2 # Replicas
      spec: # Deployment spec
        template:
          metadata:
            labels:
              el.tekton.dev/namespaces: all
              el.tekton.dev/size: small
          spec: {}
kubectl apply -f eventlistener.yaml

Create Ingress and TLS Secrets

INFO

You need to set the <host> with the corresponding domain name and certificate information.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: eventlistener-ingress
  annotations:
    ### Note ALB does not require setting ingressClassName
    ## kubernetes.io/ingress.class: "nginx" ## Follow changes to the ingress class, and remember to add corresponding ingress annotations.
    ### The following configuration should be customized based on requirements:
    alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS":443}, {"HTTP":80}]'
    alb.ingress.kubernetes.io/scheme: internet-facing
    alb.ingress.kubernetes.io/target-type: ip
spec:
  ### Note ALB does not require setting ingressClassName
  ## ingressClassName: alb ## Change according to the required ingress class
  tls:
  - hosts:
    - <host> # Domain name setting
    secretName: <tls secret> # Name of the secret containing TLS certificate
  rules:
  - host: <host> # Domain name setting
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: el-eventlistener 
            port:
              number: 80

Validate Webhook Configuration

You can test whether the configuration is normal using the following curl.

curl -k -X POST -H 'Content-Type: application/json' -d '{"hello": "world"}' <host>

## The following is the expected return format:
$> {
  "eventListener": "eventlistener",
  "namespace": "tekton-webhooks",
  "eventListenerUID": "8a7edab2-b426-453a-9f92-xxxxxx",
  "eventID": "aefd3b5b-2b19-4a14-b411-xxxxxxx"
}

Best Practices

  1. Resource Limits:

    • Set appropriate resource requests and limits for EventListener Pods.
    • Adjust the number of replicas based on actual load.
  2. Security:

    • Use HTTPS and Webhook Secrets.
    • Configure the least privilege ServiceAccount.
    • Validate all incoming events using interceptors.
  3. Availability:

    • Expose services using LoadBalancer or Ingress.
    • Configure appropriate health checks.
    • Implement high-availability deployments.
  4. Monitoring:

    • Monitor EventListener logs.
    • Set appropriate alert mechanisms.
    • Track event processing performance.

Frequently Asked Questions

  1. Events Not Triggering Pipeline

    • Check interceptor configurations.
    • Validate Webhook configuration.
    • Review EventListener logs.
  2. Permission Issues

    • Confirm ServiceAccount permissions.
    • If using the default triggers-default-sa ServiceAccount, verify that it exists in the namespace and has been automatically granted the required permissions.
    • If using a custom ServiceAccount, check Role and RoleBinding configurations.
    • Verify namespace access permissions.
    • If using namespaceSelector to listen across namespaces, ensure you're using a custom ServiceAccount with cluster-scoped permissions. The triggers-default-sa ServiceAccount only has namespace-scoped permissions.
  3. Performance Issues

    • Adjust resource limits.
    • Optimize interceptor configurations.
    • Consider horizontal scaling.