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
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export LOKI_OPERATOR_CHANNEL?=stable-6.4
IMAGE_LOGGING_VECTOR?=quay.io/openshift-logging/vector:v0.54.0
IMAGE_LOGFILEMETRICEXPORTER?=quay.io/openshift-logging/log-file-metric-exporter:latest
IMAGE_LOGGING_EVENTROUTER?=quay.io/openshift-logging/eventrouter:v0.5.0
IMAGE_TLS_SCANNER?=quay.io/openshift/tls-scanner:latest

REPLICAS?=0
export E2E_TEST_EXCLUDES?=flowcontrol
Expand Down Expand Up @@ -223,6 +224,7 @@ test-env: ## Echo test environment, useful for running tests outside of the Make
@echo \
RELATED_IMAGE_VECTOR=$(IMAGE_LOGGING_VECTOR) \
RELATED_IMAGE_LOG_FILE_METRIC_EXPORTER=$(IMAGE_LOGFILEMETRICEXPORTER) \
IMAGE_TLS_SCANNER=$(IMAGE_TLS_SCANNER) \

.PHONY: test-functional
test-functional: test-functional-benchmarker-vector
Expand Down Expand Up @@ -319,6 +321,7 @@ test-e2e: $(JUNITREPORT)
RELATED_IMAGE_VECTOR=$(IMAGE_LOGGING_VECTOR) \
RELATED_IMAGE_LOG_FILE_METRIC_EXPORTER=$(IMAGE_LOGFILEMETRICEXPORTER) \
IMAGE_LOGGING_EVENTROUTER=$(IMAGE_LOGGING_EVENTROUTER) \
IMAGE_TLS_SCANNER=$(IMAGE_TLS_SCANNER) \
EXCLUDES="$(E2E_TEST_EXCLUDES)" CLF_EXCLUDES="$(CLF_TEST_EXCLUDES)" LOG_LEVEL=3 hack/test-e2e-olm.sh

.PHONY: test-e2e-local
Expand All @@ -328,6 +331,7 @@ test-e2e-local: $(JUNITREPORT) deploy-image
RELATED_IMAGE_VECTOR=$(IMAGE_LOGGING_VECTOR) \
RELATED_IMAGE_LOG_FILE_METRIC_EXPORTER=$(IMAGE_LOGFILEMETRICEXPORTER) \
IMAGE_LOGGING_EVENTROUTER=$(IMAGE_LOGGING_EVENTROUTER) \
IMAGE_TLS_SCANNER=$(IMAGE_TLS_SCANNER) \
CLF_INCLUDES=$(CLF_TEST_INCLUDES) \
EXCLUDES=$(E2E_TEST_EXCLUDES) \
IMAGE_CLUSTER_LOGGING_OPERATOR=image-registry.openshift-image-registry.svc:5000/openshift/origin-cluster-logging-operator:$(CURRENT_BRANCH) \
Expand Down
3 changes: 2 additions & 1 deletion bundle/manifests/cluster-logging.clusterserviceversion.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ metadata:
categories: OpenShift Optional, Logging & Tracing, Observability
certified: "false"
containerImage: quay.io/openshift-logging/cluster-logging-operator:latest
createdAt: "2026-04-30T19:37:39Z"
createdAt: "2026-05-08T15:11:18Z"
description: The Red Hat OpenShift Logging Operator for OCP provides a means for
configuring and managing log collection and forwarding.
features.operators.openshift.io/cnf: "false"
Expand Down Expand Up @@ -2528,6 +2528,7 @@ spec:
kubectl.kubernetes.io/default-container: cluster-logging-operator
target.workload.openshift.io/management: '{"effect": "PreferredDuringScheduling"}'
labels:
app.kubernetes.io/name: cluster-logging-operator
control-plane: controller-manager
name: cluster-logging-operator
spec:
Expand Down
1 change: 1 addition & 0 deletions config/manager/manager.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ spec:
kubectl.kubernetes.io/default-container: cluster-logging-operator
target.workload.openshift.io/management: '{"effect": "PreferredDuringScheduling"}'
labels:
app.kubernetes.io/name: cluster-logging-operator
name: cluster-logging-operator
control-plane: controller-manager
spec:
Expand Down
2 changes: 1 addition & 1 deletion olm_deploy/scripts/env.sh
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ set -eou pipefail
LOGGING_VERSION=${LOGGING_VERSION:-6.1}

