Skip to content

Commit 4573cf5

Browse files
jkheliltekton-robot
authored andcommitted
Add centrally managed TLS configuration for console-plugin nginx
1 parent a4e8dba commit 4573cf5

3 files changed

Lines changed: 599 additions & 0 deletions

File tree

pkg/reconciler/openshift/tektonconfig/console_plugin_reconciler.go

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,15 @@ type consolePluginReconciler struct {
6565
operatorVersion string
6666
pipelinesConsolePluginImage string
6767
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
6877
}
6978

7079
// reconcile steps
@@ -184,6 +193,7 @@ func (cpr *consolePluginReconciler) updateOnce(ctx context.Context) {
184193
"environmentVariable", envKey,
185194
)
186195
}
196+
187197
})
188198
}
189199

@@ -221,6 +231,8 @@ func (cpr *consolePluginReconciler) transform(ctx context.Context, manifest *mf.
221231
// updates "metadata.namespace" to targetNamespace
222232
common.ReplaceNamespace(tektonConfigCR.Spec.TargetNamespace),
223233
cpr.transformerConsolePlugin(tektonConfigCR.Spec.TargetNamespace),
234+
// Add nginx TLS configuration transformer
235+
cpr.transformerNginxTLS(),
224236
common.AddConfiguration(tektonConfigCR.Spec.Config),
225237
}
226238

@@ -249,3 +261,113 @@ func (cpr *consolePluginReconciler) transformerConsolePlugin(targetNamespace str
249261
return unstructured.SetNestedField(u.Object, targetNamespace, "spec", "backend", "service", "namespace")
250262
}
251263
}
264+
265+
// transformerNginxTLS updates the nginx.conf ConfigMap with TLS directives
266+
func (cpr *consolePluginReconciler) transformerNginxTLS() mf.Transformer {
267+
return func(u *unstructured.Unstructured) error {
268+
if u.GetKind() != "ConfigMap" || u.GetName() != "pipelines-console-plugin" {
269+
return nil
270+
}
271+
272+
// Get the current nginx.conf
273+
data, found, err := unstructured.NestedString(u.Object, "data", "nginx.conf")
274+
if err != nil || !found {
275+
return err
276+
}
277+
278+
// Generate the updated nginx.conf with TLS directives
279+
updatedConf := cpr.generateNginxConfWithTLS(data)
280+
281+
// Set the updated nginx.conf back
282+
return unstructured.SetNestedField(u.Object, updatedConf, "data", "nginx.conf")
283+
}
284+
}
285+
286+
// generateNginxConfWithTLS injects TLS directives into nginx configuration.
287+
// Directives are always produced (ssl_protocols + ML-KEM ssl_conf_command) so
288+
// this function never returns the unmodified base configuration.
289+
func (cpr *consolePluginReconciler) generateNginxConfWithTLS(baseConf string) string {
290+
tlsDirectives := cpr.buildNginxTLSDirectives()
291+
292+
// Inject TLS directives into the server block
293+
// Find "server {" and inject after it
294+
lines := strings.Split(baseConf, "\n")
295+
var result strings.Builder
296+
297+
for _, line := range lines {
298+
result.WriteString(line)
299+
result.WriteString("\n")
300+
301+
// After "server {", inject TLS directives
302+
if strings.Contains(line, "server {") {
303+
// Add TLS directives with proper indentation
304+
result.WriteString(tlsDirectives)
305+
}
306+
}
307+
308+
return result.String()
309+
}
310+
311+
// buildNginxTLSDirectives generates nginx TLS directives from the centrally resolved
312+
// TLS profile. When no explicit profile is configured (cluster uses the "Default"
313+
// profile), secure Intermediate-equivalent defaults are applied so that PQC
314+
// directives are always present regardless of cluster configuration.
315+
func (cpr *consolePluginReconciler) buildNginxTLSDirectives() string {
316+
var directives strings.Builder
317+
318+
// ssl_protocols – derived from the minimum TLS version in the APIServer profile.
319+
// Fall back to "1.2" (Intermediate) when no central TLS config is present, which
320+
// is the OpenShift default for clusters without an explicit tlsSecurityProfile.
321+
minVersion := "1.2"
322+
if cpr.tlsConfig != nil && cpr.tlsConfig.MinVersion != "" {
323+
minVersion = cpr.tlsConfig.MinVersion
324+
}
325+
protocols := convertTLSVersionToNginx(minVersion)
326+
directives.WriteString(fmt.Sprintf(" ssl_protocols %s;\n", protocols))
327+
328+
// Always enable ML-KEM (X25519MLKEM768) hybrid key exchange for PQC readiness.
329+
// ssl_conf_command passes OpenSSL configuration directly and is the only nginx
330+
// mechanism that supports the post-quantum hybrid groups introduced in OpenSSL 3.x;
331+
// ssl_ecdh_curve does not cover these groups.
332+
// X25519MLKEM768 is tried first (PQC); X25519 is the classical fallback for
333+
// clients that do not yet support ML-KEM.
334+
directives.WriteString(" ssl_conf_command Groups X25519MLKEM768:X25519;\n")
335+
336+
// NOTE: IANA cipher suite names (TLS_ECDHE_RSA_…) cannot be used directly in
337+
// nginx's ssl_ciphers directive (which uses OpenSSL names) or ssl_conf_command
338+
// (which uses a different format). Relying on nginx's own TLS 1.3 defaults is
339+
// simpler and equally secure; we intentionally skip cipher configuration here.
340+
if cpr.tlsConfig != nil && cpr.tlsConfig.CipherSuites != "" {
341+
cpr.logger.Debugw("TLS cipher suites provided but not applied to nginx (using nginx defaults)",
342+
"reason", "IANA names are not directly usable in nginx ssl_ciphers",
343+
)
344+
}
345+
346+
// ssl_ecdh_curve – comma-separated curve names become colon-separated for nginx.
347+
// This covers TLS 1.2 classical curves; ML-KEM hybrid groups are handled above
348+
// via ssl_conf_command Groups.
349+
if cpr.tlsConfig != nil && cpr.tlsConfig.CurvePreferences != "" {
350+
curves := strings.ReplaceAll(cpr.tlsConfig.CurvePreferences, ",", ":")
351+
directives.WriteString(fmt.Sprintf(" ssl_ecdh_curve %s;\n", curves))
352+
}
353+
354+
return directives.String()
355+
}
356+
357+
// convertTLSVersionToNginx converts the Go crypto/tls minimum version string
358+
// ("1.2" or "1.3", as stored in TLSEnvVars.MinVersion) to the corresponding
359+
// nginx ssl_protocols value.
360+
func convertTLSVersionToNginx(minVersion string) string {
361+
switch minVersion {
362+
case "1.3":
363+
return "TLSv1.3"
364+
case "1.2":
365+
return "TLSv1.2 TLSv1.3"
366+
case "1.1":
367+
return "TLSv1.1 TLSv1.2 TLSv1.3"
368+
case "1.0":
369+
return "TLSv1 TLSv1.1 TLSv1.2 TLSv1.3"
370+
default:
371+
return "TLSv1.2 TLSv1.3"
372+
}
373+
}

0 commit comments

Comments
 (0)