Skip to content
Merged
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
3,363 changes: 2,656 additions & 707 deletions charts/tekton-operator/templates/kubernetes-crds.yaml

Large diffs are not rendered by default.

3,363 changes: 2,656 additions & 707 deletions charts/tekton-operator/templates/openshift-crds.yaml

Large diffs are not rendered by default.

489 changes: 489 additions & 0 deletions config/base/generated-crds/operator.tekton.dev_syncerservices.yaml

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -575,8 +575,9 @@ spec:
networkPolicy:
description: |-
NetworkPolicy configures NetworkPolicy resources for the operand namespace.
This field is propagated to TektonTrigger, TektonPipeline, TektonChain,
TektonPruner, and TektonResult, which implement NetworkPolicy reconciliation.
This field is propagated to TektonPipeline, TektonTrigger, TektonChain,
TektonPruner, TektonResult, Pipelines-as-Code, and MultiCluster components
(TektonScheduler, TektonMulticlusterProxyAAE, SyncerService).
Other components (Dashboard) do not yet act on this field.
properties:
disabled:
Expand Down

Large diffs are not rendered by default.

472 changes: 472 additions & 0 deletions config/base/generated-crds/operator.tekton.dev_tektonresults.yaml

Large diffs are not rendered by default.

489 changes: 489 additions & 0 deletions config/base/generated-crds/operator.tekton.dev_tektonschedulers.yaml

Large diffs are not rendered by default.

64 changes: 53 additions & 11 deletions docs/NetworkPolicy.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,10 @@ weight: 15
# NetworkPolicy

The operator can manage [NetworkPolicy][np] resources for Tekton component workloads.
Currently TektonPipeline (core controllers, resolvers, and proxy-webhook),
TektonTrigger, TektonChain, Pipelines-as-Code, ManualApprovalGate, TektonPruner,
and TektonResult are supported; other components will be added later.
TektonPipeline (core controllers, resolvers, and proxy-webhook), TektonTrigger,
TektonChain, Pipelines-as-Code, ManualApprovalGate, TektonPruner, TektonResult,
and MultiCluster components (TektonScheduler, TektonMulticlusterProxyAAE,
SyncerService) are supported; other components will be added later.

Configuration is available via `TektonConfig`:

