Skip to content

feat(tls): centrally managed TLS for webhook and proxy-webhook (SRVKP-9612, SRVKP-9613)#3406

Open
jkhelil wants to merge 3 commits intotektoncd:mainfrom
jkhelil:SRVKP-9612
Open

feat(tls): centrally managed TLS for webhook and proxy-webhook (SRVKP-9612, SRVKP-9613)#3406
jkhelil wants to merge 3 commits intotektoncd:mainfrom
jkhelil:SRVKP-9612

Conversation

@jkhelil
Copy link
Copy Markdown
Member

@jkhelil jkhelil commented May 7, 2026

Changes

Implements centrally managed TLS for both the tekton-operator-webhook and
tekton-operator-proxy-webhook on OpenShift by inheriting the cluster-wide TLS
security profile from the OpenShift APIServer resource.

tekton-operator-webhook (fixes SRVKP-9612)

  • cmd/openshift/webhook/main.go: at startup, sets up an APIServer informer
    via the shared occommon.SetupAPIServerTLSWatch. Reads the current TLS
    profile with occommon.GetTLSProfileFromAPIServer + TLSEnvVarsFromProfile
    and injects WEBHOOK_TLS_MIN_VERSION and WEBHOOK_TLS_CIPHER_SUITES as
    process-level env vars before Knative bootstraps. On TLS profile change, the
    webhook calls os.Exit(1) so Kubernetes restarts it with the updated settings.

tekton-operator-proxy-webhook (fixes SRVKP-9613)

  • cmd/openshift/proxy-webhook/main.go: same pattern as the webhook above.
    signals.NewContext() is now called once in main() and reused throughout,
    avoiding a panic from double-initialisation of the signal handler.
    proxy.Getctx() is removed from controller.go — context setup is now
    inlined directly in main(), consistent with all other webhook binaries.
  • cmd/kubernetes/proxy-webhook/main.go: context setup also inlined; no TLS
    watch (Kubernetes-only binary).
  • cmd/openshift/operator/kodata/webhook/webhook.yaml: adds get/list/watch
    on apiservers.config.openshift.io to the tekton-operators-proxy-admin
    ClusterRole so the proxy webhook can read the TLS profile at startup.

Shared infrastructure

  • pkg/reconciler/openshift/common/apiserver_watch.go (new): extracts
    SetupAPIServerTLSWatch, APIServerTLSProfileChanged, and
    SkipAPIServerTLSWatch into a reusable package. Both the TektonConfig
    controller and the webhook binaries now call the same function.
  • pkg/reconciler/openshift/common/apiserver_watch_test.go (new): unit tests
    for APIServerTLSProfileChanged.
  • pkg/reconciler/openshift/tektonconfig/controller.go: simplified to delegate
    to occommon.SetupAPIServerTLSWatch; private tlsProfileChanged and
    customProfilesEqual functions removed.
  • pkg/reconciler/openshift/tektonpipeline/extension.go: adds
    common.ReplaceNamespaceInClusterRoleBinding to the OpenShift TektonPipeline
    extension transformers so the proxy-webhook ClusterRoleBinding subject
    namespace is correctly set to the target namespace (e.g. openshift-pipelines)
    instead of the static placeholder tekton-pipelines.

TLS version safety

WEBHOOK_TLS_MIN_VERSION is only set when the effective value is "1.2" or
"1.3". Profiles that permit older versions (e.g. the OpenShift Old profile
which uses VersionTLS10) are handled gracefully: the min-version env var is
skipped and Knative falls back to its safe default of TLS 1.2. Cipher suites
from the profile are still propagated in all cases.

Submitter Checklist

See the contribution guide for more details.

Release Notes

On OpenShift, the tekton-operator-webhook and tekton-operator-proxy-webhook now
inherit their TLS security settings (minimum TLS version and cipher suites) from
the cluster-wide OpenShift APIServer TLS security profile. Both webhooks restart
automatically when the profile changes so the new settings take effect immediately.

jkhelil and others added 2 commits May 7, 2026 12:36
… by webhook

Move setupAPIServerTLSWatch, tlsProfileChanged, and customProfilesEqual out of
the TektonConfig controller into pkg/reconciler/openshift/common as exported
functions (SetupAPIServerTLSWatch, APIServerTLSProfileChanged). Both the operator
controller and the webhook binary can now call the shared helper independently.

Also moves the SKIP_APISERVER_TLS_WATCH constant to occommon.SkipAPIServerTLSWatch
to avoid duplication between controller.go and the upcoming webhook main.go.

Co-authored-by: Cursor <cursoragent@cursor.com>
…nject as WEBHOOK_TLS_* env vars

At startup the webhook calls occommon.SetupAPIServerTLSWatch (the same helper
used by the TektonConfig controller) to initialise the shared APIServer lister
and register a watcher. When the cluster TLS profile changes the webhook exits
with code 1; Kubernetes restartPolicy: Always restarts it so the new instance
picks up the updated profile.

After the watch is set up, GetTLSProfileFromAPIServer + TLSEnvVarsFromProfile
convert the current profile into "1.2"/"1.3" + comma-separated IANA cipher
strings and inject them as WEBHOOK_TLS_MIN_VERSION / WEBHOOK_TLS_CIPHER_SUITES /
WEBHOOK_TLS_CURVE_PREFERENCES before Knative bootstraps. Knative's
DefaultConfigFromEnv("WEBHOOK_") inside webhook.New() picks them up automatically.

No changes to kwebhook.Options, Deployment manifests, or the Kubernetes webhook.

Co-authored-by: Cursor <cursoragent@cursor.com>
@tekton-robot tekton-robot added the do-not-merge/release-note-label-needed Indicates that a PR should not merge because it's missing one of the release note labels. label May 7, 2026
@tekton-robot tekton-robot requested review from khrm and mbpavan May 7, 2026 12:39
@tekton-robot
Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
To complete the pull request process, please ask for approval from jkhelil after the PR has been reviewed.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@tekton-robot tekton-robot added the size/XL Denotes a PR that changes 500-999 lines, ignoring generated files. label May 7, 2026
…tup, inject as WEBHOOK_TLS_* env vars

Same pattern as cmd/openshift/webhook/main.go: cfg and signalCtx are created
first, SetupAPIServerTLSWatch populates the shared lister and watches for TLS
profile changes (os.Exit(1) on change), then GetTLSProfileFromAPIServer +
TLSEnvVarsFromProfile inject WEBHOOK_TLS_* env vars before Knative bootstraps.

Both openshift and kubernetes proxy-webhook/main.go now inline the context setup
(namespace scope + kwebhook.WithOptions) directly, the same way the regular
webhooks do. proxy.Getctx() is removed from controller.go — it was only a thin
wrapper around signals.NewContext() + webhook.WithOptions and is no longer needed.

Co-authored-by: Cursor <cursoragent@cursor.com>
@tekton-robot tekton-robot added release-note Denotes a PR that will be considered when it comes time to generate release notes. and removed do-not-merge/release-note-label-needed Indicates that a PR should not merge because it's missing one of the release note labels. labels May 7, 2026
@jkhelil
Copy link
Copy Markdown
Member Author

jkhelil commented May 7, 2026

Cluster Evidence — TLS Profile Propagation

Tested on a live OpenShift cluster with the code from this PR.


Environment

APIServer cluster spec: {"audit":{"profile":"Default"}}
# spec.tlsSecurityProfile is nil → library-go resolves to Intermediate (TLS 1.2 min, strong ciphers)

1. RBAC — ClusterRole & ClusterRoleBinding

$ oc get clusterrole tekton-operators-proxy-admin -o yaml | grep -A4 "config.openshift.io"
  - apiGroups: ["config.openshift.io"]
    resources: ["apiservers"]
    verbs: ["get", "list", "watch"]

$ oc get clusterrolebinding tekton-operators-proxy-webhook-admin \
    -o jsonpath='name={.subjects[0].name} namespace={.subjects[0].namespace}'
