Skip to content

Centralized TLS config#3225

Merged
tekton-robot merged 3 commits intotektoncd:mainfrom
enarha:central-tls-config
Apr 9, 2026
Merged

Centralized TLS config#3225
tekton-robot merged 3 commits intotektoncd:mainfrom
enarha:central-tls-config

Conversation

@enarha
Copy link
Copy Markdown
Contributor

@enarha enarha commented Feb 17, 2026

Changes

Submitter Checklist

These are the criteria that every PR should meet, please check them off as you
review them:

See the contribution guide for more details.

Release Notes

Add support for centralized TLS configuration on OpenShift. When
`enableCentralTLSConfig` is set to `true` in `TektonConfig.spec.platforms.openshift`,
Tekton components automatically inherit TLS settings (minimum version, cipher suites)
from the cluster's APIServer TLS security profile. Changes to the APIServer profile
are detected and propagated to components without manual intervention. TektonResult
is the first component to support this; other components will follow.

@tekton-robot tekton-robot added do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. release-note-none Denotes a PR that doesnt merit a release note. labels Feb 17, 2026
@tekton-robot tekton-robot added the size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files. label Feb 17, 2026
@enarha enarha mentioned this pull request Feb 17, 2026
4 tasks
@enarha
Copy link
Copy Markdown
Contributor Author

enarha commented Feb 17, 2026

This is still missing documentation, maybe add few more tests, but in general it's tested working and ready for review.

@enarha enarha force-pushed the central-tls-config branch 2 times, most recently from c641544 to bded46d Compare February 17, 2026 16:45
@jkhelil
Copy link
Copy Markdown
Member

jkhelil commented Feb 18, 2026

@enarha Please add PR deescrtipion with changes, architecture diagram,

