Skip to content

Commit 064aa10

Browse files
committed
Wire TLS security profile through operator to service config.
Propagate the CR tlsSecurityProfile into generated olsconfig.yaml (with Intermediate defaults) so service endpoint TLS follows operator/user configuration, and add appserver coverage for default, modern, and custom profiles. Made-with: Cursor
1 parent d155f96 commit 064aa10

6 files changed

Lines changed: 119 additions & 8 deletions

File tree

internal/controller/appserver/assets.go

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,10 @@ import (
88
"slices"
99
"strings"
1010

11+
configv1 "github.com/openshift/api/config/v1"
12+
1113
"github.com/openshift/lightspeed-operator/internal/controller/reconciler"
14+
utiltls "github.com/openshift/lightspeed-operator/internal/tls"
1215

1316
monv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
1417
corev1 "k8s.io/api/core/v1"
@@ -284,6 +287,17 @@ func buildOLSConfig(r reconciler.Reconciler, ctx context.Context, cr *olsv1alpha
284287
ProxyConfig: proxyConfig,
285288
}
286289

290+
tlsProfileType := utiltls.DefaultTLSProfileType
291+
if cr.Spec.OLSConfig.TLSSecurityProfile != nil && cr.Spec.OLSConfig.TLSSecurityProfile.Type != "" {
292+
tlsProfileType = cr.Spec.OLSConfig.TLSSecurityProfile.Type
293+
}
294+
tlsProfileSpec := utiltls.GetTLSProfileSpec(cr.Spec.OLSConfig.TLSSecurityProfile)
295+
olsConfig.TLSSecurityProfile = &utils.TLSSecurityProfileConfig{
296+
ProfileType: serviceTLSProfileType(tlsProfileType),
297+
MinTLSVersion: utiltls.MinTLSVersion(tlsProfileSpec),
298+
Ciphers: utiltls.TLSCiphers(tlsProfileSpec),
299+
}
300+
287301
return olsConfig, nil
288302
}
289303

@@ -398,8 +412,6 @@ func GenerateOLSConfigMap(r reconciler.Reconciler, ctx context.Context, cr *olsv
398412
return nil, err
399413
}
400414

