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
86 changes: 86 additions & 0 deletions config/base/generated-crds/operator.tekton.dev_tektonconfigs.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1607,6 +1607,92 @@ spec:
namespace or in the Default field.
type: string
type: object
namespaceSync:
description: NamespaceSync controls per-namespace resource
provisioning by the NamespaceSyncController.
properties:
createCABundles:
description: CreateCABundles controls whether the CA bundle
ConfigMaps are created in each namespace.
type: boolean
createEditRoleBinding:
description: CreateEditRoleBinding controls whether the
openshift-pipelines-edit RoleBinding is created in each
namespace.
type: boolean
createPipelineSA:
description: CreatePipelineSA controls whether the pipeline
ServiceAccount is created in each namespace.
type: boolean
createSCCRoleBinding:
description: CreateSCCRoleBinding controls whether the
SCC RoleBinding is created in each namespace.
type: boolean
namespaceSelector:
description: NamespaceSelector is an optional label selector
that restricts which namespaces are synced.
properties:
matchExpressions:
items:
properties:
key:
type: string
operator:
type: string
values:
items:
type: string
type: array
required:
- key
- operator
type: object
type: array
matchLabels:
additionalProperties:
type: string
type: object
type: object
secretBindings:
description: SecretBindings declares secrets to be automatically
bound to the pipeline SA in each namespace. Each entry must
set exactly one of labelSelector or secretName.
items:
description: SecretBinding describes a secret or class of
secrets to bind to the pipeline SA.
properties:
labelSelector:
description: LabelSelector selects secrets by label.
All matching secrets in a namespace are bound.
properties:
matchExpressions:
items:
properties:
key:
type: string
operator:
type: string
values:
items:
type: string
type: array
required:
- key
- operator
type: object
type: array
matchLabels:
additionalProperties:
type: string
type: object
type: object
secretName:
description: SecretName binds a specific named secret
in each namespace to the pipeline SA.
type: string
type: object
type: array
type: object
type: object
type: object
profile:
Expand Down
2 changes: 1 addition & 1 deletion config/openshift/base/operator.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ spec:
image: ko://github.com/tektoncd/operator/cmd/openshift/operator
args:
- "-controllers"
- "tektonconfig,tektonpipeline,tektontrigger,tektonchain,tektonaddon,tektonresult,openshiftpipelinesascode,manualapprovalgate,tektonpruner,tektonkueue,tektonmulticlusterproxyaae,syncerservice"
- "tektonconfig,tektonpipeline,tektontrigger,tektonchain,tektonaddon,tektonresult,openshiftpipelinesascode,manualapprovalgate,tektonpruner,tektonkueue,tektonmulticlusterproxyaae,syncerservice,namespacesync"
- "-unique-process-name"
- "tekton-operator-lifecycle"
imagePullPolicy: Always
Expand Down
131 changes: 131 additions & 0 deletions docs/TektonConfig.md
Original file line number Diff line number Diff line change
Expand Up @@ -632,6 +632,137 @@ In the deployment the environment name will be converted as follows,
- `tekton-hub-api` => `TEKTON_HUB_API`
- `artifact-hub-api` => `ARTIFACT_HUB_API`

### NamespaceSync (OpenShift only)

The `namespaceSync` block under `spec.platforms.openshift` controls the **NamespaceSyncController**, which watches every user namespace and ensures Tekton-required resources are present and up to date. It replaces the legacy per-namespace batch loop that was part of the RBAC reconciler.

#### Resources managed per namespace

| Resource | Kind | Purpose |
|---|---|---|
| `pipeline` | `ServiceAccount` | Identity for PipelineRun pods |
| `pipelines-scc-rolebinding` | `RoleBinding` → `pipelines-scc-clusterrole` | Grants the pipeline SA permission to use the default SCC |
| `openshift-pipelines-edit` | `RoleBinding` → `ClusterRole/edit` | Gives the pipeline SA edit access within its namespace |
| `config-trusted-cabundle` | `ConfigMap` | CA bundle for custom/internal PKI trust |
| `config-service-cabundle` | `ConfigMap` | OpenShift service CA bundle |
| `openshift-pipelines-clusterinterceptors` | `ClusterRoleBinding` subject | Lets the pipeline SA call ClusterInterceptors |

#### Configuration fields

