diff --git a/api/v1alpha1/flowcollector_webhook.go b/api/v1alpha1/flowcollector_webhook.go index 0d6a9dc63..e993f5ef8 100644 --- a/api/v1alpha1/flowcollector_webhook.go +++ b/api/v1alpha1/flowcollector_webhook.go @@ -57,6 +57,8 @@ func (r *FlowCollector) ConvertTo(dstRaw conversion.Hub) error { dst.Spec.Processor.Metrics.DisableAlerts = restored.Spec.Processor.Metrics.DisableAlerts } + dst.Spec.Loki.StatusTLS = restored.Spec.Loki.StatusTLS + return nil } @@ -100,3 +102,10 @@ func Convert_v1beta1_FlowCollectorFLP_To_v1alpha1_FlowCollectorFLP(in *v1beta1.F func Convert_v1beta1_FLPMetrics_To_v1alpha1_FLPMetrics(in *v1beta1.FLPMetrics, out *FLPMetrics, s apiconversion.Scope) error { return autoConvert_v1beta1_FLPMetrics_To_v1alpha1_FLPMetrics(in, out, s) } + +// This function need to be manually created because conversion-gen not able to create it intentionally because +// we have new defined fields in v1beta1 not in v1alpha1 +// nolint:golint,stylecheck,revive +func Convert_v1beta1_FlowCollectorLoki_To_v1alpha1_FlowCollectorLoki(in *v1beta1.FlowCollectorLoki, out *FlowCollectorLoki, s apiconversion.Scope) error { + return autoConvert_v1beta1_FlowCollectorLoki_To_v1alpha1_FlowCollectorLoki(in, out, s) +} diff --git a/api/v1alpha1/zz_generated.conversion.go b/api/v1alpha1/zz_generated.conversion.go index fbf944af9..f6d827c6e 100644 --- a/api/v1alpha1/zz_generated.conversion.go +++ b/api/v1alpha1/zz_generated.conversion.go @@ -193,11 +193,6 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } - if err := s.AddGeneratedConversionFunc((*v1beta1.FlowCollectorLoki)(nil), (*FlowCollectorLoki)(nil), func(a, b interface{}, scope conversion.Scope) error { - return Convert_v1beta1_FlowCollectorLoki_To_v1alpha1_FlowCollectorLoki(a.(*v1beta1.FlowCollectorLoki), b.(*FlowCollectorLoki), scope) - }); err != nil { - return err - } if err := s.AddGeneratedConversionFunc((*FlowCollectorSpec)(nil), (*v1beta1.FlowCollectorSpec)(nil), func(a, b interface{}, scope conversion.Scope) error { return Convert_v1alpha1_FlowCollectorSpec_To_v1beta1_FlowCollectorSpec(a.(*FlowCollectorSpec), b.(*v1beta1.FlowCollectorSpec), scope) }); err != nil { @@ -268,6 +263,11 @@ func RegisterConversions(s *runtime.Scheme) error { }); err != nil { return err } + if err := s.AddConversionFunc((*v1beta1.FlowCollectorLoki)(nil), (*FlowCollectorLoki)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1beta1_FlowCollectorLoki_To_v1alpha1_FlowCollectorLoki(a.(*v1beta1.FlowCollectorLoki), b.(*FlowCollectorLoki), scope) + }); err != nil { + return err + } return nil } @@ -823,14 +823,10 @@ func autoConvert_v1beta1_FlowCollectorLoki_To_v1alpha1_FlowCollectorLoki(in *v1b if err := Convert_v1beta1_ClientTLS_To_v1alpha1_ClientTLS(&in.TLS, &out.TLS, s); err != nil { return err } + // WARNING: in.StatusTLS requires manual conversion: does not exist in peer-type return nil } -// Convert_v1beta1_FlowCollectorLoki_To_v1alpha1_FlowCollectorLoki is an autogenerated conversion function. -func Convert_v1beta1_FlowCollectorLoki_To_v1alpha1_FlowCollectorLoki(in *v1beta1.FlowCollectorLoki, out *FlowCollectorLoki, s conversion.Scope) error { - return autoConvert_v1beta1_FlowCollectorLoki_To_v1alpha1_FlowCollectorLoki(in, out, s) -} - func autoConvert_v1alpha1_FlowCollectorSpec_To_v1beta1_FlowCollectorSpec(in *FlowCollectorSpec, out *v1beta1.FlowCollectorSpec, s conversion.Scope) error { out.Namespace = in.Namespace if err := Convert_v1alpha1_FlowCollectorAgent_To_v1beta1_FlowCollectorAgent(&in.Agent, &out.Agent, s); err != nil { diff --git a/api/v1beta1/flowcollector_types.go b/api/v1beta1/flowcollector_types.go index 819edde96..8ff0024b3 100644 --- a/api/v1beta1/flowcollector_types.go +++ b/api/v1beta1/flowcollector_types.go @@ -462,6 +462,7 @@ type FlowCollectorLoki struct { // This is useful to show error messages and some context in the frontend. // When using the Loki Operator, set it to the Loki HTTP query frontend service, for example // https://loki-query-frontend-http.netobserv.svc:3100/. + // statusTLS configuration will be used when statusUrl is set. StatusURL string `json:"statusUrl,omitempty"` //+kubebuilder:default:="netobserv" @@ -509,9 +510,13 @@ type FlowCollectorLoki struct { // staticLabels is a map of common labels to set on each flow. StaticLabels map[string]string `json:"staticLabels,omitempty"` - // tls client configuration. + // tls client configuration for loki URL. // +optional TLS ClientTLS `json:"tls"` + + // tls client configuration for loki status URL. + // +optional + StatusTLS ClientTLS `json:"statusTls"` } // FlowCollectorConsolePlugin defines the desired ConsolePlugin state of FlowCollector diff --git a/api/v1beta1/zz_generated.deepcopy.go b/api/v1beta1/zz_generated.deepcopy.go index 0bb0e8956..ad2bcc39f 100644 --- a/api/v1beta1/zz_generated.deepcopy.go +++ b/api/v1beta1/zz_generated.deepcopy.go @@ -402,6 +402,7 @@ func (in *FlowCollectorLoki) DeepCopyInto(out *FlowCollectorLoki) { } } out.TLS = in.TLS + out.StatusTLS = in.StatusTLS } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FlowCollectorLoki. diff --git a/bundle/manifests/flows.netobserv.io_flowcollectors.yaml b/bundle/manifests/flows.netobserv.io_flowcollectors.yaml index 13fdd65b4..ef3a18802 100644 --- a/bundle/manifests/flows.netobserv.io_flowcollectors.yaml +++ b/bundle/manifests/flows.netobserv.io_flowcollectors.yaml @@ -3363,6 +3363,71 @@ spec: description: staticLabels is a map of common labels to set on each flow. type: object + statusTls: + description: tls client configuration for loki status URL. + properties: + caCert: + description: caCert defines the reference of the certificate + for the Certificate Authority + properties: + certFile: + description: certFile defines the path to the certificate + file name within the config map or secret + type: string + certKey: + description: certKey defines the path to the certificate + private key file name within the config map or secret. + Omit when the key is not necessary. + type: string + name: + description: name of the config map or secret containing + certificates + type: string + type: + description: 'type for the certificate reference: "configmap" + or "secret"' + enum: + - configmap + - secret + type: string + type: object + enable: + default: false + description: enable TLS + type: boolean + insecureSkipVerify: + default: false + description: insecureSkipVerify allows skipping client-side + verification of the server certificate If set to true, CACert + field will be ignored + type: boolean + userCert: + description: userCert defines the user certificate reference, + used for mTLS (you can ignore it when using regular, one-way + TLS) + properties: + certFile: + description: certFile defines the path to the certificate + file name within the config map or secret + type: string + certKey: + description: certKey defines the path to the certificate + private key file name within the config map or secret. + Omit when the key is not necessary. + type: string + name: + description: name of the config map or secret containing + certificates + type: string + type: + description: 'type for the certificate reference: "configmap" + or "secret"' + enum: + - configmap + - secret + type: string + type: object + type: object statusUrl: description: statusURL specifies the address of the Loki /ready /metrics /config endpoints, in case it is different from the @@ -3370,6 +3435,7 @@ spec: This is useful to show error messages and some context in the frontend. When using the Loki Operator, set it to the Loki HTTP query frontend service, for example https://loki-query-frontend-http.netobserv.svc:3100/. + statusTLS configuration will be used when statusUrl is set. type: string tenantID: default: netobserv @@ -3383,7 +3449,7 @@ spec: limit. A Timeout of zero means no timeout. type: string tls: - description: tls client configuration. + description: tls client configuration for loki URL. properties: caCert: description: caCert defines the reference of the certificate diff --git a/bundle/manifests/netobserv-operator.clusterserviceversion.yaml b/bundle/manifests/netobserv-operator.clusterserviceversion.yaml index d9f8a3b5e..59e8339b4 100644 --- a/bundle/manifests/netobserv-operator.clusterserviceversion.yaml +++ b/bundle/manifests/netobserv-operator.clusterserviceversion.yaml @@ -282,6 +282,21 @@ metadata: "maxBackoff": "5s", "maxRetries": 2, "minBackoff": "1s", + "statusTls": { + "caCert": { + "certFile": "service-ca.crt", + "name": "loki-ca-bundle", + "type": "configmap" + }, + "enable": false, + "insecureSkipVerify": false, + "userCert": { + "certFile": "tls.crt", + "certKey": "tls.key", + "name": "loki-query-frontend-http", + "type": "secret" + } + }, "tls": { "caCert": { "certFile": "service-ca.crt", diff --git a/config/crd/bases/flows.netobserv.io_flowcollectors.yaml b/config/crd/bases/flows.netobserv.io_flowcollectors.yaml index 99c201e0d..9e1009774 100644 --- a/config/crd/bases/flows.netobserv.io_flowcollectors.yaml +++ b/config/crd/bases/flows.netobserv.io_flowcollectors.yaml @@ -3350,6 +3350,71 @@ spec: description: staticLabels is a map of common labels to set on each flow. type: object + statusTls: + description: tls client configuration for loki status URL. + properties: + caCert: + description: caCert defines the reference of the certificate + for the Certificate Authority + properties: + certFile: + description: certFile defines the path to the certificate + file name within the config map or secret + type: string + certKey: + description: certKey defines the path to the certificate + private key file name within the config map or secret. + Omit when the key is not necessary. + type: string + name: + description: name of the config map or secret containing + certificates + type: string + type: + description: 'type for the certificate reference: "configmap" + or "secret"' + enum: + - configmap + - secret + type: string + type: object + enable: + default: false + description: enable TLS + type: boolean + insecureSkipVerify: + default: false + description: insecureSkipVerify allows skipping client-side + verification of the server certificate If set to true, CACert + field will be ignored + type: boolean + userCert: + description: userCert defines the user certificate reference, + used for mTLS (you can ignore it when using regular, one-way + TLS) + properties: + certFile: + description: certFile defines the path to the certificate + file name within the config map or secret + type: string + certKey: + description: certKey defines the path to the certificate + private key file name within the config map or secret. + Omit when the key is not necessary. + type: string + name: + description: name of the config map or secret containing + certificates + type: string + type: + description: 'type for the certificate reference: "configmap" + or "secret"' + enum: + - configmap + - secret + type: string + type: object + type: object statusUrl: description: statusURL specifies the address of the Loki /ready /metrics /config endpoints, in case it is different from the @@ -3357,6 +3422,7 @@ spec: This is useful to show error messages and some context in the frontend. When using the Loki Operator, set it to the Loki HTTP query frontend service, for example https://loki-query-frontend-http.netobserv.svc:3100/. + statusTLS configuration will be used when statusUrl is set. type: string tenantID: default: netobserv @@ -3370,7 +3436,7 @@ spec: limit. A Timeout of zero means no timeout. type: string tls: - description: tls client configuration. + description: tls client configuration for loki URL. properties: caCert: description: caCert defines the reference of the certificate diff --git a/config/samples/flows_v1alpha1_flowcollector.yaml b/config/samples/flows_v1alpha1_flowcollector.yaml index 340bef399..4cf751bad 100644 --- a/config/samples/flows_v1alpha1_flowcollector.yaml +++ b/config/samples/flows_v1alpha1_flowcollector.yaml @@ -62,6 +62,7 @@ spec: loki: url: 'http://loki.netobserv.svc:3100/' # Uncomment lines below for typical installation with loki-operator (5.6+ needed) + # and ensure tls is enabled # url: 'https://loki-gateway-http.netobserv.svc:8080/api/logs/v1/network/' # statusUrl: 'https://loki-query-frontend-http.netobserv.svc:3100/' # authToken: HOST diff --git a/config/samples/flows_v1beta1_flowcollector.yaml b/config/samples/flows_v1beta1_flowcollector.yaml index 098c6cda9..5930fb606 100644 --- a/config/samples/flows_v1beta1_flowcollector.yaml +++ b/config/samples/flows_v1beta1_flowcollector.yaml @@ -66,9 +66,10 @@ spec: loki: url: 'http://loki.netobserv.svc:3100/' # Uncomment lines below for typical installation with loki-operator (5.6+ needed) + # and ensure tls and statusTls are enabled # url: 'https://loki-gateway-http.netobserv.svc:8080/api/logs/v1/network/' # statusUrl: 'https://loki-query-frontend-http.netobserv.svc:3100/' - # authToken: HOST + # authToken: FORWARD tls: enable: false caCert: @@ -76,6 +77,18 @@ spec: name: loki-gateway-ca-bundle certFile: service-ca.crt insecureSkipVerify: false + statusTls: + enable: false + caCert: + certFile: service-ca.crt + name: loki-ca-bundle + type: configmap + insecureSkipVerify: false + userCert: + certFile: tls.crt + certKey: tls.key + name: loki-query-frontend-http + type: secret batchWait: 1s batchSize: 10485760 minBackoff: 1s diff --git a/controllers/consoleplugin/consoleplugin_objects.go b/controllers/consoleplugin/consoleplugin_objects.go index 57a4dce84..23d01b3da 100644 --- a/controllers/consoleplugin/consoleplugin_objects.go +++ b/controllers/consoleplugin/consoleplugin_objects.go @@ -30,6 +30,7 @@ const configFile = "config.yaml" const configVolume = "config-volume" const configPath = "/opt/app-root/" const lokiCerts = "loki-certs" +const lokiStatusCerts = "loki-status-certs" const tokensPath = "/var/run/secrets/tokens/" type builder struct { @@ -181,9 +182,21 @@ func buildArgs(desired *flowslatest.FlowCollectorSpec) []string { if desired.Loki.TLS.InsecureSkipVerify { args = append(args, "-loki-skip-tls") } else { - args = append(args, "--loki-ca-path", helper.GetCACertPath(&desired.Loki.TLS, lokiCerts)) + args = append(args, "-loki-ca-path", helper.GetCACertPath(&desired.Loki.TLS, lokiCerts)) } } + + statusTLS := helper.GetLokiStatusTLS(&desired.Loki) + if statusTLS.Enable { + if statusTLS.InsecureSkipVerify { + args = append(args, "-loki-status-skip-tls") + } else { + args = append(args, "-loki-status-ca-path", helper.GetCACertPath(&statusTLS, lokiStatusCerts)) + args = append(args, "-loki-status-user-cert-path", helper.GetUserCertPath(&statusTLS, lokiStatusCerts)) + args = append(args, "-loki-status-user-key-path", helper.GetUserKeyPath(&statusTLS, lokiStatusCerts)) + } + } + if helper.LokiUseHostToken(&desired.Loki) { args = append(args, "-loki-token-path", tokenPath(&desired.Loki)) } @@ -226,6 +239,11 @@ func (b *builder) podTemplate(cmDigest string) *corev1.PodTemplateSpec { volumes, volumeMounts = helper.AppendCertVolumes(volumes, volumeMounts, &b.desired.Loki.TLS, lokiCerts, b.cWatcher) } + statusTLS := helper.GetLokiStatusTLS(&b.desired.Loki) + if b.desired != nil && statusTLS.Enable && !statusTLS.InsecureSkipVerify { + volumes, volumeMounts = helper.AppendCertVolumes(volumes, volumeMounts, &statusTLS, lokiStatusCerts, b.cWatcher) + } + if helper.LokiUseHostToken(&b.desired.Loki) { volumes, volumeMounts = helper.AppendTokenVolume(volumes, volumeMounts, constants.PluginName, constants.PluginName) } diff --git a/controllers/consoleplugin/consoleplugin_reconciler.go b/controllers/consoleplugin/consoleplugin_reconciler.go index 6cad122c5..8cde07b81 100644 --- a/controllers/consoleplugin/consoleplugin_reconciler.go +++ b/controllers/consoleplugin/consoleplugin_reconciler.go @@ -197,7 +197,7 @@ func (r *CPReconciler) reconcileDeployment(ctx context.Context, builder builder, newDepl := builder.deployment(cmDigest) // Annotate pod with certificate reference so that it is reloaded if modified - if err := r.CertWatcher.AnnotatePod(ctx, r.Client, &newDepl.Spec.Template, lokiCerts); err != nil { + if err := r.CertWatcher.AnnotatePod(ctx, r.Client, &newDepl.Spec.Template, lokiCerts, lokiStatusCerts); err != nil { return err } if !r.nobjMngr.Exists(r.owned.deployment) { diff --git a/controllers/consoleplugin/consoleplugin_test.go b/controllers/consoleplugin/consoleplugin_test.go index 6ceb76363..e66793285 100644 --- a/controllers/consoleplugin/consoleplugin_test.go +++ b/controllers/consoleplugin/consoleplugin_test.go @@ -188,6 +188,49 @@ func TestContainerUpdateCheck(t *testing.T) { report = helper.NewChangeReport("") assert.False(helper.PodChanged(&old.Spec.Template, &new.Spec.Template, constants.PluginName, &report)) assert.Contains(report.String(), "no change") + old = new + + //set status url and enable default tls + loki.StatusURL = "http://loki.status:3100/" + loki.StatusTLS.Enable = true + + spec = flowslatest.FlowCollectorSpec{ConsolePlugin: plugin, Loki: loki} + builder = newBuilder(testNamespace, testImage, &spec, &certWatcher) + new = builder.deployment("digest") + report = helper.NewChangeReport("") + assert.True(helper.PodChanged(&old.Spec.Template, &new.Spec.Template, constants.PluginName, &report)) + assert.Contains(report.String(), "Container changed") + old = new + + //update status ca cert + loki.StatusTLS.CACert = flowslatest.CertificateReference{ + Type: "configmap", + Name: "status-cm-name", + CertFile: "status-ca.crt", + } + + spec = flowslatest.FlowCollectorSpec{ConsolePlugin: plugin, Loki: loki} + builder = newBuilder(testNamespace, testImage, &spec, &certWatcher) + new = builder.deployment("digest") + report = helper.NewChangeReport("") + assert.True(helper.PodChanged(&old.Spec.Template, &new.Spec.Template, constants.PluginName, &report)) + assert.Contains(report.String(), "Volumes changed") + old = new + + //update status user cert + loki.StatusTLS.UserCert = flowslatest.CertificateReference{ + Type: "secret", + Name: "sec-name", + CertFile: "tls.crt", + CertKey: "tls.key", + } + + spec = flowslatest.FlowCollectorSpec{ConsolePlugin: plugin, Loki: loki} + builder = newBuilder(testNamespace, testImage, &spec, &certWatcher) + new = builder.deployment("digest") + report = helper.NewChangeReport("") + assert.True(helper.PodChanged(&old.Spec.Template, &new.Spec.Template, constants.PluginName, &report)) + assert.Contains(report.String(), "Volumes changed") } func TestServiceUpdateCheck(t *testing.T) { diff --git a/docs/FlowCollector.md b/docs/FlowCollector.md index 7b61c18a2..bc09165c5 100644 --- a/docs/FlowCollector.md +++ b/docs/FlowCollector.md @@ -5952,11 +5952,18 @@ loki, the flow store, client settings. Default: map[app:netobserv-flowcollector]
false + + statusTls + object + + tls client configuration for loki status URL.
+ + false statusUrl string - statusURL specifies the address of the Loki /ready /metrics /config endpoints, in case it is different from the Loki querier URL. If empty, the QuerierURL value will be used. This is useful to show error messages and some context in the frontend. When using the Loki Operator, set it to the Loki HTTP query frontend service, for example https://loki-query-frontend-http.netobserv.svc:3100/.
+ statusURL specifies the address of the Loki /ready /metrics /config endpoints, in case it is different from the Loki querier URL. If empty, the QuerierURL value will be used. This is useful to show error messages and some context in the frontend. When using the Loki Operator, set it to the Loki HTTP query frontend service, for example https://loki-query-frontend-http.netobserv.svc:3100/. statusTLS configuration will be used when statusUrl is set.
false @@ -5981,7 +5988,7 @@ loki, the flow store, client settings. tls object - tls client configuration.
+ tls client configuration for loki URL.
false @@ -5997,12 +6004,164 @@ loki, the flow store, client settings. +### FlowCollector.spec.loki.statusTls +[↩ Parent](#flowcollectorspecloki-1) + + + +tls client configuration for loki status URL. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescriptionRequired
caCertobject + caCert defines the reference of the certificate for the Certificate Authority
+
false
enableboolean + enable TLS
+
+ Default: false
+
false
insecureSkipVerifyboolean + insecureSkipVerify allows skipping client-side verification of the server certificate If set to true, CACert field will be ignored
+
+ Default: false
+
false
userCertobject + userCert defines the user certificate reference, used for mTLS (you can ignore it when using regular, one-way TLS)
+
false
+ + +### FlowCollector.spec.loki.statusTls.caCert +[↩ Parent](#flowcollectorspeclokistatustls) + + + +caCert defines the reference of the certificate for the Certificate Authority + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescriptionRequired
certFilestring + certFile defines the path to the certificate file name within the config map or secret
+
false
certKeystring + certKey defines the path to the certificate private key file name within the config map or secret. Omit when the key is not necessary.
+
false
namestring + name of the config map or secret containing certificates
+
false
typeenum + type for the certificate reference: "configmap" or "secret"
+
+ Enum: configmap, secret
+
false
+ + +### FlowCollector.spec.loki.statusTls.userCert +[↩ Parent](#flowcollectorspeclokistatustls) + + + +userCert defines the user certificate reference, used for mTLS (you can ignore it when using regular, one-way TLS) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypeDescriptionRequired
certFilestring + certFile defines the path to the certificate file name within the config map or secret
+
false
certKeystring + certKey defines the path to the certificate private key file name within the config map or secret. Omit when the key is not necessary.
+
false
namestring + name of the config map or secret containing certificates
+
false
typeenum + type for the certificate reference: "configmap" or "secret"
+
+ Enum: configmap, secret
+
false
+ + ### FlowCollector.spec.loki.tls [↩ Parent](#flowcollectorspecloki-1) -tls client configuration. +tls client configuration for loki URL. diff --git a/pkg/helper/flowcollector.go b/pkg/helper/flowcollector.go index f6d0ddbcb..ca1776f79 100644 --- a/pkg/helper/flowcollector.go +++ b/pkg/helper/flowcollector.go @@ -42,6 +42,13 @@ func LokiForwardUserToken(spec *flowslatest.FlowCollectorLoki) bool { return spec.AuthToken == flowslatest.LokiAuthForwardUserToken } +func GetLokiStatusTLS(spec *flowslatest.FlowCollectorLoki) flowslatest.ClientTLS { + if spec.StatusURL != "" { + return spec.StatusTLS + } + return spec.TLS +} + func GetRecordTypes(processor *flowslatest.FlowCollectorFLP) []string { outputRecordTypes := []string{constants.FlowLogType} if processor.LogTypes != nil {