The trigger-wrapper controller 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.
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 trigger-wrapper controller refreshes its cache and reconciles resources according to the new rules.
Each entry in export-rules represents a publishing strategy. Important fields:
nginx, traefik.https://edge.example.com/hooks becomes https://edge.example.com/hooks<trigger-path>, so add trailing slashes or prefixes explicitly as needed./triggers. The final path rendered in the Ingress is ${urlPathPrefix}/${eventlistener-namespace}/${eventlistener-name}. Always start with / and avoid trailing slashes."*" to target all namespaces.hosts (list of hostnames) and secretName (name of the TLS Secret containing the certificate).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.
The following table shows how export rule fields map to the generated Ingress resource:
| Export Rule Field | Ingress Resource Field | Description |
|---|---|---|
name | metadata.name | The Ingress resource name is set to the rule name |
ingressClass | spec.ingressClassName | Specifies which Ingress controller should handle this Ingress |
host | spec.rules[].host | Hostname for the Ingress rule. If empty or "*", matches all hosts. Note: IP addresses are not supported as host values. If using an IP, leave host empty or configure a domain name that resolves to the IP. |
urlPathPrefix | spec.rules[].http.paths[].path | Combined with namespace and EventListener name to form the path: ${urlPathPrefix}/${namespace}/${eventlistener-name} |
tls | spec.tls | TLS configuration for HTTPS. Each entry maps to spec.tls[].hosts and spec.tls[].secretName |
annotations | metadata.annotations | User-provided annotations are merged with controller-managed annotations |
namespaceSelector | N/A | Used to filter EventListeners, not directly mapped to Ingress |
labelSelector | N/A | Used to filter EventListeners, not directly mapped to Ingress |
externalHosts | N/A | Used to populate EventListener status.addresses, not directly mapped to Ingress |
Example Mapping:
Given this export rule:
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: Includes cert-manager.io/cluster-issuer and controller-managed annotations
externalHoststells external clients which URL to call. The Ingress still matches requests byhostand${urlPathPrefix}/${namespace}/${eventlistener}, and the backend Service receives exactly that path.
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.
Result: every EventListener appears at https://webhooks.example.com/triggers/${namespace}/${eventlistener}; the backend sees the same path.
Result:
https://gitlab-staging.example.com/staging/gitlab/${namespace}/${eventlistener}https://github-prod.example.com/prod/github/${namespace}/${eventlistener}Result: only EventListeners in team-a are exposed, at /triggers/team-a/${eventlistener}.
Result:
webhook.internal.local/internal/hooks/${namespace}/${eventlistener} internally.https://webhooks.example.com/hooks/internal/hooks/${namespace}/${eventlistener} and https://backup.example.com/api/hooks/internal/hooks/${namespace}/${eventlistener}./internal/hooks/${namespace}/${eventlistener}.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.
Configure your export rule with cert-manager annotations:
cert-manager will automatically:
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.
TektonConfig resource (see Configuration entry point).kubectl apply -f tektonconfig.yaml.trigger-wrapper controller will then reconcile new resources automatically.Check that the ConfigMap contains the expected configuration:
Expected output (normal):
What to check:
config keyexport-rules array matches your TektonConfig specificationCheck that Ingress resources are created for matching EventListeners:
Expected output (normal):
What to check:
HOSTS field matches the host specified in the export ruleADDRESS assigned (may take a few minutes)matchNames and EventListener labels match labelSelectorVerify that EventListener status contains the generated webhook addresses:
Expected output (normal):
What to check:
addresses array contains URLs matching your externalHosts configuration<externalHost>/<urlPathPrefix>/<namespace>/<eventlistener-name>addresses is empty or missing, the EventListener may not match any export ruleCheck the export metadata stored in Trigger annotations:
Expected output (normal):
What to check:
name, namespace, endpoints, and relevance fieldsendpoints array matches the EventListener's status.addressesrelevance.score indicates how well the EventListener matches the Trigger (higher is better)If a rule does not apply:
matchNames (or use "*" for all namespaces)labelSelector requirementsReady stateMisconfigured label selectors:
kubectl logs -n tekton-pipelines -l app=tektoncd-enhancement-controllerRemoving a rule:
export-rules to an empty array disables all external exposurestatus.addresses will be cleared when no rules matchUsing IP addresses instead of domain names:
Problem: Kubernetes Ingress resources do not support IP addresses as host values. If you configure host with 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 host empty 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 host field:
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: externalHosts can contain IP addresses or URLs, as it's only used to populate EventListener status.addresses and doesn't affect Ingress creation. However, the Ingress itself must use a valid hostname (or be empty) in the host field.
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.