401-
// Add quota handlers configuration if specified
402-
// This configures rate limiting and token tracking for API usage
403415
if cr.Spec.OLSConfig.QuotaHandlersConfig != nil {
404416
olsConfig.QuotaHandlersConfig = &utils.QuotaHandlersConfig{
405417
Storage: postgresCacheConfig(r, cr),
@@ -888,6 +900,21 @@ func GenerateMetricsReaderSecret(r reconciler.Reconciler, cr *olsv1alpha1.OLSCon
888900
return secret, nil
889901
}
890902

903+
func serviceTLSProfileType(profileType configv1.TLSProfileType) string {
904+
switch profileType {
905+
case configv1.TLSProfileOldType:
906+
return "OldType"
907+
case configv1.TLSProfileIntermediateType:
908+
return "IntermediateType"
909+
case configv1.TLSProfileModernType:
910+
return "ModernType"
911+
case configv1.TLSProfileCustomType:
912+
return "Custom"
913+
default:
914+
return "IntermediateType"
915+
}
916+
}
917+
891918
func getQueryFilters(cr *olsv1alpha1.OLSConfig) []utils.QueryFilters {
892919
if cr.Spec.OLSConfig.QueryFilters == nil {
893920
return nil

internal/controller/appserver/assets_test.go

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
. "github.com/onsi/ginkgo/v2"
99
. "github.com/onsi/gomega"
1010
. "github.com/onsi/gomega/gstruct"
11+
configv1 "github.com/openshift/api/config/v1"
1112
monv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
1213
networkingv1 "k8s.io/api/networking/v1"
1314

@@ -104,6 +105,11 @@ var _ = Describe("App server assets", func() {
104105
TLSCertificatePath: path.Join(utils.OLSAppCertsMountRoot, utils.OLSCertsSecretName, "tls.crt"),
105106
TLSKeyPath: path.Join(utils.OLSAppCertsMountRoot, utils.OLSCertsSecretName, "tls.key"),
106107
},
108+
TLSSecurityProfile: &utils.TLSSecurityProfileConfig{
109+
ProfileType: "IntermediateType",
110+
MinTLSVersion: string(configv1.TLSProfiles[configv1.TLSProfileIntermediateType].MinTLSVersion),
111+
Ciphers: configv1.TLSProfiles[configv1.TLSProfileIntermediateType].Ciphers,
112+
},
107113
ReferenceContent: utils.ReferenceContent{
108114
EmbeddingsModelPath: "/app-root/embeddings_model",
109115
Indexes: []utils.ReferenceIndex{
@@ -154,6 +160,48 @@ var _ = Describe("App server assets", func() {
154160
utils.DeleteTelemetryPullSecret(ctx, k8sClient)
155161
})
156162

163+
It("should generate configmap with modern TLS security profile", func() {
164+
cr.Spec.OLSConfig.TLSSecurityProfile = &configv1.TLSSecurityProfile{
165+
Type: configv1.TLSProfileModernType,
166+
}
167+
cm, err := GenerateOLSConfigMap(testReconcilerInstance, context.TODO(), cr)
168+
Expect(err).NotTo(HaveOccurred())
169+
170+
var olsConfigMap map[string]interface{}
171+
err = yaml.Unmarshal([]byte(cm.Data[utils.OLSConfigFilename]), &olsConfigMap)
172+
Expect(err).NotTo(HaveOccurred())
173+
Expect(olsConfigMap).To(HaveKeyWithValue("ols_config", HaveKeyWithValue("tlsSecurityProfile", MatchKeys(Options(IgnoreExtras), Keys{
174+
"type": Equal("ModernType"),
175+
"minTLSVersion": Equal(string(configv1.TLSProfiles[configv1.TLSProfileModernType].MinTLSVersion)),
176+
}))))
177+
})
178+
179+
It("should generate configmap with custom TLS security profile", func() {
180+
cr.Spec.OLSConfig.TLSSecurityProfile = &configv1.TLSSecurityProfile{
181+
Type: configv1.TLSProfileCustomType,
182+
Custom: &configv1.CustomTLSProfile{
183+
TLSProfileSpec: configv1.TLSProfileSpec{
184+
MinTLSVersion: configv1.VersionTLS13,
185+
Ciphers: []string{
186+
"TLS_AES_128_GCM_SHA256",
187+
"TLS_AES_256_GCM_SHA384",
188+
},
189+
},
190+
},
191+
}
192+
cm, err := GenerateOLSConfigMap(testReconcilerInstance, context.TODO(), cr)
193+
Expect(err).NotTo(HaveOccurred())
194+
195+
var olsConfigMap map[string]interface{}
196+
err = yaml.Unmarshal([]byte(cm.Data[utils.OLSConfigFilename]), &olsConfigMap)
197+
Expect(err).NotTo(HaveOccurred())
198+
Expect(olsConfigMap).To(HaveKeyWithValue("ols_config", HaveKeyWithValue("tlsSecurityProfile", MatchKeys(Options(IgnoreExtras), Keys{
199+
"type": Equal("Custom"),
200+
"minTLSVersion": Equal("VersionTLS13"),
201+
"ciphers": ContainElements("TLS_AES_128_GCM_SHA256", "TLS_AES_256_GCM_SHA384"),
202+
}))))
203+
})
204+
157205
It("should generate configmap with queryFilters", func() {
158206
crWithFilters := utils.WithQueryFilters(cr)
159207
cm, err := GenerateOLSConfigMap(testReconcilerInstance, context.TODO(), crWithFilters)
@@ -1237,6 +1285,19 @@ ols_config:
12371285
- product_docs_index_id: ocp-product-docs-` + major + `_` + minor + `
12381286
product_docs_index_path: /app-root/vector_db/ocp_product_docs/` + major + `.` + minor + `
12391287
product_docs_origin: Red Hat OpenShift 123.456 documentation
1288+
tlsSecurityProfile:
1289+
ciphers:
1290+
- TLS_AES_128_GCM_SHA256
1291+
- TLS_AES_256_GCM_SHA384
1292+
- TLS_CHACHA20_POLY1305_SHA256
1293+
- ECDHE-ECDSA-AES128-GCM-SHA256
1294+
- ECDHE-RSA-AES128-GCM-SHA256
1295+
- ECDHE-ECDSA-AES256-GCM-SHA384
1296+
- ECDHE-RSA-AES256-GCM-SHA384
1297+
- ECDHE-ECDSA-CHACHA20-POLY1305
1298+
- ECDHE-RSA-CHACHA20-POLY1305
1299+
minTLSVersion: VersionTLS12
1300+
type: IntermediateType
12401301
tls_config:
12411302
tls_certificate_path: /etc/certs/lightspeed-tls/tls.crt
12421303
tls_key_path: /etc/certs/lightspeed-tls/tls.key
@@ -1297,6 +1358,19 @@ ols_config:
12971358
- product_docs_index_id: ocp-product-docs-` + major + `_` + minor + `
12981359
product_docs_index_path: /app-root/vector_db/ocp_product_docs/` + major + `.` + minor + `
12991360
product_docs_origin: Red Hat OpenShift 123.456 documentation
1361+
tlsSecurityProfile:
1362+
ciphers:
1363+
- TLS_AES_128_GCM_SHA256
1364+
- TLS_AES_256_GCM_SHA384
1365+
- TLS_CHACHA20_POLY1305_SHA256
1366+
- ECDHE-ECDSA-AES128-GCM-SHA256
1367+
- ECDHE-RSA-AES128-GCM-SHA256
1368+
- ECDHE-ECDSA-AES256-GCM-SHA384
1369+
- ECDHE-RSA-AES256-GCM-SHA384
1370+
- ECDHE-ECDSA-CHACHA20-POLY1305
1371+
- ECDHE-RSA-CHACHA20-POLY1305
1372+
minTLSVersion: VersionTLS12
1373+
type: IntermediateType
13001374
tls_config:
13011375
tls_certificate_path: /etc/certs/lightspeed-tls/tls.crt
13021376
tls_key_path: /etc/certs/lightspeed-tls/tls.key

internal/controller/appserver/deployment.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ import (
2323
"github.com/openshift/lightspeed-operator/internal/controller/utils"
2424
)
2525

26-
2726
func getOLSServerResources(cr *olsv1alpha1.OLSConfig) *corev1.ResourceRequirements {
2827
return utils.GetResourcesOrDefault(
2928
cr.Spec.OLSConfig.DeploymentConfig.APIContainer.Resources,
@@ -496,7 +495,7 @@ func GenerateOLSDeployment(r reconciler.Reconciler, cr *olsv1alpha1.OLSConfig) (
496495
Image: r.GetOpenShiftMCPServerImage(),
497496
ImagePullPolicy: corev1.PullIfNotPresent,
498497
SecurityContext: utils.RestrictedContainerSecurityContext(),
499-
VolumeMounts: []corev1.VolumeMount{configMount},
498+
VolumeMounts: []corev1.VolumeMount{configMount},
500499
Command: []string{
501500
"/openshift-mcp-server",
502501
"--read-only",

internal/controller/console/deployment.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ func GenerateConsoleUIDeployment(r reconciler.Reconciler, cr *olsv1alpha1.OLSCon
5858
Protocol: corev1.ProtocolTCP,
5959
},
6060
},
61-
SecurityContext: utils.RestrictedContainerSecurityContext(),
61+
SecurityContext: utils.RestrictedContainerSecurityContext(),
6262
ImagePullPolicy: corev1.PullAlways,
6363
Env: utils.GetProxyEnvVars(),
6464
Resources: *resources,

internal/controller/postgres/deployment.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -205,9 +205,9 @@ func GeneratePostgresDeployment(r reconciler.Reconciler, ctx context.Context, cr
205205
Protocol: corev1.ProtocolTCP,
206206
},
207207
},
208-
SecurityContext: utils.RestrictedContainerSecurityContext(),
209-
VolumeMounts: volumeMounts,
210-
Resources: *databaseResources,
208+
SecurityContext: utils.RestrictedContainerSecurityContext(),
209+
VolumeMounts: volumeMounts,
210+
Resources: *databaseResources,
211211
Env: []corev1.EnvVar{
212212
{
213213
Name: "POSTGRESQL_USER",

internal/controller/utils/types.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,8 @@ type OLSConfig struct {
165165
ConversationCache ConversationCacheConfig `json:"conversation_cache,omitempty"`
166166
// TLS configuration
167167
TLSConfig TLSConfig `json:"tls_config,omitempty"`
168+
// TLS security profile for service endpoint
169+
TLSSecurityProfile *TLSSecurityProfileConfig `json:"tlsSecurityProfile,omitempty"`
168170
// Query filters
169171
QueryFilters []QueryFilters `json:"query_filters,omitempty"`
170172
// Reference content for RAG
@@ -187,6 +189,15 @@ type OLSConfig struct {
187189
ToolsApproval *ToolsApprovalConfig `json:"tools_approval,omitempty"`
188190
}
189191

192+
type TLSSecurityProfileConfig struct {
193+
// Profile type expected by the service (OldType, IntermediateType, ModernType, Custom)
194+
ProfileType string `json:"type,omitempty"`
195+
// Minimum TLS protocol version (VersionTLS12, VersionTLS13, ...)
196+
MinTLSVersion string `json:"minTLSVersion,omitempty"`
197+
// Allowed ciphers in OpenSSL format
198+
Ciphers []string `json:"ciphers,omitempty"`
199+
}
200+
190201
// ToolFilteringConfig defines configuration for tool filtering using hybrid RAG retrieval
191202
// The embedding model is not exposed as it's handled by the container image
192203
type ToolFilteringConfig struct {

0 commit comments

Comments
 (0)