LOGGING_VECTOR_VERSION=${LOGGING_VECTOR_VERSION:-v0.54.0}
LOGGING_LOG_FILE_METRIC_EXPORTER_VERSION=${LOGGING_LOG_FILE_METRIC_EXPORTER_VERSION:-6.1}
LOGGING_LOG_FILE_METRIC_EXPORTER_VERSION=${LOGGING_LOG_FILE_METRIC_EXPORTER_VERSION:-latest}

LOGGING_IS=${LOGGING_IS:-openshift-logging}
export IMAGE_CLUSTER_LOGGING_OPERATOR_REGISTRY=${IMAGE_CLUSTER_LOGGING_OPERATOR_REGISTRY:-quay.io/${LOGGING_IS}/cluster-logging-operator-registry:${LOGGING_VERSION}}
Expand Down
217 changes: 217 additions & 0 deletions test/e2e/operator/tls/e2e_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
package tls

import (
"context"
"fmt"

clolog "github.com/ViaQ/logerr/v2/log/static"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
configv1 "github.com/openshift/api/config/v1"
obs "github.com/openshift/cluster-logging-operator/api/observability/v1"
"github.com/openshift/cluster-logging-operator/internal/constants"
internalruntime "github.com/openshift/cluster-logging-operator/internal/runtime"
obsruntime "github.com/openshift/cluster-logging-operator/internal/runtime/observability"
internaltls "github.com/openshift/cluster-logging-operator/internal/tls"
"github.com/openshift/cluster-logging-operator/internal/utils/sets"
"github.com/openshift/cluster-logging-operator/test/client"
framework "github.com/openshift/cluster-logging-operator/test/framework/e2e"
tlsscanner "github.com/openshift/cluster-logging-operator/test/framework/e2e/tls"
"github.com/openshift/cluster-logging-operator/test/helpers/loki"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
crclient "sigs.k8s.io/controller-runtime/pkg/client"
)

var _ = Describe("[E2E][Operator][TLS] TLS Scanner Validation", func() {
const (
forwarderName = "tls-test-collector"
)

var (
e2e *framework.E2ETestFramework
err error
k8sClient crclient.Client
profileSpec configv1.TLSProfileSpec
)

BeforeEach(func() {
e2e = framework.NewE2ETestFramework()

// Create a controller-runtime client with configv1 scheme for fetching APIServer TLS profile
// This matches the production scheme setup in cmd/main.go
scheme := runtime.NewScheme()
Expect(configv1.AddToScheme(scheme)).To(Succeed())
k8sClient, err = crclient.New(e2e.RestConfig, crclient.Options{Scheme: scheme})
Expect(err).To(BeNil())

tlsProfile, err := internaltls.FetchAPIServerTlsProfile(k8sClient)
Expect(err).To(BeNil(), "Failed to fetch APIServer TLS profile")

By("Fetching the cluster TLS profile")
profileSpec = internaltls.GetClusterTLSProfileSpec(tlsProfile)
clolog.Info("Cluster TLS Profile", "spec", profileSpec)
})

AfterEach(func() {
e2e.Cleanup()
}, framework.DefaultCleanUpTimeout)

var (
runTlsScanner = func(e2e *framework.E2ETestFramework, scanNS string) (results []tlsscanner.ScanResult, err error) {
By("Deploying TLS Scanner")
scanner := tlsscanner.NewScanner(e2e.KubeClient, &e2e.CleanupFns)
e2e.AddCleanup(func() error {
return e2e.KubeClient.BatchV1().Jobs(scanNS).Delete(context.TODO(), tlsscanner.Name, metav1.DeleteOptions{})
})
job, err := scanner.Deploy(scanNS, scanNS)
Expect(err).To(BeNil(), "Failed to deploy TLS Scanner")
Expect(job).NotTo(BeNil())

By("Waiting for TLS Scanner to complete")
err = scanner.WaitForCompletion(job, tlsscanner.JobTimeout)
Expect(err).To(BeNil(), "TLS Scanner job did not complete successfully. It may not have matched any components to scan")

By("Retrieving TLS scan results")
results, err = scanner.GetResults(job)
Expect(err).To(BeNil(), "Failed to retrieve TLS scan results")
Expect(results).NotTo(BeEmpty(), "TLS Scanner returned no results")
return results, err
}

verifyResultsHaveComponents = func(results []tlsscanner.ScanResult, epxComponents ...string) {
components := sets.NewString()
for _, result := range results {
components.Insert(result.Component)
}
Expect(components.List()).To(ConsistOf(epxComponents))
}
)

Context("when inspecting deployed ClusterLogForwarder", func() {

var (
testNS string
clf *obs.ClusterLogForwarder
l *loki.Receiver
sa *corev1.ServiceAccount
)

BeforeEach(func() {

testNS = e2e.CreateTestNamespace(func(namespace *corev1.Namespace) {
namespace.Labels = map[string]string{
"pod-security.kubernetes.io/audit": "privileged",
"pod-security.kubernetes.io/enforce": "privileged",
"pod-security.kubernetes.io/warn": "privileged",
}
})

// Create service account for the collector with permissions for application and infrastructure logs
sa, err = e2e.BuildAuthorizationFor(testNS, forwarderName).
AllowClusterRole(framework.ClusterRoleCollectApplicationLogs).
AllowClusterRole(framework.ClusterRoleCollectInfrastructureLogs).
Create()
Expect(err).To(BeNil())

// Deploy Loki receiver
l = loki.NewReceiver(testNS, "loki-server")
Expect(l.Create(client.Get())).To(Succeed())

// Deploy ClusterLogForwarder with both default inputs and receiver inputs
// to ensure all input receiver types are running for TLS scanning
clf = obsruntime.NewClusterLogForwarder(testNS, forwarderName, internalruntime.Initialize, func(clf *obs.ClusterLogForwarder) {
clf.Spec.ServiceAccount.Name = sa.Name
clf.Spec.Inputs = []obs.InputSpec{
{
Name: "http-receiver",
Type: obs.InputTypeReceiver,
Receiver: &obs.ReceiverSpec{
Type: obs.ReceiverTypeHTTP,
Port: 8080,
HTTP: &obs.HTTPReceiver{
Format: obs.HTTPReceiverFormatKubeAPIAudit,
},
},
},
{
Name: "syslog-receiver",
Type: obs.InputTypeReceiver,
Receiver: &obs.ReceiverSpec{
Type: obs.ReceiverTypeSyslog,
Port: 10514,
},
},
}
clf.Spec.Outputs = []obs.OutputSpec{
{
Name: "loki-output",
Type: obs.OutputTypeLoki,
Loki: &obs.Loki{
URLSpec: obs.URLSpec{
URL: l.InternalURL("").String(),
},
},
},
}
clf.Spec.Pipelines = []obs.PipelineSpec{
{
Name: "test-app",
InputRefs: []string{string(obs.InputTypeApplication)},
OutputRefs: []string{"loki-output"},
},
{
Name: "test-receivers",
InputRefs: []string{"http-receiver", "syslog-receiver"},
OutputRefs: []string{"loki-output"},
},
}
})

if err := e2e.CreateObservabilityClusterLogForwarder(clf); err != nil {
Fail(fmt.Sprintf("Unable to create ClusterLogForwarder: %v", err))
}

if err := e2e.WaitForDaemonSet(clf.Namespace, clf.Name); err != nil {
Fail(fmt.Sprintf("Failed waiting for collector DaemonSet to be ready: %v", err))
}
})

It("should validate the TLS server configurations match the cluster TLS profile", func() {
results, _ := runTlsScanner(e2e, testNS)
clolog.Info("TLS Scanner found endpoints", "count", len(results))
clolog.V(2).Info("TLS endpoint scanned", "result", results)
verifyResultsHaveComponents(results, constants.VectorName)

By("Validating TLS compliance")
err = tlsscanner.ValidateCompliance(results, profileSpec)
Expect(err).To(BeNil(), "TLS compliance validation failed")
})
})

Context("when inspecting the operator and LogFileMetricExporter", func() {
It("should validate the TLS configurations matches the cluster TLS profile", func() {

// Deploy LFME
lfme := internalruntime.NewLogFileMetricExporter(constants.OpenshiftNS, constants.SingletonName)
e2e.AddCleanup(func() error {
return e2e.KubeClient.AppsV1().DaemonSets(constants.OpenshiftNS).Delete(context.TODO(), lfme.Name, metav1.DeleteOptions{})
})
if err := e2e.Create(lfme); err != nil {
Fail(fmt.Sprintf("Unable to create LogFileMetricExporter: %v", err))
}
if err := e2e.WaitForDaemonSet(lfme.Namespace, constants.LogfilesmetricexporterName); err != nil {
Fail(fmt.Sprintf("Failed waiting for lfme DaemonSet to be ready: %v", err))
}

results, _ := runTlsScanner(e2e, constants.OpenshiftNS)
clolog.Info("TLS Scanner found endpoints", "count", len(results))
verifyResultsHaveComponents(results, constants.ClusterLoggingOperator, constants.LogfilesmetricexporterName)

By("Validating TLS compliance")
err = tlsscanner.ValidateCompliance(results, profileSpec)
Expect(err).To(BeNil(), "TLS compliance validation failed")
})
})
})
13 changes: 13 additions & 0 deletions test/e2e/operator/tls/suite_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package tls

import (
"testing"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)

func TestSuite(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "[e2e][operator][tls] Suite")
}
19 changes: 14 additions & 5 deletions test/framework/e2e/framework.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,16 +177,22 @@ func (tc *E2ETestFramework) DeployCURLLogGeneratorWithNamespaceAndEndpoint(names
return client.Get().WaitFor(pod, client.PodRunning)
}

func (tc *E2ETestFramework) CreateTestNamespace() string {
return tc.CreateTestNamespaceWithPrefix("clo-test")
// CreateTestNamespace with a default prefix of 'clo-test'. Optionally include a list of functions to modify the object
// before it is created
func (tc *E2ETestFramework) CreateTestNamespace(visitors ...func(*corev1.Namespace)) string {
return tc.CreateTestNamespaceWithPrefix("clo-test", visitors...)
}

func (tc *E2ETestFramework) CreateTestNamespaceWithPrefix(prefix string) string {
// CreateTestNamespaceWithPrefix using the given prefix. Optionally include a list of functions to modify the object
// before it is created
func (tc *E2ETestFramework) CreateTestNamespaceWithPrefix(prefix string, visitors ...func(*corev1.Namespace)) string {
name := fmt.Sprintf("%s-%d", prefix, rand.Intn(10000)) //nolint:gosec
return tc.CreateNamespace(name)
return tc.CreateNamespace(name, visitors...)
}

func (tc *E2ETestFramework) CreateNamespace(name string) string {
// CreateNamespace using the given name. Optionally include a list of functions to modify the object
// before it is created
func (tc *E2ETestFramework) CreateNamespace(name string, visitors ...func(*corev1.Namespace)) string {
if value, found := os.LookupEnv("GENERATOR_NS"); found {
name = value
} else {
Expand All @@ -200,6 +206,9 @@ func (tc *E2ETestFramework) CreateNamespace(name string) string {
Name: name,
},
}
for _, visitor := range visitors {
visitor(namespace)
}

if err := tc.Test.Recreate(namespace); err != nil {
clolog.Error(err, "Error")
Expand Down
3 changes: 2 additions & 1 deletion test/framework/e2e/splunk.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ package e2e
import (
"context"
"fmt"
"github.com/openshift/cluster-logging-operator/internal/runtime"
"net/url"

"github.com/openshift/cluster-logging-operator/internal/runtime"

"github.com/openshift/cluster-logging-operator/internal/constants"
"github.com/openshift/cluster-logging-operator/internal/utils"
"github.com/openshift/cluster-logging-operator/test/helpers/oc"
Expand Down
Loading