```yaml
spec:
platforms:
openshift:
namespaceSync:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jkhelil Any specific reason why we allow user's to make these choices for all these reconciliations? In legacy batch RBAC mode users/admins did not have the option to manually intervene this behavior. If we still consider manual intervention is required, could you consider addressing the following concerns:

  1. namespaceSelector misconfig fails silently,

A typo or malformed selector turns provisioning OFF everywhere. When the selector can't be parsed, namespaceMatchesSelector returns false (match nothing). So a small YAML mistake means every new namespace silently gets no pipeline SA, no SCC binding, no CA bundles — and pipelines there fail with permission errors. TektonConfig still shows Ready, so there's no hint anything is wrong.

  1. {} means the opposite of standard Kubernetes.
    namespaceSelector: {} means "match nothing" here, but in every other Kubernetes API an empty selector means "match everything." Someone will almost certainly write {} expecting "all namespaces" and get the exact opposite.

The current design hardens only one direction, "a typo can't accidentally widen sync to the whole cluster" but leaves the more likely mistake (accidentally turning everything off) both easy to hit and invisible.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks @anithapriyanatarajan
1.and 2 fixed
the reason for adding this is to avoid watching selected namespaces, eventually all, if the user dont want to opt in rbac provisioning through operator

createPipelineSA: true # create/maintain the pipeline SA
createSCCRoleBinding: true # create/maintain pipelines-scc-rolebinding
createEditRoleBinding: true # create/maintain openshift-pipelines-edit
createCABundles: true # inject CA bundle ConfigMaps

# Optional: restrict which namespaces are synced.
# Omit entirely (or set to {}) to sync all non-system namespaces (default).
# Use matchLabels/matchExpressions to restrict to a subset.
namespaceSelector:
matchLabels:
pipelines.openshift.io/sync: "true"

# Optional: automatically bind secrets to the pipeline SA.
# Use secretName for an exact name, or labelSelector to match by label.
secretBindings:
- secretName: pipeline-quay-openshift # Quay Bridge robot account secret
- labelSelector:
matchLabels:
quay-integration: my-quay # all secrets with this label
```

All boolean fields default to `true` when the `namespaceSync` block is present.

#### Disabling individual features

Set the flag to `false` to stop managing that resource class. Existing resources
are **not deleted** — the controller simply stops reconciling them:

```yaml
spec:
platforms:
openshift:
namespaceSync:
createEditRoleBinding: false # do not create openshift-pipelines-edit
```

#### Restricting sync to specific namespaces

Use `namespaceSelector` to limit which namespaces the controller acts on.
Label namespaces you want synced, then configure the selector to match:

```bash
# Label a namespace to opt in
oc label namespace my-project pipelines.openshift.io/sync=true
```

```yaml
spec:
platforms:
openshift:
namespaceSync:
namespaceSelector:
matchLabels:
pipelines.openshift.io/sync: "true"
```

To disable sync for **all** namespaces while keeping the feature flags intact,
set all individual flags to `false`:

```yaml
namespaceSync:
createPipelineSA: false
createCABundles: false
createEditRoleBinding: false
createSCCRoleBinding: false
```

Or remove the `namespaceSync` field entirely to fall back to operator defaults.

#### Quay Bridge secret auto-binding

