Constrain Tekton Pipeline Execution with Kyverno
Use Kyverno to answer questions such as: "May teams run their own Tasks?", "Which template must they use?", and "Which tool images may execute?" A Task defines steps; a Pipeline connects Tasks; TaskRuns and PipelineRuns execute those definitions. Kyverno checks their Kubernetes API requests against rules written by a platform administrator.
It can check the object submitted to the Kubernetes API, the Pod created for a TaskRun, and selected fields written to a completed run. It does not replace Tekton's execution semantics or prove what an arbitrary shell command will do.
This guide is a capability map with generic examples. The values in angle brackets are intentional placeholders. Replace them with values owned by your platform team before applying a policy. For a concrete CI scenario, see Constrain Catalog Pipeline Usage with Kyverno. That companion page uses a Pipeline delivered by ArtifactHub Shim and shows how to turn these generic controls into practical restrictions on user configuration, parameters, and scan results. The design rationale is in Pipeline Policy Constraints with Tekton and Kyverno.
TOC
What can be constrainedPrerequisitesRead and install a policy1. Close inline and direct-run bypasses2. Require a reviewed resolver reference3. Limit the images that can execute4. Audit what a completed run reportsRoll out and make exceptions safelySelf-validationTroubleshootingRelated documentationWhat can be constrained
Kyverno sees different objects at different points in a Tekton execution. Choose the object that contains the fact you want to govern.
The timing matters. A resolver reference is available when a PipelineRun is admitted,
but the fetched Pipeline and its labels are not guaranteed to be available yet. A user
can also submit a label that looks like a platform label. Use resolver parameters for an
admission decision and labels or results for post-execution audit.
The lifecycle is: run admission, remote resolution, child TaskRun admission, Pod admission, then status updates. A remotely fetched Task or Pipeline is not automatically submitted as a Kubernetes Task or Pipeline, so policies on those definitions do not validate fetched YAML. A child TaskRun's reference is visible at its admission, but a remote Task's body may still be unresolved. Pod admission sees the resolved container configuration.
Kyverno is one layer in the control. Use RBAC to decide who may create or update Tekton objects, use the operator's inline-spec feature flag for a cluster-wide baseline, keep catalog and Pipeline sources under review, and keep image registries available in an air-gapped cluster. No single policy provides template integrity by itself.
Prerequisites
- Tekton Pipelines and its validating webhook are installed and configured to fail closed for invalid Tekton resources.
- Kyverno admission, background, and reports controllers are Ready. The examples were
verified with Kyverno engine 1.15.9 and Tekton
v1resources. This guide uses thekyverno.io/v1ClusterPolicyAPI and thekyverno.io/v2PolicyExceptionAPI. - You can create policies and, if your exception process permits it, narrowly scoped
PolicyExceptionobjects. - The governed namespace, resolver catalog, and internal image registries are known.
- In an air-gapped cluster, install Kyverno, resolver configuration, policy YAML, and all referenced images from an approved offline repository.
Start with Audit in one disposable namespace. Move a policy to Enforce only after its
match scope and legitimate exceptions are understood. background: false is used below
because these examples are intended to evaluate admission or status updates rather than
rewrite history. The examples are opt-in policies, not installed product defaults.
Read and install a policy
The policy-level spec.validationFailureAction is deprecated and will be removed in a
future Kyverno release. Use spec.rules[].validate.failureAction as shown below; see
Kyverno validation rules.
When migrating an older policy, move its action into every validation rule and remove
the policy-level field.
Put each complete policy below in its own YAML file, replace its placeholders, and first
set validate.failureAction: Audit on every rule. For example, after changing all four
rules in the first policy:
Use the same apply/wait procedure for the other policies. A Ready policy alone is not
proof that it matches a run: execute the positive and negative checks below.
1. Close inline and direct-run bypasses
Use case: require work to enter through a reviewed Pipeline and prevent a user from
embedding a taskSpec or pipelineSpec in a run or definition.
Enforcement point: admission on TaskRun create requests and PipelineRun or
Pipeline create/update requests. A denied request never reaches a Tekton controller.
The standalone TaskRun rule checks only CREATE. The Tekton controller ServiceAccount is
excluded because it creates child TaskRuns for an accepted PipelineRun. Change the
ServiceAccount and namespace when the cluster uses a customized Tekton installation. This
is an authenticated request identity, not spec.serviceAccountName or an owner label that
a user can supply. RBAC must prevent users from impersonating this identity or running
their own Pods under it. Do not extend this rule to UPDATE: the tekton-results-watcher
and tekton-chains-controller components update TaskRun metadata and finalizers on the
main resource, so denying those updates can stop result storage, signing, and finalizer
removal. If another trusted component creates TaskRuns, add its ServiceAccount to the
narrow exclusion as well.
Tekton also has an operator-managed baseline. The following is a configuration fragment
for the existing TektonPipeline, not a new installation. If TektonConfig owns that
resource, set the corresponding spec.pipeline.disable-inline-spec field there instead:
The feature flag is useful when every namespace follows the same rule. Kyverno is useful
when rollout scope, denial messages, PolicyReports, or exceptions matter. The flag does
not create a policy report and neither option replaces RBAC.
The flag prohibits inline specs, but it does not prohibit a standalone TaskRun using
taskRef. A Kyverno PolicyException cannot bypass the Tekton feature flag.
2. Require a reviewed resolver reference
Use case: require every governed PipelineRun to identify a remote Pipeline through
the hub resolver. The generic rule checks only the reference shape. The catalog name and
version belong in the companion Catalog guide.
Enforcement point: PipelineRun admission. This rule does not inspect the remote
Pipeline body.
Add a second policy with an allowlist of name@version pairs. Keep that allowlist in the
Catalog guide when it contains Catalog-specific names; the current Java example is
in Constrain Catalog Pipeline Usage with Kyverno.
3. Limit the images that can execute
Use case: prevent a resolved Task from starting with an image outside approved registries. This is the first point at which every resolved step image is visible.
Enforcement point: Pod admission, before the Task starts. The list must include
Tekton helper images and any platform-injected init image as well as the main tool images.
Replace both registry hosts in both expressions with your actual approved hosts. Escape
literal dots and retain the trailing / so look-alike registry names cannot match.
The selector keeps unrelated application Pods out of this example. A dedicated pipeline
namespace is often simpler. Inspect a server-side dry run before switching to Enforce
because an admission webhook can inject an internal helper image after the submitted Pod
template is rendered.
This policy checks executable images, not build output destinations, images pulled inside
a build step, image signatures, or arbitrary network traffic. Use parameter policies,
registry permissions, and network controls for those concerns. Restrict direct Pod
creation with RBAC; users who can create unlabelled Pods can avoid this selector.
4. Audit what a completed run reports
Use case: detect a missing or unexpected template label after a resolver has finished, without treating a user-controlled label as an admission identity.
Enforcement point: PipelineRun/status updates. The rule is Audit; it never blocks
the initial PipelineRun request. Kyverno cannot use background scans for a status
subresource, so this records new status changes rather than historical runs.
A passing label check is a consistency signal, not proof of provenance: a manually supplied
label remains forgeable even after completion. Never use Enforce on a result rule to try
to stop work that has already happened; rejecting controller status writes can leave runs
stuck without undoing their effects.
For status rules, check reports-controller permissions explicitly:
If policy installation reports missing permissions, an administrator can grant the
following read-only access in the governed namespace. It also covers the companion
Catalog TaskRun audit. Replace every placeholder first; both the Role and RoleBinding
must keep metadata.namespace: <governed-namespace> so that the binding references the
Role in the same namespace. Apply the Role and RoleBinding before the status policies:
Use a similar TaskRun/status policy for task results. Result names and value formats are
Task-specific; do not invent a common result contract. The Catalog guide demonstrates the
real sonarqube-scanner and trivy-scanner contracts for one Pipeline version.
Roll out and make exceptions safely
-
Set every rule's
validate.failureActiontoAudit, install the policy in a disposable namespace, and inspectPolicyReport. -
Create both a valid object and an intentional violation. A missing report can mean the rule did not match, so check the namespace, GVK, and preconditions.
-
For each admission policy, change every rule's
validate.failureActiontoEnforce, starting with the narrowest namespace. Keep status audit rules inAudit. -
Keep an exception that names one policy, one rule, one namespace, and one resource.
-
Give the exception an owner and expiry. Existing objects are not retroactively rejected, but updates and newly created child objects can be.
Do not grant a cluster-wide wildcard exception. Kyverno must be configured to allow
PolicyException resources. Configure the Kyverno admission controller (or the equivalent
chart values) with both --enablePolicyException=true and
--exceptionNamespace=<exception-namespace>. In Kyverno 1.15, enabling the feature without
an allowed namespace, or creating the object in a different namespace, produces an
admission warning but still stores the PolicyException; the exception selector does not
use it, so it has no effect. Configure the allowed namespace first and create the object
there, then treat any admission warning as a failed exception setup. RBAC must also
restrict who can create exceptions. The allowed exception namespace can differ from the
matched run namespace. Expiry is a review/deletion process unless your platform separately
automates it; the resource above has no automatic TTL. An exception skips only its named
rules, not other policies matching the same run.
By default, Kyverno allows updates that preserve a pre-existing violation. Set
validate.allowExistingViolations: false on a rule if those updates must also be denied,
after assessing the effect on running workloads. Keep status audit policies in Audit.
Self-validation
Run these checks in a disposable namespace after replacing the placeholders. Set every
rule's validate.failureAction in the first three policies to Enforce, leaving the label
audit rule in Audit. Test this generic set
before installing the Catalog-specific allowlist; otherwise the additional Catalog rules
must also allow each positive request. Server dry runs exercise admission without starting
builds or pulling images. They do not create persistent PolicyReports.
Additional checks for the same policies:
For a real status audit, submit a deliberately nonexistent template to the configured local catalog. This does not execute a Task or need an external image. It should be admitted, then fail remote resolution and generate a missing-label audit:
Allow the reports controller time to reconcile. Find a fail result for
completed-run-has-template-label on this run. Tekton's resolution failure is separate
from the audit; Kyverno did not deny the request. For the passing case, run an approved
template that propagates the configured label and check for pass instead. A result in
error, or no matching result, does not prove compliance.
After testing, delete only the example runs, policies, exception, Role and RoleBinding you created. Delete the namespace only if it is disposable. Do not remove shared policies.
Troubleshooting
- A child TaskRun create is rejected for the controller. Add the actual Tekton controller
ServiceAccount to the rule exclusion; do not exempt the whole namespace. Metadata updates
from
tekton-results-watcherortekton-chains-controllerare intentionally outside this create-only rule. - A resolver-shaped run is rejected. Resolver parameters must be separate entries with
the exact names
catalog,type,kind,name, andversion. Runtime Pipeline parameters belong underspec.params. - A Pod is rejected after the PipelineRun passed. Pod admission sees the final resolved image list. Add every approved helper registry or create a narrow exception.
- An Audit rule has no report. Check the status subresource match, terminal-condition precondition, reports-controller permissions, and the resource's namespace.
- An existing violation remains. Admission does not rewrite history. Use reports or update the object through the approved path.
Related documentation
- Constrain Catalog Pipeline Usage with Kyverno — a concrete CI example for limiting user configuration on the delivered Java Pipeline, including Catalog-specific parameters and result fields.
- Pipeline Policy Constraints with Tekton and Kyverno — design rationale and control boundaries.
- Tekton Hub resolver concepts — resolver behavior and reference syntax.
- Comply with Pod Security Restricted Standard — Pod security context requirements.
- Tekton Chains verification guides — signing, SBOM, and vulnerability verification, which are separate from the execution policies here.