Configure EventListener automatic exposure rules
TOC
What This Document Helps You DoFeature overviewConfiguration entry pointField referenceField Mapping to Ingress ResourcesRequest flow diagramConfiguration examplesExample 1: wildcard host with custom prefixExample 2: shared hostname and prefixExample 3: environment-specific rulesExample 4: team-scoped publishing with default prefixExample 5: multiple external endpoints and adjusted prefixExample 6: Configuring TLS/HTTPSOption A: Manual TLS with pre-created SecretOption B: Using cert-manager for automatic certificate managementOption C: Combined TLS and annotationsConfiguration workflowVerification and troubleshootingVerify ConfigMap contentVerify Ingress objectsCheck EventListener addressesInspect Trigger annotationsTroubleshooting tipsWhat This Document Helps You Do
This document helps you configure automatic external exposure of EventListeners through the automatic exposure feature. You will learn:
- How to configure export rules to automatically expose EventListeners via Ingress
- How to set up webhook URLs that will be displayed in the UI
- How to configure different exposure strategies for different namespaces or environments
- How to verify that EventListeners are properly exposed
When to use this: Use this feature when you want the system to automatically create Ingress resources for your EventListeners, eliminating the need to manually create and manage Ingress resources. This is especially useful in production environments where you need consistent webhook URL patterns.
Prerequisites: You should have cluster administrator privileges to configure TektonConfig resources, and you should have a basic understanding of Kubernetes Ingress and networking concepts.
Feature overview
The automatic exposure controller (internally named trigger-wrapper) reads the trigger-wrapper-config ConfigMap in the Tekton system namespace (default: tekton-pipelines). The export-rules defined in that ConfigMap determine which EventListeners should be exposed externally (Service, Ingress, etc.) and populate the EventListener/Trigger status with the generated endpoints.
Technical Note: The internal component name is trigger-wrapper, but you don't need to remember this. You only need to configure the export rules through TektonConfig, and the system will handle the rest automatically.
Configuration entry point
On Alauda Tekton, it is recommended to manage this configuration through the TektonConfig custom resource. Embed the rule definitions under spec.pipeline.options.configMaps.trigger-wrapper-config.data.config, for example:
The Operator synchronises this spec into the trigger-wrapper-config ConfigMap inside Tekton system namespace (default: tekton-pipelines). Once updated, the automatic exposure controller refreshes its cache and reconciles resources according to the new rules.
Note: The ConfigMap name trigger-wrapper-config is an internal technical name. You manage the configuration through TektonConfig as shown above, and don't need to directly interact with the ConfigMap.
Field reference
Each entry in export-rules represents a publishing strategy. Important fields:
-
name – rule name, also used when generating Service/Ingress names.
-
ingressClass (optional) – the Ingress controller to use, e.g.
nginx,traefik. -
host (optional) – hostname matched by the Ingress. Leave empty to accept all hosts. Important: When configuring a domain name, ensure DNS resolution is properly configured (or add to
/etc/hostsfor local testing). The domain must be resolvable from systems that will send webhooks. -
externalHosts (optional) – What it does: Defines the webhook URLs that will be displayed to users in the UI and populated in EventListener's
status.addressesfield.Think of it as: The "public address" that external systems (like GitHub, GitLab) will use to send webhooks to your EventListener.
How it works:
- The controller combines each
externalHostsURL with the generated path:${externalHost}/<urlPathPrefix>/<eventlistener-namespace>/<eventlistener-name> - For example:
externalHosts: ["https://webhooks.example.com"]+urlPathPrefix: /triggers→ Final URL:https://webhooks.example.com/triggers/my-namespace/my-listener - These URLs appear in EventListener's
status.addressesfield, making it easy to copy and paste into GitHub/GitLab webhook configuration
Common scenarios:
What happens if you fill it wrong?
- ✅ Ingress will still work correctly (this field doesn't affect Ingress creation)
- ❌ Users will see incorrect webhook URLs in the UI
- ❌ Copying the URL from
status.addressesto GitHub/GitLab will fail - 🔧 Fix: Update the
externalHostsvalue in TektonConfig and the controller will refresh EventListener status
Key differences from
hostfield:Rule of thumb:
- If you can access your webhook at
https://webhooks.example.com:8443/triggers/ns/el, then fill:externalHosts: ["https://webhooks.example.com:8443"] - The controller will append the path automatically
Important notes:
- Always include the protocol (
http://orhttps://) - Include custom ports if your LoadBalancer uses non-standard ports
- Don't include the path in
urlPathPrefix(like/triggers) - the controller appends it to the end of theexternalHostsautomatically - If unsure, leave it empty and check the actual accessible URL first, then update the configuration
- The controller combines each
-
urlPathPrefix (optional) – path prefix; defaults to
/triggers. The final path rendered in the Ingress is${urlPathPrefix}/${eventlistener-namespace}/${eventlistener-name}. Always start with/and avoid trailing slashes. -
namespaceSelector.matchNames (optional) – namespaces allowed by this rule. Use
"*"to target all namespaces. -
labelSelector (optional) – Kubernetes LabelSelector used to filter EventListeners.
-
tls (optional) – TLS configuration for Ingress. Each entry specifies
hosts(list of hostnames) andsecretName(name of the TLS Secret containing the certificate). -
annotations (optional) – additional annotations for Ingress. Useful for cert-manager, nginx-specific settings, etc. Controller-managed annotations (like
nginx.ingress.kubernetes.io/rewrite-target) will be merged with user-provided annotations.
Namespace matching currently supports
matchNamesonly. If you need label-based namespace selection, enumerate the namespaces explicitly.
Field Mapping to Ingress Resources
The following table shows how export rule fields map to the generated Ingress resource:
Example Mapping:
Given this export rule:
DNS Configuration: When using a domain name in the host field, ensure DNS records are configured to resolve the domain to your Ingress controller's IP. For local testing, you can add entries to /etc/hosts (Linux/Mac) or C:\Windows\System32\drivers\etc\hosts (Windows).
The generated Ingress will have:
metadata.name:test-webhooksspec.ingressClassName:nginxspec.rules[0].host:webhooks.example.comspec.rules[0].http.paths[].path:/triggers/${namespace}/${eventlistener-name}(for each matching EventListener)spec.tls[0].hosts:["webhooks.example.com"]spec.tls[0].secretName:webhooks-tls-secretmetadata.annotations: Includescert-manager.io/cluster-issuerand controller-managed annotations
Request flow diagram
externalHoststells external clients which URL to call. The Ingress still matches requests byhostand${urlPathPrefix}/${namespace}/${eventlistener}, and the backend Service receives exactly that path.
Configuration examples
Example 1: wildcard host with custom prefix
Result: the Ingress exposes /hooks/default/${namespace}/${eventlistener}. Because host is empty, any hostname will be accepted—ideal when an external gateway assigns the public domain.
Example 2: shared hostname and prefix
Result: every EventListener appears at https://webhooks.example.com/triggers/${namespace}/${eventlistener}; the backend sees the same path.
Example 3: environment-specific rules
Result:
- GitLab webhooks:
https://gitlab-staging.example.com/staging/gitlab/${namespace}/${eventlistener} - GitHub webhooks:
https://github-prod.example.com/prod/github/${namespace}/${eventlistener}
Example 4: team-scoped publishing with default prefix
Result: only EventListeners in team-a are exposed, at /triggers/team-a/${eventlistener}.
Example 5: multiple external endpoints and adjusted prefix
Result:
- Ingress serves
webhook.internal.local/internal/hooks/${namespace}/${eventlistener}internally. - Externally you can publish
https://webhooks.example.com/hooks/internal/hooks/${namespace}/${eventlistener}andhttps://backup.example.com/api/hooks/internal/hooks/${namespace}/${eventlistener}. - The backend Service always receives
/internal/hooks/${namespace}/${eventlistener}.
Example 6: Configuring TLS/HTTPS
Option A: Manual TLS with pre-created Secret
-
Create a TLS Secret containing your certificate:
-
Configure your export rule with TLS:
The controller will automatically configure the Ingress with TLS using the specified Secret.
Option B: Using cert-manager for automatic certificate management
Configure your export rule with cert-manager annotations:
cert-manager will automatically:
- Create a Certificate resource
- Obtain a certificate from Let's Encrypt (or your configured issuer)
- Create a TLS Secret
- Update the Ingress with TLS configuration
Option C: Combined TLS and annotations
You can combine manual TLS configuration with additional annotations:
Note: When both
tlsand cert-manager annotations are configured, thetlsconfiguration takes precedence. For automatic certificate management, use cert-manager annotations withouttlsconfiguration.
Configuration workflow
- Edit the
TektonConfigresource (see Configuration entry point). - Apply the changes:
kubectl apply -f tektonconfig.yaml. - Wait for the Operator to propagate the ConfigMap; the automatic exposure controller will then reconcile new resources automatically.
Verification and troubleshooting
Verify ConfigMap content
Check that the ConfigMap contains the expected configuration:
Expected output (normal):
What to check:
- The ConfigMap exists and contains the
configkey - The
export-rulesarray matches your TektonConfig specification - YAML syntax is valid (no parsing errors)
Verify Ingress objects
Check that Ingress resources are created for matching EventListeners:
Important: The <namespace> in the command should be the namespace where your EventListener is deployed, not the system namespace (tekton-pipelines). The automatic exposure feature creates Ingress resources in the same namespace as the EventListener.
Expected output (normal):
What to check:
- Ingress objects exist for EventListeners that match export rules
- The
HOSTSfield matches thehostspecified in the export rule - The Ingress has an
ADDRESSassigned (may take a few minutes) - If no Ingress appears, verify the namespace matches
matchNamesand EventListener labels matchlabelSelector
Check EventListener addresses
Verify that EventListener status contains the generated webhook addresses:
Expected output (normal):
What to check:
- The
addressesarray contains URLs matching yourexternalHostsconfiguration - URLs follow the pattern:
<externalHost>/<urlPathPrefix>/<eventlistener-namespace>/<eventlistener-name> - If
addressesis empty or missing, the EventListener may not match any export rule
Inspect Trigger annotations
Check the export metadata stored in Trigger annotations:
Expected output (normal):
What to check:
- The annotation contains an array of EventListener information
- Each entry includes
name,namespace,endpoints, andrelevancefields - The
endpointsarray matches the EventListener'sstatus.addresses - The
relevance.scoreindicates how well the EventListener matches the Trigger (higher is better) - If the annotation is missing, the Trigger may not have found any matching EventListeners
Troubleshooting tips
-
If a rule does not apply:
- Verify that the namespace is listed in
matchNames(or use"*"for all namespaces) - Check that EventListener labels satisfy the
labelSelectorrequirements - Ensure the EventListener is in
Readystate
- Verify that the namespace is listed in
-
Misconfigured label selectors:
- Appear in controller logs as parsing errors
- Check controller logs:
kubectl logs -n tekton-pipelines -l app=tektoncd-enhancement-controller
-
Removing a rule:
- Cascades deletion of the generated resources (Ingress, Service, etc.)
- Setting
export-rulesto an empty array disables all external exposure - EventListener
status.addresseswill be cleared when no rules match
-
Using IP addresses instead of domain names:
-
Problem: Kubernetes Ingress resources do not support IP addresses as
hostvalues. If you configurehostwith an IP address (e.g.,host: 192.168.1.100), the Ingress will fail to be created or will not work correctly. -
Solution 1: Leave
hostempty or set it to"*"to accept all hosts. The Ingress will match requests regardless of the host header: -
Solution 2: Configure a domain name that resolves to your IP address, then use that domain in the
hostfield:-
Set up DNS resolution: Add an A record pointing your domain to the IP address (e.g.,
webhooks.example.com→192.168.1.100) -
Configure the export rule with the domain name:
-
-
Note:
externalHostscan contain IP addresses or URLs, as it's only used to populate EventListenerstatus.addressesand doesn't affect Ingress creation. However, the Ingress itself must use a valid hostname (or be empty) in thehostfield.
-
By maintaining the ConfigMap through TektonConfig, you can flexibly control how Tekton EventListeners are exposed to external systems. Keep an eye on controller logs during updates to confirm that reconciliations complete successfully.