@@ -29,6 +29,7 @@ import (
2929 "github.com/tektoncd/operator/pkg/apis/operator/v1alpha1"
3030 "github.com/tektoncd/operator/pkg/client/clientset/versioned"
3131 "github.com/tektoncd/operator/pkg/reconciler/common"
32+ occommon "github.com/tektoncd/operator/pkg/reconciler/openshift/common"
3233 "github.com/tektoncd/operator/pkg/reconciler/shared/hash"
3334 "go.uber.org/zap"
3435 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -64,6 +65,15 @@ type consolePluginReconciler struct {
6465 operatorVersion string
6566 pipelinesConsolePluginImage string
6667 manifest mf.Manifest
68+ // tlsConfig holds the centrally resolved TLS profile (set on every reconcile).
69+ // nil means central TLS is disabled; the nginx.conf is left unmodified.
70+ tlsConfig * occommon.TLSEnvVars
71+ }
72+
73+ // SetTLSConfig stores the resolved central TLS configuration for use during the
74+ // next reconcile cycle. Call this before reconcile() on every reconcile loop.
75+ func (cpr * consolePluginReconciler ) SetTLSConfig (tlsEnvVars * occommon.TLSEnvVars ) {
76+ cpr .tlsConfig = tlsEnvVars
6777}
6878
6979// reconcile steps
@@ -169,6 +179,7 @@ func (cpr *consolePluginReconciler) updateOnce(ctx context.Context) {
169179 "environmentVariable" , PipelinesConsolePluginImageEnvironmentKey ,
170180 )
171181 }
182+
172183 })
173184}
174185
@@ -206,6 +217,8 @@ func (cpr *consolePluginReconciler) transform(ctx context.Context, manifest *mf.
206217 // updates "metadata.namespace" to targetNamespace
207218 common .ReplaceNamespace (tektonConfigCR .Spec .TargetNamespace ),
208219 cpr .transformerConsolePlugin (tektonConfigCR .Spec .TargetNamespace ),
220+ // Add nginx TLS configuration transformer
221+ cpr .transformerNginxTLS (),
209222 common .AddConfiguration (tektonConfigCR .Spec .Config ),
210223 }
211224
@@ -234,3 +247,106 @@ func (cpr *consolePluginReconciler) transformerConsolePlugin(targetNamespace str
234247 return unstructured .SetNestedField (u .Object , targetNamespace , "spec" , "backend" , "service" , "namespace" )
235248 }
236249}
250+
251+ // transformerNginxTLS updates the nginx.conf ConfigMap with TLS directives
252+ func (cpr * consolePluginReconciler ) transformerNginxTLS () mf.Transformer {
253+ return func (u * unstructured.Unstructured ) error {
254+ if u .GetKind () != "ConfigMap" || u .GetName () != "pipelines-console-plugin" {
255+ return nil
256+ }
257+
258+ // Get the current nginx.conf
259+ data , found , err := unstructured .NestedString (u .Object , "data" , "nginx.conf" )
260+ if err != nil || ! found {
261+ return err
262+ }
263+
264+ // Generate the updated nginx.conf with TLS directives
265+ updatedConf := cpr .generateNginxConfWithTLS (data )
266+
267+ // Set the updated nginx.conf back
268+ return unstructured .SetNestedField (u .Object , updatedConf , "data" , "nginx.conf" )
269+ }
270+ }
271+
272+ // generateNginxConfWithTLS injects TLS directives into nginx configuration
273+ func (cpr * consolePluginReconciler ) generateNginxConfWithTLS (baseConf string ) string {
274+ // Build TLS directives
275+ tlsDirectives := cpr .buildNginxTLSDirectives ()
276+
277+ // If no TLS directives to add, return original
278+ if tlsDirectives == "" {
279+ return baseConf
280+ }
281+
282+ // Inject TLS directives into the server block
283+ // Find "server {" and inject after it
284+ lines := strings .Split (baseConf , "\n " )
285+ var result strings.Builder
286+
287+ for _ , line := range lines {
288+ result .WriteString (line )
289+ result .WriteString ("\n " )
290+
291+ // After "server {", inject TLS directives
292+ if strings .Contains (line , "server {" ) {
293+ // Add TLS directives with proper indentation
294+ result .WriteString (tlsDirectives )
295+ }
296+ }
297+
298+ return result .String ()
299+ }
300+
301+ // buildNginxTLSDirectives generates nginx TLS directives from the centrally resolved
302+ // TLS profile. Returns an empty string when no TLS config is available.
303+ func (cpr * consolePluginReconciler ) buildNginxTLSDirectives () string {
304+ if cpr .tlsConfig == nil {
305+ return ""
306+ }
307+
308+ var directives strings.Builder
309+
310+ // ssl_protocols – derived from the minimum TLS version in the APIServer profile.
311+ // TLSEnvVars.MinVersion is in Go crypto/tls format: "1.2" or "1.3".
312+ if cpr .tlsConfig .MinVersion != "" {
313+ protocols := convertTLSVersionToNginx (cpr .tlsConfig .MinVersion )
314+ directives .WriteString (fmt .Sprintf (" ssl_protocols %s;\n " , protocols ))
315+ }
316+
317+ // NOTE: IANA cipher suite names (TLS_ECDHE_RSA_…) cannot be used directly in
318+ // nginx's ssl_ciphers directive (which uses OpenSSL names) or ssl_conf_command
319+ // (which uses a different format). Relying on nginx's own TLS 1.3 defaults is
320+ // simpler and equally secure; we intentionally skip cipher configuration here.
321+ if cpr .tlsConfig .CipherSuites != "" {
322+ cpr .logger .Debugw ("TLS cipher suites provided but not applied to nginx (using nginx defaults)" ,
323+ "reason" , "IANA names are not directly usable in nginx ssl_ciphers" ,
324+ )
325+ }
326+
327+ // ssl_ecdh_curve – comma-separated curve names become colon-separated for nginx.
328+ if cpr .tlsConfig .CurvePreferences != "" {
329+ curves := strings .ReplaceAll (cpr .tlsConfig .CurvePreferences , "," , ":" )
330+ directives .WriteString (fmt .Sprintf (" ssl_ecdh_curve %s;\n " , curves ))
331+ }
332+
333+ return directives .String ()
334+ }
335+
336+ // convertTLSVersionToNginx converts the Go crypto/tls minimum version string
337+ // ("1.2" or "1.3", as stored in TLSEnvVars.MinVersion) to the corresponding
338+ // nginx ssl_protocols value.
339+ func convertTLSVersionToNginx (minVersion string ) string {
340+ switch minVersion {
341+ case "1.3" :
342+ return "TLSv1.3"
343+ case "1.2" :
344+ return "TLSv1.2 TLSv1.3"
345+ case "1.1" :
346+ return "TLSv1.1 TLSv1.2 TLSv1.3"
347+ case "1.0" :
348+ return "TLSv1 TLSv1.1 TLSv1.2 TLSv1.3"
349+ default :
350+ return "TLSv1.2 TLSv1.3"
351+ }
352+ }
0 commit comments