Setup EventListener
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:
- 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).
- Interceptor Validation: Use CEL interceptors for event validation.
- 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:
| Permission | Resource | Description |
|---|
| get, list, watch | configmaps | Read ConfigMaps |
| get, list, watch | secrets | Read Secrets |
| get, list, watch | serviceaccounts | Read ServiceAccounts |
| create, get, list, watch, patch, update | deployments | Manage Deployments |
| create, get, list, watch, patch, update | services | Manage Services |
| create, get, list, watch, patch, update | pods | Manage Pods |
| create, get, list, watch, patch, update | events | Manage Events |
| create | pipelineruns | Create PipelineRuns |
| create | taskruns | Create TaskRuns |
| get, list, watch | clustertriggerbindings | Read ClusterTriggerBindings |
| get, list, watch | triggerbindings | Read TriggerBindings |
| get, list, watch | clusterinterceptors | Read ClusterInterceptors |
| get, list, watch | interceptors | Read Interceptors |
| get, list, watch | triggers | Read Triggers |
| get, list, watch | triggertemplates | Read TriggerTemplates |
| get, list, watch | eventlisteners | Read 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:
| Scenario | Namespace Scope | ServiceAccount | Configuration Complexity | Use Case |
|---|
| Namespace-Level | Single namespace | triggers-default-sa (auto) | Simple | Single project/team |
| Project-Level | Multiple specified namespaces | Custom SA (cluster permissions) | Moderate | Multiple related projects |
| Global-Level | All namespaces (*) | Custom SA (cluster permissions) | Complex | Cluster-wide management |
Scale
In different planning scenarios, different configurations can be used to meet varying requirements.
| Scale | Trigger Count | Resource Settings |
|---|
| Small Scale | 2 (triggers) * 100 (namespaces) * 10 (pipelines) = 2,000 triggers/cluster | Moderate, more than two replicas |
| Medium Scale | 2 (triggers) * 1,000 (namespaces) * 10 (pipelines) = 20,000 triggers/cluster | Moderate, 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 Configuration | Protocol | Description |
|---|
| Official Domain and Certificate | https | Set up TLS certificates via ClusterIP + Ingress |
| Custom Domain and Certificate | https | Use 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. |
| NodePort | http | Set accessible addresses via NodePort + Cluster / Node IP |
Small Scale + HTTPS + ALB Ingress Configuration Example
Prerequisites
- The domain name is configured correctly, and corresponding certificates are in place.
- 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
-
Resource Limits:
- Set appropriate resource requests and limits for EventListener Pods.
- Adjust the number of replicas based on actual load.
-
Security:
- Use HTTPS and Webhook Secrets.
- Configure the least privilege ServiceAccount.
- Validate all incoming events using interceptors.
-
Availability:
- Expose services using LoadBalancer or Ingress.
- Configure appropriate health checks.
- Implement high-availability deployments.
-
Monitoring:
- Monitor EventListener logs.
- Set appropriate alert mechanisms.
- Track event processing performance.
Frequently Asked Questions
-
Events Not Triggering Pipeline
- Check interceptor configurations.
- Validate Webhook configuration.
- Review EventListener logs.
-
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.
-
Performance Issues
- Adjust resource limits.
- Optimize interceptor configurations.
- Consider horizontal scaling.
Reference Links