@@ -0,0 +1,229 @@
/*
Copyright 2024 The Tekton Authors
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Question: Should it not be 2026?

@@ -0,0 +1,167 @@
/*
Copyright 2024 The Tekton Authors
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Same here.

@@ -0,0 +1,229 @@
/*
Copyright 2024 The Tekton Authors
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

s/2024/2026

@@ -0,0 +1,167 @@
/*
Copyright 2024 The Tekton Authors
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

s/2024/2026

// GetTLSEnvVarsFromAPIServer fetches the TLS security profile from the OpenShift APIServer
// resource and converts it to environment variable values that can be used by Tekton components.
// Returns nil if the APIServer has no TLS profile configured or if the shared lister is not initialized.
func GetTLSEnvVarsFromAPIServer(ctx context.Context, _ *rest.Config) (*TLSEnvVars, error) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Can we return tls.config here from crypto/tls
We Could need other configration in the future
We could use then func TLSEnvVarsFromConfig(cfg *tls.Config) *TLSEnvVars to turn it to envvars

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

We can. But we'll need to do the conversation twice APIServer string -> tls.Config -> env var strings instead of APIServer string -> env var strings. If you think we can immediately use the tls.Config with a specific consumer in mind (webhooks, nginx or whatever), then I'll follow your suggestion. If we do not have specific case immediately waiting for that, then I'll suggest we add this when we need it.
Please let me know what do you think.

recorder := events.NewLoggingEventRecorder("tekton-operator")
observedConfig, errs := apiserver.ObserveTLSSecurityProfile(listers, recorder, existingConfig)
if len(errs) > 0 {
logger.Warnf("Errors observing TLS security profile: %v", errs)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

should we return error here

Copy link
Copy Markdown
Contributor Author

@enarha enarha Feb 24, 2026

Choose a reason for hiding this comment

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

Good question. It is a matter of policy - what do we want to happen in the case of a failure. I encountered two types of errors. In the first case we are able to read the APIServer, but failed to populate the map existingConfig with values. It was a bug in the way library-go handles this case in the older version we use, which I fixed, thus we have that two level check. The second case is we fail to read the APIServer resource. If we return an error and bubble it up, we'll break the reconciliation of the operands (e.g. TektonResult). The current behavior is to log a warning, degrade the TLS funcitonality (centralized TLS configuration does not have an effect), but operands continue working. The question is if we prefer that harder or softer form of failure. I believe with the hard failure, the Tekton administrator can still disable the centralized TLS configuration by disabling it through the TektonConfig and if that's the case I'm inclined to agree with a hard failure. WDYT?


// If no TLS configuration is present, return nil
if minVersion == "" && len(cipherSuites) == 0 {
return nil, nil
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

should we log and return error ?

return &TLSEnvVars{
MinVersion: convertTLSVersionToEnvFormat(minVersion),
CipherSuites: strings.Join(cipherSuites, ","),
CurvePreferences: "", // Will be populated once openshift/api#2583 is merged
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

can we mention this in PR description openshift/api#2583
because empty curve preferences means go defaults


// convertTLSVersionToEnvFormat converts library-go TLS version format (VersionTLSxx) to
// the format expected by Go's crypto/tls (1.x)
func convertTLSVersionToEnvFormat(version string) string {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

We should consider parse TLSVversion to go format, webhook for example are expecting this in go native constant , I suppose the same thing for go apis using tls
https://github.com/knative/pkg/blob/main/webhook/webhook.go#L53

A conversion in this format feels more suitable to error prone constant
func parseTLSVersion(version string) (uint16, error) {
switch version {
case "VersionTLS10", "TLSv1.0":
return tls.VersionTLS10, nil
case "VersionTLS11", "TLSv1.1":
return tls.VersionTLS11, nil
case "VersionTLS12", "TLSv1.2":
return tls.VersionTLS12, nil
case "VersionTLS13", "TLSv1.3":
return tls.VersionTLS13, nil
default:
return 0, fmt.Errorf("unknown TLS version: %s", version)
}
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Switched to function which returns an error if unknown tls version is set through the apiserver record. Also split the retrieval of the tls configuration from the transformation. If we need to add more transformations in the future (e.g. to tsl.Config) we can do that without affecting existing code.

if oe.resolvedTLSConfig == nil {
return ""
}
return fmt.Sprintf("%s:%s:%s", oe.resolvedTLSConfig.MinVersion, oe.resolvedTLSConfig.CipherSuites, oe.resolvedTLSConfig.CurvePreferences)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

can we use a real hash function for the fingerprint like sha256, the ":" thingy cna be present in ciphers ro curves

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Ok first look, thaught that this function is calculating a hash, but hte hash is calculted in isntallerset code
mm I think the name is misleading here, could we called GetPlatformData rather than GetHash Data

}
}

// injectTLSConfig injects the TLS configuration as environment variables into the Results API deployment
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

this should be common i think

if err := setupAPIServerTLSWatch(ctx, ctrl); err != nil {
// On OpenShift clusters the APIServer resource should always exist.
// This env var is an escape hatch for edge cases and must be explicitly enabled.
if os.Getenv("SKIP_APISERVER_TLS_WATCH") == "true" {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

may be move this to a constant

@enarha enarha force-pushed the central-tls-config branch from bded46d to 2de7f83 Compare February 18, 2026 12:07
// and check with annotation, if they are same then we skip updating the object
// otherwise we update the manifest
specHash, err := hash.Compute(tr.Spec)
hashInput := struct {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This seems redudant and duplciate for all component
Can we have a common function that computes Hash give spec and common extension

Would make thing clear when redaing

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I kept it per component for now. Each component has specific deployments to update. I considered a separate function which takes a resource type (e.g. deployment/statefulset) and resource object (e.g. tekton-results-api), but it requires any type params and extra import of the common package, so I think for now the advantages are not much bigger than the disadvantages.

if oe.resolvedTLSConfig == nil {
return ""
}
return fmt.Sprintf("%s:%s:%s", oe.resolvedTLSConfig.MinVersion, oe.resolvedTLSConfig.CipherSuites, oe.resolvedTLSConfig.CurvePreferences)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Ok first look, thaught that this function is calculating a hash, but hte hash is calculted in isntallerset code
mm I think the name is misleading here, could we called GetPlatformData rather than GetHash Data

@enarha enarha force-pushed the central-tls-config branch 2 times, most recently from b744aba to 63a684f Compare February 26, 2026 15:59
@jkhelil
Copy link
Copy Markdown
Member

jkhelil commented Mar 2, 2026

@enarha can we add in this PR transformation for other components
we will need to inject tls env vars to pipeline,, pac, triggers,


### 3. Extension Interface Enhancement

- Added `GetHashData() string` method to the Extension interface
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

can you use the new function name GetPlatformData


// Wait for caches to sync
if !cache.WaitForCacheSync(ctx.Done(), apiServerInformer.Informer().HasSynced) {
logger.Warn("Failed to sync APIServer informer cache")
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

What happens if the cache is not synced (because of network issue or ai server not reachable), is the code safe on this ? We should probably retrigger a reconcile if cache is not synced, but that will be more complex as for now, let just verify code is safe nothing will panic just after, may be we need to add unit test

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

From what I see, nothing will panic if the cluster apiserver resource is not found in the cache. The reconciliation of the operand (e.g. tektonresult) will fail repeatedly though. There will be some very rapid reconcile retries with an exponential backoff. The same goes for the cache sync. The admin can still disable the central TLS configuration. If they opt-in into that feature, then I think louder failure without a panic makes sense. If you prefer we do not affect the operand reconciliation, then we can ignore that error and threat it like "no TLS config available" in the APIServer resource and just log some warning.

func ResolveCentralTLSToEnvVars(ctx context.Context, lister TektonConfigLister) (*TLSEnvVars, error) {
tc, err := lister.Get(v1alpha1.ConfigResourceName)
if err != nil {
return nil, nil
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Here we should propagate the error: failed to get tektonconfig

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

done.

}

// TLS 1.3 cipher suite names (IANA names)
tls13Ciphers := map[string]bool{
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

should we add this
As per this https://go.dev/blog/tls-cipher-suites#:~:text=Go%20does%20allow%20configuring%20cipher,order%20by%20default%2C%20unless%20Config.

ciphers are not configrable. with tls 1.3, because they are considered as safe
Now the issue if we add them here, that may procude issues, right ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The reason this was included in the first place is that the newer version of library-go does the same. They are commented out in the 2023 version, but in the newer ones they are not.
They are not configurable indeed and not required for golang based operands. But we have some non golang based dependencies like PostgreSQL and Nginx maybe more. I'm not sure how will these handle the 1.3 ciphers if we do not explicitly specify them. So that's one reason to include them. For Tekton Results we already have the code which handles the ciphers list and there the 1.3 ciphers are simply ignored. To me it makes more sense to keep these for now. WDYT?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Yes we can have the "ignore mecansim for our go apps" centralised, not just for results

@jkhelil
Copy link
Copy Markdown
Member

jkhelil commented Mar 2, 2026

@pratap0007 @anithapriyanatarajan @mbpavan Can you review please ?

@enarha enarha force-pushed the central-tls-config branch from 63a684f to 6137592 Compare March 2, 2026 18:58
@tekton-robot tekton-robot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Mar 4, 2026
@enarha enarha force-pushed the central-tls-config branch from 6137592 to 04296ed Compare March 9, 2026 10:52
@tekton-robot tekton-robot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Mar 9, 2026
@enarha enarha changed the title WIP: Centralized TLS config Centralized TLS config Mar 9, 2026
@tekton-robot tekton-robot removed the do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. label Mar 9, 2026
@enarha
Copy link
Copy Markdown
Contributor Author

enarha commented Mar 9, 2026

/hold
Waiting for more reviews and after getting the required approvals I'll do another cycle of e2e testing, thus the hold.

@tekton-robot tekton-robot added do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. labels Mar 9, 2026
@enarha enarha force-pushed the central-tls-config branch 2 times, most recently from 6f72622 to 485b2e0 Compare March 15, 2026 17:35
@tekton-robot tekton-robot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Mar 18, 2026
@enarha
Copy link
Copy Markdown
Contributor Author

enarha commented Mar 23, 2026

@anithapriyanatarajan @mbpavan any chance you could have a final look to this or lgtm ?

kind reminder.

@tekton-robot tekton-robot added the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Mar 27, 2026
@anithapriyanatarajan
Copy link
Copy Markdown
Contributor

@enarha - could you rebase this PR.

@enarha enarha force-pushed the central-tls-config branch from 7dcd289 to 6eb7fbb Compare March 30, 2026 17:26
@tekton-robot tekton-robot added needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. and removed needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. labels Mar 30, 2026
enarha added 3 commits April 1, 2026 22:33
Add support for centralized TLS configuration derived from the
OpenShift APIServer TLS security profile. This enables Tekton
components to inherit cluster-wide TLS settings (minimum version,
cipher suites) via the TektonConfig CR.

Key changes:
- Watch the APIServer resource for TLS profile changes and enqueue
  TektonConfig for reconciliation
- Add GetTLSProfileFromAPIServer and TLSEnvVarsFromProfile to extract
  and convert TLS profiles to environment variables
- Add ResolveCentralTLSToEnvVars and InjectTLSEnvVars as reusable
  helpers for component extensions
- Add EnableCentralTLSConfig flag in TektonConfig OpenShift platform
  spec (opt-in, default false)
- Add GetPlatformData to the Extension interface for platform-specific
  hash data (e.g., TLS config fingerprint)
- Add RBAC permissions for reading the APIServer resource

Note: curve preferences (CurvePreferences) are currently omitted and
default to Go's standard library values until openshift/api#2583 is
merged.

Assisted-by: Cursor
Activate the centralized TLS configuration infrastructure for the
TektonResult component:

- Resolve TLS config from APIServer via ResolveCentralTLSToEnvVars in PreReconcile
- Inject TLS env vars into the results-api deployment using the generic
  InjectTLSEnvVars transformer
- Include TLS config fingerprint in GetPlatformData for installer set
  hash computation, triggering updates on TLS profile changes
- Log injected TLS config at Info level for observability

Assisted-by: Cursor
Testing of the central TLS functionality requires full OpenShift cluster
(not ROSA, Hypershift) because it requires access to the APIServer
resource. This change adds testing plan and easy way to run the required
commands.
@enarha enarha force-pushed the central-tls-config branch from 6eb7fbb to 611010c Compare April 1, 2026 19:33
@tekton-robot tekton-robot removed the needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. label Apr 1, 2026
@jkhelil
Copy link
Copy Markdown
Member

jkhelil commented Apr 2, 2026

@anithapriyanatarajan @mbpavan any chance to have lgtm here ?

@anithapriyanatarajan
Copy link
Copy Markdown
Contributor

/hold

@tekton-robot tekton-robot added the do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. label Apr 9, 2026
@anithapriyanatarajan
Copy link
Copy Markdown
Contributor

@enarha marked to be on hold to check the possibility of refactoring the implementation to be inclusive of plain kubernetes users as well. Basically to check the option to have tektonconfig as central  to manage what TLS version and cipher suites to use. For Openshift, this gets populated by the API server CR watch and for Kubernetes, admins can manually configure as preferred. Thank you.

@enarha
Copy link
Copy Markdown
Contributor Author

enarha commented Apr 9, 2026

@enarha marked to be on hold to check the possibility of refactoring the implementation to be inclusive of plain kubernetes users as well. Basically to check the option to have tektonconfig as central  to manage what TLS version and cipher suites to use. For Openshift, this gets populated by the API server CR watch and for Kubernetes, admins can manually configure as preferred. Thank you.

Personally I'm against such approach until we get a clean evidence such requirement exists. That will complicate implementation and maintenance with no clear benefit (YAGNI). To be honest, before implementing it that way, I researched the topic (Kubernetes way of setting application configuration cluster wide) and found nothing specific, so I decided to stick to the current requirements. That also goes beyond the scope of Tekton, so I do not see how we can influence Kubernetes even if add support for it. That's IMO.

@anithapriyanatarajan
Copy link
Copy Markdown
Contributor

@enarha marked to be on hold to check the possibility of refactoring the implementation to be inclusive of plain kubernetes users as well. Basically to check the option to have tektonconfig as central  to manage what TLS version and cipher suites to use. For Openshift, this gets populated by the API server CR watch and for Kubernetes, admins can manually configure as preferred. Thank you.

Personally I'm against such approach until we get a clean evidence such requirement exists. That will complicate implementation and maintenance with no clear benefit (YAGNI). To be honest, before implementing it that way, I researched the topic (Kubernetes way of setting application configuration cluster wide) and found nothing specific, so I decided to stick to the current requirements. That also goes beyond the scope of Tekton, so I do not see how we can influence Kubernetes even if add support for it. That's IMO.

In its current form the variables (TLS_MIN_VERSION, TLS_CIPHER_SUITES, TLS_CURVE_PREFERENCES) are directly read from API server and Injected to Envars. This is tightly coupled to openshift API. My request is to have this stored to the tektonconfig CR and mark it as populated manually / automated. This way an admin gets an opportunity to override if required and also for kuberenetes plain version, admins can set this manually as required.  This way any other tekton components consumption model from Operator remains intact even if the source for reading the policy changes.

@anithapriyanatarajan
Copy link
Copy Markdown
Contributor

/hold cancel

@tekton-robot tekton-robot removed the do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. label Apr 9, 2026
@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

/ok-to-test

@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 Apr 9, 2026
@anithapriyanatarajan
Copy link
Copy Markdown
Contributor

@enarha - Thank you for the PR. Approving the changes limiting the scope of Cryptoagility to Openshift.

@anithapriyanatarajan
Copy link
Copy Markdown
Contributor

/lgtm

@tekton-robot tekton-robot added the lgtm Indicates that a PR is ready to be merged. label Apr 9, 2026
@tekton-robot tekton-robot merged commit fff9269 into tektoncd:main Apr 9, 2026
15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. kind/feature Categorizes issue or PR as related to a new feature. lgtm Indicates that a PR is ready to be merged. release-note Denotes a PR that will be considered when it comes time to generate release notes. size/XXL Denotes a PR that changes 1000+ lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants