Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 29 additions & 2 deletions internal/controller/appserver/assets.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ import (
"slices"
"strings"

configv1 "github.com/openshift/api/config/v1"

"github.com/openshift/lightspeed-operator/internal/controller/reconciler"
utiltls "github.com/openshift/lightspeed-operator/internal/tls"

monv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
corev1 "k8s.io/api/core/v1"
Expand Down Expand Up @@ -291,6 +294,17 @@ func buildOLSConfig(r reconciler.Reconciler, ctx context.Context, cr *olsv1alpha
ProxyConfig: proxyConfig,
}

tlsProfileType := utiltls.DefaultTLSProfileType
if cr.Spec.OLSConfig.TLSSecurityProfile != nil && cr.Spec.OLSConfig.TLSSecurityProfile.Type != "" {
tlsProfileType = cr.Spec.OLSConfig.TLSSecurityProfile.Type
}
tlsProfileSpec := utiltls.GetTLSProfileSpec(cr.Spec.OLSConfig.TLSSecurityProfile)
olsConfig.TLSSecurityProfile = &utils.TLSSecurityProfileConfig{
ProfileType: serviceTLSProfileType(tlsProfileType),
MinTLSVersion: utiltls.MinTLSVersion(tlsProfileSpec),
Ciphers: utiltls.TLSCiphers(tlsProfileSpec),
}

return olsConfig, nil
}

Expand Down Expand Up @@ -411,8 +425,6 @@ func GenerateOLSConfigMap(r reconciler.Reconciler, ctx context.Context, cr *olsv
return nil, err
}

// Add quota handlers configuration if specified
// This configures rate limiting and token tracking for API usage
if cr.Spec.OLSConfig.QuotaHandlersConfig != nil {
olsConfig.QuotaHandlersConfig = &utils.QuotaHandlersConfig{
Storage: postgresCacheConfig(r, cr),
Expand Down Expand Up @@ -901,6 +913,21 @@ func GenerateMetricsReaderSecret(r reconciler.Reconciler, cr *olsv1alpha1.OLSCon
return secret, nil
}

func serviceTLSProfileType(profileType configv1.TLSProfileType) string {
switch profileType {
case configv1.TLSProfileOldType:
return "OldType"
case configv1.TLSProfileIntermediateType:
return "IntermediateType"
case configv1.TLSProfileModernType:
return "ModernType"
case configv1.TLSProfileCustomType:
return "Custom"
default:
return "IntermediateType"
}
}

func getQueryFilters(cr *olsv1alpha1.OLSConfig) []utils.QueryFilters {
if cr.Spec.OLSConfig.QueryFilters == nil {
return nil
Expand Down
74 changes: 74 additions & 0 deletions internal/controller/appserver/assets_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
. "github.com/onsi/gomega/gstruct"
configv1 "github.com/openshift/api/config/v1"
monv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1"
networkingv1 "k8s.io/api/networking/v1"

Expand Down Expand Up @@ -104,6 +105,11 @@ var _ = Describe("App server assets", func() {
TLSCertificatePath: path.Join(utils.OLSAppCertsMountRoot, utils.OLSCertsSecretName, "tls.crt"),
TLSKeyPath: path.Join(utils.OLSAppCertsMountRoot, utils.OLSCertsSecretName, "tls.key"),
},
TLSSecurityProfile: &utils.TLSSecurityProfileConfig{
ProfileType: "IntermediateType",
MinTLSVersion: string(configv1.TLSProfiles[configv1.TLSProfileIntermediateType].MinTLSVersion),
Ciphers: configv1.TLSProfiles[configv1.TLSProfileIntermediateType].Ciphers,
},
ReferenceContent: utils.ReferenceContent{
EmbeddingsModelPath: "/app-root/embeddings_model",
Indexes: []utils.ReferenceIndex{
Expand Down Expand Up @@ -200,6 +206,48 @@ var _ = Describe("App server assets", func() {
Expect(olsconfigGenerated.LLMProviders[0].Models[0].Parameters.MaxTokensForResponse).To(Equal(0))
})

It("should generate configmap with modern TLS security profile", func() {
cr.Spec.OLSConfig.TLSSecurityProfile = &configv1.TLSSecurityProfile{
Type: configv1.TLSProfileModernType,
}
cm, err := GenerateOLSConfigMap(testReconcilerInstance, context.TODO(), cr)
Expect(err).NotTo(HaveOccurred())

var olsConfigMap map[string]interface{}
err = yaml.Unmarshal([]byte(cm.Data[utils.OLSConfigFilename]), &olsConfigMap)
Expect(err).NotTo(HaveOccurred())
Expect(olsConfigMap).To(HaveKeyWithValue("ols_config", HaveKeyWithValue("tlsSecurityProfile", MatchKeys(Options(IgnoreExtras), Keys{
"type": Equal("ModernType"),
"minTLSVersion": Equal(string(configv1.TLSProfiles[configv1.TLSProfileModernType].MinTLSVersion)),
}))))
})

It("should generate configmap with custom TLS security profile", func() {
cr.Spec.OLSConfig.TLSSecurityProfile = &configv1.TLSSecurityProfile{
Type: configv1.TLSProfileCustomType,
Custom: &configv1.CustomTLSProfile{
TLSProfileSpec: configv1.TLSProfileSpec{
MinTLSVersion: configv1.VersionTLS13,
Ciphers: []string{
"TLS_AES_128_GCM_SHA256",
"TLS_AES_256_GCM_SHA384",
},
},
},
}
cm, err := GenerateOLSConfigMap(testReconcilerInstance, context.TODO(), cr)
Expect(err).NotTo(HaveOccurred())

var olsConfigMap map[string]interface{}
err = yaml.Unmarshal([]byte(cm.Data[utils.OLSConfigFilename]), &olsConfigMap)
Expect(err).NotTo(HaveOccurred())
Expect(olsConfigMap).To(HaveKeyWithValue("ols_config", HaveKeyWithValue("tlsSecurityProfile", MatchKeys(Options(IgnoreExtras), Keys{
"type": Equal("Custom"),
"minTLSVersion": Equal("VersionTLS13"),
"ciphers": ContainElements("TLS_AES_128_GCM_SHA256", "TLS_AES_256_GCM_SHA384"),
}))))
})

It("should generate configmap with queryFilters", func() {
crWithFilters := utils.WithQueryFilters(cr)
cm, err := GenerateOLSConfigMap(testReconcilerInstance, context.TODO(), crWithFilters)
Expand Down Expand Up @@ -1283,6 +1331,19 @@ ols_config:
- product_docs_index_id: ocp-product-docs-` + major + `_` + minor + `
product_docs_index_path: /app-root/vector_db/ocp_product_docs/` + major + `.` + minor + `
product_docs_origin: Red Hat OpenShift 123.456 documentation
tlsSecurityProfile:
ciphers:
- TLS_AES_128_GCM_SHA256
- TLS_AES_256_GCM_SHA384
- TLS_CHACHA20_POLY1305_SHA256
- ECDHE-ECDSA-AES128-GCM-SHA256
- ECDHE-RSA-AES128-GCM-SHA256
- ECDHE-ECDSA-AES256-GCM-SHA384
- ECDHE-RSA-AES256-GCM-SHA384
- ECDHE-ECDSA-CHACHA20-POLY1305
- ECDHE-RSA-CHACHA20-POLY1305
minTLSVersion: VersionTLS12
type: IntermediateType
tls_config:
tls_certificate_path: /etc/certs/lightspeed-tls/tls.crt
tls_key_path: /etc/certs/lightspeed-tls/tls.key
Expand Down Expand Up @@ -1343,6 +1404,19 @@ ols_config:
- product_docs_index_id: ocp-product-docs-` + major + `_` + minor + `
product_docs_index_path: /app-root/vector_db/ocp_product_docs/` + major + `.` + minor + `
product_docs_origin: Red Hat OpenShift 123.456 documentation
tlsSecurityProfile:
ciphers:
- TLS_AES_128_GCM_SHA256
- TLS_AES_256_GCM_SHA384
- TLS_CHACHA20_POLY1305_SHA256
- ECDHE-ECDSA-AES128-GCM-SHA256
- ECDHE-RSA-AES128-GCM-SHA256
- ECDHE-ECDSA-AES256-GCM-SHA384
- ECDHE-RSA-AES256-GCM-SHA384
- ECDHE-ECDSA-CHACHA20-POLY1305
- ECDHE-RSA-CHACHA20-POLY1305
minTLSVersion: VersionTLS12
type: IntermediateType
tls_config:
tls_certificate_path: /etc/certs/lightspeed-tls/tls.crt
tls_key_path: /etc/certs/lightspeed-tls/tls.key
Expand Down
11 changes: 11 additions & 0 deletions internal/controller/utils/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,8 @@ type OLSConfig struct {
ConversationCache ConversationCacheConfig `json:"conversation_cache,omitempty"`
// TLS configuration
TLSConfig TLSConfig `json:"tls_config,omitempty"`
// TLS security profile for service endpoint
TLSSecurityProfile *TLSSecurityProfileConfig `json:"tlsSecurityProfile,omitempty"`
// Query filters
QueryFilters []QueryFilters `json:"query_filters,omitempty"`
// Reference content for RAG
Expand All @@ -189,6 +191,15 @@ type OLSConfig struct {
ToolsApproval *ToolsApprovalConfig `json:"tools_approval,omitempty"`
}

type TLSSecurityProfileConfig struct {
// Profile type expected by the service (OldType, IntermediateType, ModernType, Custom)
ProfileType string `json:"type,omitempty"`
// Minimum TLS protocol version (VersionTLS12, VersionTLS13, ...)
MinTLSVersion string `json:"minTLSVersion,omitempty"`
// Allowed ciphers in OpenSSL format
Ciphers []string `json:"ciphers,omitempty"`
}

// ToolFilteringConfig defines configuration for tool filtering using hybrid RAG retrieval
// The embedding model is not exposed as it's handled by the container image
type ToolFilteringConfig struct {
Expand Down