When the [Quay Bridge Operator](https://github.com/quay/quay-bridge-operator) is
installed, it creates a robot-account secret named `pipeline-quay-openshift` in
each namespace. Declare a `secretBinding` to have the NamespaceSyncController
automatically bind that secret to the `pipeline` SA as an image pull secret:

```yaml
spec:
platforms:
openshift:
namespaceSync:
secretBindings:
- secretName: pipeline-quay-openshift
```

Once configured:
- When the secret appears in a namespace it is added to both `imagePullSecrets`
and `secrets` on the `pipeline` SA within seconds.
- When the secret is deleted the reference is removed automatically.

#### Migration from legacy `spec.params`

Older releases controlled this behaviour through `spec.params` entries. These
are deprecated: the operator continues to honor them for backward
compatibility, but they should be migrated to the typed fields below. The
operator automatically migrates and persists them during the first
reconcile after an upgrade:

| Legacy `spec.params` | Typed field |
|---|---|
| `createRbacResource: "false"` | `createPipelineSA`, `createSCCRoleBinding`, `createEditRoleBinding` all set to `false` |
| `createCABundleConfigMaps: "false"` | `createCABundles: false` |
| `legacyPipelineRbac: "false"` | `createEditRoleBinding: false` |

After migration the legacy params are removed from `spec.params` and the typed
fields take effect. There is no need to manually update the TektonConfig CR.

---

### OpenShiftPipelinesAsCode

The PipelinesAsCode section allows you to customize the Pipelines as Code features on both Kubernetes and OpenShift. When you change the TektonConfig CR, the Operator automatically applies the settings to custom resources and configmaps in your installation. On Kubernetes, configure `spec.platforms.kubernetes.pipelinesAsCode` (the managed CR remains `OpenShiftPipelinesAsCode` for API compatibility).
Expand Down
80 changes: 80 additions & 0 deletions pkg/apis/operator/v1alpha1/openshift_platform.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ limitations under the License.

package v1alpha1

import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

type OpenShift struct {
// PipelinesAsCode allows configuring PipelinesAsCode configurations
// +optional
Expand Down Expand Up @@ -48,6 +50,84 @@ type OpenShift struct {
// Default: false (opt-in). Set to true to activate metrics mTLS.
// +optional
EnableMetricsMTLS *bool `json:"enableMetricsMTLS,omitempty"`
// NamespaceSync controls what the Tekton Operator synchronises into each
// user namespace on OpenShift (pipeline SA, CA bundles, edit RoleBinding,
// and registry secret bindings).
// +optional
NamespaceSync *NamespaceSyncConfig `json:"namespaceSync,omitempty"`
}

// NamespaceSyncConfig configures the NamespaceSyncController which watches
// user namespaces and ensures Tekton-required resources are present and up to date.
// All boolean fields default to true when the NamespaceSync block is present.
type NamespaceSyncConfig struct {
// CreatePipelineSA controls whether the pipeline ServiceAccount is created
// in each namespace. Disable only if you manage the pipeline SA externally.
// Replaces the legacy spec.params entry createRbacResource.
// Default: true
// +optional
CreatePipelineSA *bool `json:"createPipelineSA,omitempty"`

// CreateCABundles controls whether the CA bundle ConfigMaps
// (config-trusted-cabundle, config-service-cabundle) are injected into
// each namespace for TLS trust.
// Replaces the legacy spec.params entry createCABundleConfigMaps.
// Default: true
// +optional
CreateCABundles *bool `json:"createCABundles,omitempty"`

// CreateEditRoleBinding controls whether a RoleBinding named
// openshift-pipelines-edit is created in each namespace, binding the
// pipeline SA to the built-in edit ClusterRole. Set to false for
// least-privilege environments where PipelineRuns should not have
// broad write permissions in their namespace.
// Replaces the legacy spec.params entry legacyPipelineRbac.
// Default: true
// +optional
CreateEditRoleBinding *bool `json:"createEditRoleBinding,omitempty"`

// CreateSCCRoleBinding controls whether the pipelines-scc-rolebinding
// RoleBinding (and, when a namespace-level SCC is requested via the
// operator.tekton.dev/scc annotation, the pipelines-scc-role Role) is
// managed in each namespace. When enabled, the pipeline SA is granted
// permission to use the cluster-wide default SCC (pipelines-scc by
// default) or a namespace-specific SCC when the annotation is present.
// Default: true
// +optional
CreateSCCRoleBinding *bool `json:"createSCCRoleBinding,omitempty"`

// SecretBindings declares secrets that should be automatically bound to
// the pipeline SA in every namespace. When a secret matching a binding
// appears in a namespace it is added to both imagePullSecrets and secrets
// on the pipeline SA. When the secret is deleted the reference is removed.
// Each entry must set exactly one of labelSelector or secretName.
// +optional
SecretBindings []SecretBinding `json:"secretBindings,omitempty"`

// NamespaceSelector is an optional label selector that restricts which
// namespaces are synced. Follows standard Kubernetes label-selector
// semantics: when absent (nil) every non-system namespace is synced;
// an empty selector ({}) also matches every namespace; use
// matchLabels/matchExpressions to restrict sync to a subset of namespaces.
// To disable namespace sync entirely, set namespaceSync to null or set all
// individual feature flags (createPipelineSA, createCABundles, etc.) to false.
// +optional
NamespaceSelector *metav1.LabelSelector `json:"namespaceSelector,omitempty"`
}

// SecretBinding describes a secret (or class of secrets by label) that the
// NamespaceSyncController should bind to the pipeline SA in every namespace.
// Exactly one of LabelSelector or SecretName must be set.
type SecretBinding struct {
// LabelSelector selects secrets by label. All secrets matching this
// selector in a given namespace are bound to the pipeline SA.
// +optional
LabelSelector *metav1.LabelSelector `json:"labelSelector,omitempty"`

// SecretName binds a specific named secret in each namespace to the
// pipeline SA. The secret is bound when it exists and unbound when deleted.
// +optional
SecretName string `json:"secretName,omitempty"`
}

type SCC struct {
Expand Down
Loading
Loading