name=tekton-operators-proxy-webhook namespace=openshift-pipelines

$ oc auth can-i get apiservers.config.openshift.io \
    --as=system:serviceaccount:openshift-pipelines:tekton-operators-proxy-webhook
yes

2. TLS Profile Propagated — both webhooks negotiate TLS 1.3

# proxy-webhook (openshift-pipelines namespace)
$ echo | openssl s_client -connect tekton-operator-proxy-webhook.openshift-pipelines.svc:443 2>&1 \
    | grep -E 'Protocol|Cipher|New,'
New, TLSv1.3, Cipher is TLS_AES_128_GCM_SHA256
Protocol: TLSv1.3
    Protocol  : TLSv1.3
    Cipher    : TLS_AES_128_GCM_SHA256

# operator-webhook (openshift-operators namespace)
$ echo | openssl s_client -connect tekton-operator-webhook.openshift-operators.svc:443 2>&1 \
    | grep -E 'Protocol|Cipher|New,'
New, TLSv1.3, Cipher is TLS_AES_128_GCM_SHA256
Protocol: TLSv1.3
    Protocol  : TLSv1.3
    Cipher    : TLS_AES_128_GCM_SHA256

Both webhooks negotiate TLS 1.3 / TLS_AES_128_GCM_SHA256, consistent with the
Intermediate profile which the Knative framework selects when WEBHOOK_TLS_MIN_VERSION
is set to "1.2" (Go's crypto/tls always prefers TLS 1.3 when the peer supports it).


3. Change Detection — webhook restarts on profile update

# Pods BEFORE patching APIServer to Intermediate (explicit)
tekton-operator-proxy-webhook-5d56599669-5xllx   1/1  Running  7 (29m ago)
tekton-operator-webhook-7f7b587766-x9tgt         1/1  Running  0 (23m ago)

# Patch applied
$ oc patch apiserver cluster --type=merge \
    -p '{"spec":{"tlsSecurityProfile":{"type":"Intermediate","intermediate":{}}}}'
apiserver.config.openshift.io/cluster patched

# Pods AFTER ~12 seconds — both restarted
tekton-operator-proxy-webhook-5d56599669-5xllx   1/1  Running  8 (12s ago)
tekton-operator-webhook-7f7b587766-x9tgt         1/1  Running  1 (14s ago)

Log lines from the previous run of each pod (captured via --previous):

# proxy-webhook
{"caller":"common/apiserver_watch.go:76","msg":"APIServer TLS security profile changed"}
2026/05/07 12:51:50 APIServer TLS profile changed — restarting proxy webhook to apply updated settings

# operator-webhook
{"caller":"common/apiserver_watch.go:76","msg":"APIServer TLS security profile changed"}
2026/05/07 12:51:50 APIServer TLS profile changed — restarting webhook to apply updated settings

Both webhooks detected the profile change via the shared SetupAPIServerTLSWatch
informer and exited cleanly (os.Exit(1)). Kubernetes restarted them and they came
back healthy within ~15 seconds, picking up the new TLS settings on startup.


4. Proxy webhook — actively serving admission requests

$ oc logs -n openshift-pipelines tekton-operator-proxy-webhook-... | grep -c ServeHTTP
137   # admission requests served during the test window

@anithapriyanatarajan
Copy link
Copy Markdown
Contributor

/kind enhancement

@tekton-robot
Copy link
Copy Markdown
Contributor

@anithapriyanatarajan: The label(s) kind/enhancement cannot be applied, because the repository doesn't have them.

Details

In response to this:

/kind enhancement

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes/test-infra repository.

@anithapriyanatarajan
Copy link
Copy Markdown
Contributor

/kind feature

@tekton-robot tekton-robot added the kind/feature Categorizes issue or PR as related to a new feature. label May 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

kind/feature Categorizes issue or PR as related to a new feature. release-note Denotes a PR that will be considered when it comes time to generate release notes. size/XL Denotes a PR that changes 500-999 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants