Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions charts/tekton-operator/templates/kubernetes-crds.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2829,6 +2829,24 @@ spec:
type: string
metrics.taskrun.level:
type: string
networkPolicy:
description: |-
NetworkPolicy configures NetworkPolicy creation for the proxy-webhook
workload deployed by TektonPipeline.
properties:
disabled:
description: |-
Disabled disables all NetworkPolicy creation for this component.
Existing policies are removed on the next reconcile.
type: boolean
policies:
description: |-
Policies merges with the operator's default NetworkPolicies by name.
A key matching a default policy name replaces that default entirely.
A key not matching any default is added alongside the defaults.
If nil or empty, all operator defaults are applied unchanged.
x-kubernetes-preserve-unknown-fields: true
type: object
options:
description: options holds additions fields and these fields will
be updated on the manifests
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,24 @@ spec:
type: string
metrics.taskrun.level:
type: string
networkPolicy:
description: |-
NetworkPolicy configures NetworkPolicy creation for the proxy-webhook
workload deployed by TektonPipeline.
properties:
disabled:
description: |-
Disabled disables all NetworkPolicy creation for this component.
Existing policies are removed on the next reconcile.
type: boolean
policies:
description: |-
Policies merges with the operator's default NetworkPolicies by name.
A key matching a default policy name replaces that default entirely.
A key not matching any default is added alongside the defaults.
If nil or empty, all operator defaults are applied unchanged.
x-kubernetes-preserve-unknown-fields: true
type: object
options:
description: options holds additions fields and these fields will
be updated on the manifests
Expand Down
1 change: 1 addition & 0 deletions config/kubernetes/base/kustomization.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,4 @@ resources:
- ../../webhooks/
- operator_service.yaml
- pipelinesascode.yaml
- networkpolicy.yaml
89 changes: 89 additions & 0 deletions config/kubernetes/base/networkpolicy.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# Copyright 2026 The Tekton Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# NetworkPolicy resources for the operator's own namespace (tekton-operator). Unlike the
# NetworkPolicies documented in docs/NetworkPolicy.md (reconciled dynamically by the operator for
# operand namespaces such as tekton-pipelines/tekton-triggers), no CR watches the operator's own
# namespace, so these ship statically with the install manifests/bundle instead. podSelectors are
# scoped to this operator's own pod labels only — never an empty/namespace-wide selector — so
# installing this bundle never affects other pods/operators that might share the namespace.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: tekton-operator
spec:
podSelector:
matchLabels:
name: tekton-operator
policyTypes:
- Ingress
- Egress
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: monitoring
ports:
- protocol: TCP
port: 9090
egress:
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53
- ports:
- protocol: TCP
port: 443
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: tekton-operator-webhook
spec:
podSelector:
matchLabels:
name: tekton-operator-webhook
policyTypes:
- Ingress
- Egress
ingress:
# Admission webhook callbacks originate from the API server; source IPs vary by cluster
# network plugin, so no ingress "from" restriction is applied here.
- ports:
- protocol: TCP
port: 8443
egress:
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- protocol: UDP
port: 53
- protocol: TCP
port: 53
- ports:
- protocol: TCP
port: 443
1 change: 1 addition & 0 deletions config/openshift/base/kustomization.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ resources:
- ../../webhooks
- operator_service.yaml
- operator_servicemonitor.yaml
- networkpolicy.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

Expand Down
90 changes: 90 additions & 0 deletions config/openshift/base/networkpolicy.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# Copyright 2026 The Tekton Authors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# NetworkPolicy resources for the operator's own namespace (openshift-operators). Unlike the
# NetworkPolicies documented in docs/NetworkPolicy.md (reconciled dynamically by the operator for
# operand namespaces such as openshift-pipelines), no CR watches the operator's own namespace, so
# these ship statically with the install manifests/OLM bundle instead. podSelectors are scoped to
# this operator's own pod labels only — never an empty/namespace-wide selector, per the OLM bundle
# guidance — so installing this bundle never affects other operators that may share the namespace
# (openshift-operators is typically shared across many cluster-scoped operators).
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: openshift-pipelines-operator
spec:
podSelector:
matchLabels:
name: openshift-pipelines-operator
policyTypes:
- Ingress
- Egress
ingress:
- from:
- namespaceSelector:
matchLabels:
openshift.io/cluster-monitoring: "true"
ports:
- protocol: TCP
port: 9090
egress:
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: openshift-dns
podSelector:
matchLabels:
dns.operator.openshift.io/daemonset-dns: default
ports:
- protocol: UDP
port: 5353
- protocol: TCP
port: 5353
- ports:
- protocol: TCP
port: 6443
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: tekton-operator-webhook
spec:
podSelector:
matchLabels:
name: tekton-operator-webhook
policyTypes:
- Ingress
- Egress
ingress:
# Admission webhook callbacks originate from the API server; source IPs vary by cluster
# network plugin, so no ingress "from" restriction is applied here.
- ports:
- protocol: TCP
port: 8443
egress:
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: openshift-dns
podSelector:
matchLabels:
dns.operator.openshift.io/daemonset-dns: default
ports:
- protocol: UDP
port: 5353
- protocol: TCP
port: 5353
- ports:
- protocol: TCP
port: 6443
57 changes: 54 additions & 3 deletions docs/NetworkPolicy.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ weight: 15
# NetworkPolicy

The operator can manage [NetworkPolicy][np] resources for Tekton component workloads.
Currently only TektonTrigger is supported; other components will be added later.
Currently TektonTrigger and TektonPipeline (proxy-webhook only) are supported;
other components will be added later.

Configuration is available via `TektonConfig`:

Expand All @@ -30,8 +31,9 @@ spec:
- port: 9000
```

The `networkPolicy` field is propagated from `TektonConfig` to `TektonTrigger`.
Users can also configure it directly on the `TektonTrigger` CR.
The `networkPolicy` field is propagated from `TektonConfig` to `TektonTrigger` and
`TektonPipeline`. Users can also configure it directly on the `TektonTrigger` or
`TektonPipeline` CR.

## Default Policies

Expand All @@ -53,6 +55,17 @@ to the operand namespace (e.g. `tekton-pipelines` or `openshift-pipelines`):
| | egress | UDP+TCP/53 or 5353 | DNS resolver pods |
| | egress | TCP/443 or 6443 | API server |
| | egress | TCP/80, 443 | Any (external APIs e.g. GitHub) |
| `tekton-proxy-webhook-default-deny` | deny all | — | All pods with `name: tekton-operator` (proxy-webhook) in the Pipeline target namespace |
| `proxy-webhook` | ingress | TCP/8443 | Any (admission webhook) |
| | egress | UDP+TCP/53 or 5353 | DNS resolver pods |
| | egress | TCP/443 or 6443 | API server |

The `proxy-webhook` policies apply to the TektonPipeline target namespace (e.g.
`tekton-pipelines` or `openshift-pipelines`), where the operator deploys the
proxy-webhook Deployment. They do not cover the operator's own namespace
(`tekton-operator` / `openshift-operators`), which ships fixed, non-configurable
NetworkPolicies as part of the operator's own install manifests/bundle (see
[Operator's own namespace](#operators-own-namespace) below).

### Platform differences

Expand All @@ -63,6 +76,44 @@ to the operand namespace (e.g. `tekton-pipelines` or `openshift-pipelines`):
| API server port | 443 | 6443 |
| Prometheus namespace label | `kubernetes.io/metadata.name: monitoring` | `openshift.io/cluster-monitoring: "true"` |

## Operator's own namespace

The operator's own namespace (`tekton-operator` on Kubernetes, `openshift-operators`
on OpenShift) ships two fixed NetworkPolicies as static manifests alongside the
operator's Deployment/RBAC — in `config/kubernetes/base/networkpolicy.yaml` and
`config/openshift/base/networkpolicy.yaml` respectively. These are **not**
reconciled by a controller and are **not** configurable via `spec.networkPolicy`:
no CR watches the operator's own namespace, so there is nothing to gate this on.
They are also not a namespace-wide default-deny — each policy's `podSelector` is
scoped to one of the operator's own pods (`name: tekton-operator` /
`name: openshift-pipelines-operator` for the main controller, and
`name: tekton-operator-webhook` for the CR admission webhook) so that installing
the operator's bundle never affects unrelated pods that might share the namespace
(`openshift-operators` in particular is commonly shared by many operators).

| Policy | Direction | Port | Source / Destination |
|---|---|---|---|
| `tekton-operator` / `openshift-pipelines-operator` | ingress | TCP/9090 | Prometheus namespace |
| | egress | UDP+TCP/53 or 5353 | DNS resolver pods |
| | egress | TCP/443 or 6443 | API server |
| `tekton-operator-webhook` | ingress | TCP/8443 | Any (admission webhook) |
| | egress | UDP+TCP/53 or 5353 | DNS resolver pods |
| | egress | TCP/443 or 6443 | API server |

**OpenShift caveat**: `openshift-operators` is a shared namespace where OLM installs
operators from OperatorHub, many of which ship no NetworkPolicy of their own. To
avoid silently breaking those operators' networking, OpenShift's platform payload
ships a permissive `default-allow-all` NetworkPolicy in that namespace out of the
box (labeled `capability.openshift.io/name: OperatorLifecycleManager`), with an
empty `podSelector` allowing all ingress/egress for every pod in the namespace.
Because NetworkPolicy rules are additive (a pod's allowed traffic is the union of
every policy that selects it, not the intersection), this platform-shipped policy
supersedes the two policies above in practice — the operator's own pods remain
fully open on a stock OpenShift cluster until a cluster admin removes or replaces
`default-allow-all`. The `openshift-pipelines` (operand) namespace has no such
baseline policy, so the `proxy-webhook` policies further up this page are enforced
as documented without this caveat.

## Disabling

```yaml
Expand Down
6 changes: 3 additions & 3 deletions pkg/apis/operator/v1alpha1/tektonconfig_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,9 +135,9 @@ type TektonConfigSpec struct {
// +optional
TargetNamespaceMetadata *NamespaceMetadata `json:"targetNamespaceMetadata,omitempty"`
// NetworkPolicy configures NetworkPolicy resources for the operand namespace.
// This field is propagated to TektonTrigger, which is the only component with
// NetworkPolicy reconciliation implemented. Other components (Pipeline, Chains,
// Results, Dashboard) do not yet act on this field.
// This field is propagated to TektonTrigger and TektonPipeline, which are the
// only components with NetworkPolicy reconciliation implemented. Other
// components (Chains, Results, Dashboard) do not yet act on this field.
// +optional
NetworkPolicy NetworkPolicyConfig `json:"networkPolicy,omitempty"`
}
Expand Down
4 changes: 4 additions & 0 deletions pkg/apis/operator/v1alpha1/tektonpipeline_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,10 @@ type TektonPipelineSpec struct {
// Config holds the configuration for resources created by TektonPipeline
// +optional
Config Config `json:"config,omitempty"`
// NetworkPolicy configures NetworkPolicy creation for the proxy-webhook
// workload deployed by TektonPipeline.
// +optional
NetworkPolicy NetworkPolicyConfig `json:"networkPolicy,omitempty"`
}

// TektonPipelineStatus defines the observed state of TektonPipeline
Expand Down
1 change: 1 addition & 0 deletions pkg/apis/operator/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions pkg/reconciler/kubernetes/tektonpipeline/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import (
tektonPipelineInformer "github.com/tektoncd/operator/pkg/client/injection/informers/operator/v1alpha1/tektonpipeline"
tektonPipelineReconciler "github.com/tektoncd/operator/pkg/client/injection/reconciler/operator/v1alpha1/tektonpipeline"
"github.com/tektoncd/operator/pkg/reconciler/common"
"github.com/tektoncd/operator/pkg/reconciler/common/networkpolicy"
"github.com/tektoncd/operator/pkg/reconciler/kubernetes/tektoninstallerset/client"
"k8s.io/client-go/tools/cache"
kubeclient "knative.dev/pkg/client/injection/kube/client"
Expand Down Expand Up @@ -62,12 +63,18 @@ func NewExtendedController(generator common.ExtensionGenerator) injection.Contro
}
tisClient := operatorclient.Get(ctx).OperatorV1alpha1().TektonInstallerSets()

params := networkpolicy.KubernetesPlatformDefaults()
if v1alpha1.IsOpenShiftPlatform() {
params = networkpolicy.OpenShiftPlatformDefaults()
}

c := &Reconciler{
kubeClientSet: kubeclient.Get(ctx),
extension: generator(ctx),
manifest: manifest,
pipelineVersion: pipelineVer,
installerSetClient: client.NewInstallerSetClient(tisClient, operatorVer, pipelineVer, v1alpha1.KindTektonPipeline, metrics),
platformParams: params,
}
impl := tektonPipelineReconciler.NewImpl(ctx, c)

Expand Down
5 changes: 5 additions & 0 deletions pkg/reconciler/kubernetes/tektonpipeline/finalize.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ func (r *Reconciler) FinalizeKind(ctx context.Context, original *v1alpha1.Tekton
return err
}

if err := r.installerSetClient.CleanupCustomSet(ctx, "pipeline-network-policies"); err != nil {
logger.Error("failed to cleanup pipeline network policies installerset: ", err)
return err
}

if err := r.extension.Finalize(ctx, original); err != nil {
logger.Error("Failed to finalize platform resources: ", err)
}
Expand Down
Loading
Loading