Expand All @@ -32,12 +33,12 @@ spec:
- port: 9000
```

The `networkPolicy` field is propagated from `TektonConfig` to `TektonTrigger`,
`TektonPipeline`, `TektonChain`, `TektonPruner`, and `TektonResult`. When those
component CRs are managed by `TektonConfig` (the usual install path),
**TektonConfig is the source of truth**: edits to `spec.networkPolicy` on the
component CRs alone are overwritten on the next Config reconcile. Configure
NetworkPolicy via `TektonConfig.spec.networkPolicy`.
The `networkPolicy` field is propagated from `TektonConfig` to `TektonPipeline`,
`TektonTrigger`, `TektonChain`, `TektonPruner`, `TektonResult`, Pipelines-as-Code,
and MultiCluster components. When those component CRs are managed by `TektonConfig`
(the usual install path), **TektonConfig is the source of truth**: edits to
`spec.networkPolicy` on the component CRs alone are overwritten on the next Config
reconcile. Configure NetworkPolicy via `TektonConfig.spec.networkPolicy`.

## Default Policies

Expand Down Expand Up @@ -256,8 +257,49 @@ user's browser via the OpenShift Console's proxy, not on this pod.
These are static manifests shipped with the TektonConfig console plugin resources,
not reconciled via `spec.networkPolicy`.

All policies above are applied to the operand namespace (e.g. `tekton-pipelines`
or `openshift-pipelines`). They do not cover the operator's own namespace
### TektonScheduler

Policies are applied to the operand namespace (`tekton-pipelines` or `openshift-pipelines`).

| Policy | Direction | Port | Source / Destination |
|---|---|---|---|
| `scheduler-controller-default-deny` | deny all | — | Scheduler controller pods |
| `scheduler-webhook-default-deny` | deny all | — | Scheduler webhook pods |
| `scheduler-controller` | ingress | TCP/8443 | Prometheus namespace |
| | egress | UDP+TCP/53 (K8s) or 5353 (OpenShift) | DNS resolver pods |
| | egress | all | API server (all egress allowed — NP cannot select host-network endpoints) |
| `scheduler-webhook` | ingress | TCP/9443 | Any (admission webhook) |
| | ingress | TCP/8443 | Prometheus namespace |
| | egress | UDP+TCP/53 or 5353 | DNS resolver pods |
| | egress | all | API server (all egress allowed — NP cannot select host-network endpoints) |

### TektonMulticlusterProxyAAE

Policies are applied to the operand namespace (`tekton-pipelines` or `openshift-pipelines`).
Deployed only when the scheduler is enabled with multi-cluster role = Hub.

| Policy | Direction | Port | Source / Destination |
|---|---|---|---|
| `proxy-aae-default-deny` | deny all | — | Proxy-AAE pods (`app: proxy-aae`) |
| `proxy-aae` | ingress | TCP/8080 | Any (spoke clusters connect via service 443→8080) |
| | egress | UDP+TCP/53 (K8s) or 5353 (OpenShift) | DNS resolver pods |
| | egress | all | API server (all egress allowed — NP cannot select host-network endpoints) |

### SyncerService (OpenShift only)

Policies are applied to the operand namespace (`openshift-pipelines`).
Deployed only when the scheduler is enabled with multi-cluster role = Hub.

| Policy | Direction | Port | Source / Destination |
|---|---|---|---|
| `syncer-service-default-deny` | deny all | — | SyncerService pods (`app: workload-controller`) |
| `syncer-service-controller` | egress | UDP+TCP/5353 | DNS resolver pods (OpenShift) |
| | egress | all | API server (all egress allowed — NP cannot select host-network endpoints) |

All component policies (TektonPipeline, TektonTrigger, TektonScheduler,
TektonMulticlusterProxyAAE, SyncerService, and Console Plugin) are applied to the
operand namespace (e.g. `tekton-pipelines` or `openshift-pipelines`).
None of these 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).
Expand Down
8 changes: 6 additions & 2 deletions pkg/apis/operator/v1alpha1/syncerservice_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ type SyncerServiceSpec struct {
// Config holds the configuration for resources created by SyncerService
// +optional
Config Config `json:"config,omitempty"`
// +optional
NetworkPolicy NetworkPolicyConfig `json:"networkPolicy,omitempty"`
Comment thread
khrm marked this conversation as resolved.
}

// SyncerServiceOptions defines the fields to customize SyncerService component
Expand Down Expand Up @@ -89,15 +91,17 @@ func (sss *SyncerServiceStatus) MarkPreReconcilerFailed(msg string) {
syncerServiceCondSet.Manage(sss).MarkFalse(
PreReconciler,
"Error",
msg)
msg,
)
}

func (sss *SyncerServiceStatus) MarkPostReconcilerFailed(msg string) {
sss.MarkNotReady("PostReconciliation failed")
syncerServiceCondSet.Manage(sss).MarkFalse(
PostReconciler,
"Error",
msg)
msg,
)
}

// SyncerServiceList contains a list of SyncerService
Expand Down
1 change: 1 addition & 0 deletions pkg/apis/operator/v1alpha1/syncerservice_validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,6 @@ func (ss *SyncerService) Validate(ctx context.Context) (errs *apis.FieldError) {
return errs.Also(apis.ErrInvalidValue(ss.GetName(), errMsg))
}

errs = errs.Also(ss.Spec.NetworkPolicy.validate("spec.networkPolicy"))
return errs
}
5 changes: 3 additions & 2 deletions pkg/apis/operator/v1alpha1/tektonconfig_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,8 +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, TektonPipeline, TektonChain,
// TektonPruner, and TektonResult, which implement NetworkPolicy reconciliation.
// This field is propagated to TektonPipeline, TektonTrigger, TektonChain,
// TektonPruner, TektonResult, Pipelines-as-Code, and MultiCluster components
// (TektonScheduler, TektonMulticlusterProxyAAE, SyncerService).
// Other components (Dashboard) do not yet act on this field.
// +optional
NetworkPolicy NetworkPolicyConfig `json:"networkPolicy,omitempty"`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ type TektonMulticlusterProxyAAE struct {
type TektonMulticlusterProxyAAESpec struct {
CommonSpec `json:",inline"`
MulticlusterProxyAAEOptions `json:",inline"`
// +optional
NetworkPolicy NetworkPolicyConfig `json:"networkPolicy,omitempty"`
}

type MulticlusterProxyAAEOptions struct {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,22 @@ package v1alpha1

import (
"context"
"fmt"

"knative.dev/pkg/apis"
)

// Validate implements the validation contract for the webhook. Reserved for future use.
// Validate implements the validation contract for the webhook.
func (t *TektonMulticlusterProxyAAE) Validate(ctx context.Context) (errs *apis.FieldError) {
return nil
if apis.IsInDelete(ctx) {
return nil
}

if t.GetName() != MultiClusterProxyAAEResourceName {
errMsg := fmt.Sprintf("metadata.name, Only one instance of TektonMulticlusterProxyAAE is allowed by name, %s", MultiClusterProxyAAEResourceName)
errs = errs.Also(apis.ErrInvalidValue(t.GetName(), errMsg))
}

errs = errs.Also(t.Spec.NetworkPolicy.validate("spec.networkPolicy"))
return errs
}
2 changes: 2 additions & 0 deletions pkg/apis/operator/v1alpha1/tektonscheduler_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ type TektonSchedulerList struct {
type TektonSchedulerSpec struct {
CommonSpec `json:",inline"`
Scheduler `json:",inline"`
// +optional
NetworkPolicy NetworkPolicyConfig `json:"networkPolicy,omitempty"`
}

// TektonSchedulerStatus defines the observed state of TektonScheduler
Expand Down
2 changes: 1 addition & 1 deletion pkg/apis/operator/v1alpha1/tektonscheduler_validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ import (
)

func (ts *TektonScheduler) Validate(ctx context.Context) (errs *apis.FieldError) {

if apis.IsInDelete(ctx) {
return nil
}
Expand All @@ -37,6 +36,7 @@ func (ts *TektonScheduler) Validate(ctx context.Context) (errs *apis.FieldError)

// execute common spec validations
errs = errs.Also(ts.Spec.MultiClusterConfig.validate())
errs = errs.Also(ts.Spec.NetworkPolicy.validate("spec.networkPolicy"))
return errs
}

Expand Down
3 changes: 3 additions & 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.

Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (

tektonInstallerinformer "github.com/tektoncd/operator/pkg/client/injection/informers/operator/v1alpha1/tektoninstallerset"
tektonPipelineinformer "github.com/tektoncd/operator/pkg/client/injection/informers/operator/v1alpha1/tektonpipeline"
"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 @@ -61,6 +62,11 @@ func NewExtendedController(generator common.ExtensionGenerator) injection.Contro
logger.Fatal("Error while getting operator version", err)
}

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

tisClient := operatorclient.Get(ctx).OperatorV1alpha1().TektonInstallerSets()
metrics, _ := NewRecorder()
c := &Reconciler{
Expand All @@ -70,6 +76,7 @@ func NewExtendedController(generator common.ExtensionGenerator) injection.Contro
pipelineInformer: tektonPipelineinformer.Get(ctx),
extension: generator(ctx),
manifest: manifest,
platformParams: params,
multiclusterProxyAAEVersion: proxyAAEVer,
operatorVersion: operatorVer,
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@ func (r *Reconciler) FinalizeKind(ctx context.Context, original *v1alpha1.Tekton
return err
}

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

if err := r.extension.Finalize(ctx, original); err != nil {
logger.Error("Failed to finalize platform resources", "error", err)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/*
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.
*/

package tektonmulticlusterproxyaae

import (
"context"

mf "github.com/manifestival/manifestival"
"github.com/tektoncd/operator/pkg/apis/operator/v1alpha1"
"github.com/tektoncd/operator/pkg/reconciler/common/networkpolicy"
"github.com/tektoncd/operator/pkg/reconciler/kubernetes/tektoninstallerset/client"
corev1 "k8s.io/api/core/v1"
networkingv1 "k8s.io/api/networking/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/intstr"
)

const proxyAAECustomSet = "proxy-aae-network-policies"

var proxyAAEPodSelector = metav1.LabelSelector{
MatchLabels: map[string]string{"app": "proxy-aae"},
}

func proxyAAEDefaultPolicies(params networkpolicy.PlatformParams) []networkingv1.NetworkPolicy {
proxyPort := intstr.FromInt32(8080)
tcp := corev1.ProtocolTCP

return []networkingv1.NetworkPolicy{
{
ObjectMeta: metav1.ObjectMeta{Name: "proxy-aae"},
Spec: networkingv1.NetworkPolicySpec{
PodSelector: proxyAAEPodSelector,
PolicyTypes: []networkingv1.PolicyType{networkingv1.PolicyTypeIngress, networkingv1.PolicyTypeEgress},
Ingress: []networkingv1.NetworkPolicyIngressRule{
{
Ports: []networkingv1.NetworkPolicyPort{
{Protocol: &tcp, Port: &proxyPort},
},
},
},
Egress: []networkingv1.NetworkPolicyEgressRule{
networkpolicy.DNSEgressRule(params),
networkpolicy.APIServerEgressRule(),
},
},
},
}
}

func proxyAAEDefaultDenyPolicy() networkingv1.NetworkPolicy {
return networkpolicy.DefaultDenyPolicy("proxy-aae-default-deny", proxyAAEPodSelector)
}

func (r *Reconciler) reconcileNetworkPolicies(ctx context.Context, proxy *v1alpha1.TektonMulticlusterProxyAAE) error {
if proxy.Spec.NetworkPolicy.Disabled {
return r.installerSetClient.CleanupCustomSet(ctx, proxyAAECustomSet)
}
defaults := []networkingv1.NetworkPolicy{
proxyAAEDefaultDenyPolicy(),
}
defaults = append(defaults, proxyAAEDefaultPolicies(r.platformParams)...)

manifest, err := networkpolicy.Generate(
proxy.Spec.NetworkPolicy,
proxy.Spec.GetTargetNamespace(),
defaults,
)
if err != nil {
return err
}
return r.installerSetClient.CustomSet(ctx, proxy, proxyAAECustomSet, &manifest, passthroughTransform, nil)
}

func passthroughTransform(_ context.Context, m *mf.Manifest, _ v1alpha1.TektonComponent) (*mf.Manifest, error) {
return m, nil
}

var _ client.FilterAndTransform = passthroughTransform
Loading
Loading