Skip to content

WIP: Centralized TLS config#3225

Open
enarha wants to merge 2 commits intotektoncd:mainfrom
enarha:central-tls-config
Open

WIP: Centralized TLS config#3225
enarha wants to merge 2 commits intotektoncd:mainfrom
enarha:central-tls-config

Conversation

@enarha
Copy link
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

NONE

@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
Copy link
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
To complete the pull request process, please assign piyush-garg after the PR has been reviewed.
You can assign the PR to them by writing /assign @piyush-garg in a comment when ready.

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/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
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
Member

jkhelil commented Feb 18, 2026

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

@@ -0,0 +1,229 @@
/*
Copyright 2024 The Tekton Authors

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

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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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?

@jkhelil
Copy link
Member

jkhelil commented Mar 2, 2026

@pratap0007 @anithapriyanatarajan @mbpavan Can you review please ?

enarha added 2 commits March 2, 2026 20:12
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
@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
@tekton-robot
Copy link
Contributor

@enarha: PR needs rebase.

Details

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. needs-rebase Indicates a PR cannot be merged because it has merge conflicts with HEAD. release-note-none Denotes a PR that doesnt merit a release note. 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.

4 participants