diff --git a/internal/generator/vector/output/elasticsearch/elasticsearch.go b/internal/generator/vector/output/elasticsearch/elasticsearch.go index a519e9a42..de9d4d769 100644 --- a/internal/generator/vector/output/elasticsearch/elasticsearch.go +++ b/internal/generator/vector/output/elasticsearch/elasticsearch.go @@ -256,30 +256,32 @@ func Output(o logging.OutputSpec, inputs []string, secret *corev1.Secret, op Opt func TLSConf(o logging.OutputSpec, secret *corev1.Secret) []Element { conf := []Element{} - if o.Secret != nil { - hasTLS := false - conf = append(conf, security.TLSConf{ - ComponentID: helpers.FormatComponentID(o.Name), - InsecureSkipVerify: o.TLS != nil && o.TLS.InsecureSkipVerify, - }) - if o.Name == logging.OutputNameDefault || security.HasTLSCertAndKey(secret) { - hasTLS = true - kc := TLSKeyCert{ - CertPath: security.SecretPath(o.Secret.Name, constants.ClientCertKey), - KeyPath: security.SecretPath(o.Secret.Name, constants.ClientPrivateKey), - } - conf = append(conf, kc) - } - if o.Name == logging.OutputNameDefault || security.HasCABundle(secret) { - hasTLS = true - ca := CAFile{ - CAFilePath: security.SecretPath(o.Secret.Name, constants.TrustedCABundleKey), - } - conf = append(conf, ca) + + hasTLS := false + conf = append(conf, security.TLSConf{ + ComponentID: helpers.FormatComponentID(o.Name), + InsecureSkipVerify: o.TLS != nil && o.TLS.InsecureSkipVerify, + }) + if o.Name == logging.OutputNameDefault || security.HasTLSCertAndKey(secret) { + hasTLS = true + kc := TLSKeyCert{ + CertPath: security.SecretPath(o.Secret.Name, constants.ClientCertKey), + KeyPath: security.SecretPath(o.Secret.Name, constants.ClientPrivateKey), } - if !hasTLS { - return []Element{} + conf = append(conf, kc) + } + if o.Name == logging.OutputNameDefault || security.HasCABundle(secret) { + hasTLS = true + ca := CAFile{ + CAFilePath: security.SecretPath(o.Secret.Name, constants.TrustedCABundleKey), } + conf = append(conf, ca) + } + if o.TLS != nil && o.TLS.InsecureSkipVerify { + hasTLS = true + } + if !hasTLS { + return []Element{} } return conf } diff --git a/internal/generator/vector/output/elasticsearch/elasticsearch_test.go b/internal/generator/vector/output/elasticsearch/elasticsearch_test.go index a1d4221a2..cd6042800 100644 --- a/internal/generator/vector/output/elasticsearch/elasticsearch_test.go +++ b/internal/generator/vector/output/elasticsearch/elasticsearch_test.go @@ -294,6 +294,134 @@ enabled = true key_file = "/var/run/ocp-collector/secrets/es-1/tls.key" crt_file = "/var/run/ocp-collector/secrets/es-1/tls.crt" ca_file = "/var/run/ocp-collector/secrets/es-1/ca-bundle.crt" +`, + }), + Entry("with tls without secret", helpers.ConfGenerateTest{ + CLFSpec: logging.ClusterLogForwarderSpec{ + Outputs: []logging.OutputSpec{ + { + Type: logging.OutputTypeElasticsearch, + Name: "es-1", + URL: "http://es.svc.infra.cluster:9200", + Secret: nil, + TLS: &logging.OutputTLSSpec{ + InsecureSkipVerify: true, + }, + }, + }, + }, + Secrets: security.NoSecrets, + ExpectedConf: ` +# Set Elasticsearch index +[transforms.es_1_add_es_index] +type = "remap" +inputs = ["application"] +source = ''' + index = "default" + if (.log_type == "application"){ + index = "app" + } + if (.log_type == "infrastructure"){ + index = "infra" + } + if (.log_type == "audit"){ + index = "audit" + } + .write_index = index + "-write" + ._id = encode_base64(uuid_v4()) + del(.file) + del(.tag) + del(.source_type) +''' + +[transforms.es_1_dedot_and_flatten] +type = "lua" +inputs = ["es_1_add_es_index"] +version = "2" +hooks.init = "init" +hooks.process = "process" +source = ''' + function init() + count = 0 + end + function process(event, emit) + count = count + 1 + event.log.openshift.sequence = count + if event.log.kubernetes == nil then + emit(event) + return + end + if event.log.kubernetes.labels == nil then + emit(event) + return + end + dedot(event.log.kubernetes.namespace_labels) + dedot(event.log.kubernetes.labels) + flatten_labels(event) + prune_labels(event) + emit(event) + end + + function dedot(map) + if map == nil then + return + end + local new_map = {} + local changed_keys = {} + for k, v in pairs(map) do + local dedotted = string.gsub(k, "[./]", "_") + if dedotted ~= k then + new_map[dedotted] = v + changed_keys[k] = true + end + end + for k in pairs(changed_keys) do + map[k] = nil + end + for k, v in pairs(new_map) do + map[k] = v + end + end + + function flatten_labels(event) + -- create "flat_labels" key + event.log.kubernetes.flat_labels = {} + i = 1 + -- flatten the labels + for k,v in pairs(event.log.kubernetes.labels) do + event.log.kubernetes.flat_labels[i] = k.."="..v + i=i+1 + end + end + + function prune_labels(event) + local exclusions = {"app_kubernetes_io_name", "app_kubernetes_io_instance", "app_kubernetes_io_version", "app_kubernetes_io_component", "app_kubernetes_io_part-of", "app_kubernetes_io_managed-by", "app_kubernetes_io_created-by"} + local keys = {} + for k,v in pairs(event.log.kubernetes.labels) do + for index, e in pairs(exclusions) do + if k == e then + keys[k] = v + end + end + end + event.log.kubernetes.labels = keys + end +''' + +[sinks.es_1] +type = "elasticsearch" +inputs = ["es_1_dedot_and_flatten"] +endpoint = "http://es.svc.infra.cluster:9200" +bulk.index = "{{ write_index }}" +bulk.action = "create" +encoding.except_fields = ["write_index"] +request.timeout_secs = 2147483648 +id_key = "_id" + +[sinks.es_1.tls] +enabled = true +verify_certificate = false +verify_hostname = false `, }), Entry("without security", helpers.ConfGenerateTest{ diff --git a/internal/generator/vector/output/loki/loki.go b/internal/generator/vector/output/loki/loki.go index d775dbb87..50c5eead5 100644 --- a/internal/generator/vector/output/loki/loki.go +++ b/internal/generator/vector/output/loki/loki.go @@ -191,32 +191,35 @@ func Tenant(l *logging.Loki) Element { func TLSConf(o logging.OutputSpec, secret *corev1.Secret) []Element { conf := []Element{} - if o.Secret != nil { - hasTLS := false - conf = append(conf, security.TLSConf{ - ComponentID: strings.ToLower(vectorhelpers.Replacer.Replace(o.Name)), - InsecureSkipVerify: o.TLS != nil && o.TLS.InsecureSkipVerify, - }) - if o.Name == logging.OutputNameDefault || security.HasTLSCertAndKey(secret) { - hasTLS = true - kc := TLSKeyCert{ - CertPath: security.SecretPath(o.Secret.Name, constants.ClientCertKey), - KeyPath: security.SecretPath(o.Secret.Name, constants.ClientPrivateKey), - } - conf = append(conf, kc) - } - if o.Name == logging.OutputNameDefault || security.HasCABundle(secret) { - hasTLS = true - ca := CAFile{ - CAFilePath: security.SecretPath(o.Secret.Name, constants.TrustedCABundleKey), - } - conf = append(conf, ca) + hasTLS := false + conf = append(conf, security.TLSConf{ + ComponentID: strings.ToLower(vectorhelpers.Replacer.Replace(o.Name)), + InsecureSkipVerify: o.TLS != nil && o.TLS.InsecureSkipVerify, + }) + + if o.Name == logging.OutputNameDefault || security.HasTLSCertAndKey(secret) { + hasTLS = true + kc := TLSKeyCert{ + CertPath: security.SecretPath(o.Secret.Name, constants.ClientCertKey), + KeyPath: security.SecretPath(o.Secret.Name, constants.ClientPrivateKey), } - if !hasTLS { - return []Element{} + conf = append(conf, kc) + } + if o.Name == logging.OutputNameDefault || security.HasCABundle(secret) { + hasTLS = true + ca := CAFile{ + CAFilePath: security.SecretPath(o.Secret.Name, constants.TrustedCABundleKey), } - } else if secret != nil { + conf = append(conf, ca) + } + if o.TLS != nil && o.TLS.InsecureSkipVerify { + hasTLS = true + } + if !hasTLS { + return []Element{} + } + if o.Secret == nil && secret != nil { // Set CA from logcollector ServiceAccount for internal Loki return []Element{ security.TLSConf{ diff --git a/internal/generator/vector/output/loki/loki_conf_test.go b/internal/generator/vector/output/loki/loki_conf_test.go index 9022ea430..d9af3aed8 100644 --- a/internal/generator/vector/output/loki/loki_conf_test.go +++ b/internal/generator/vector/output/loki/loki_conf_test.go @@ -70,84 +70,84 @@ var _ = Describe("Generate vector config", func() { }, }, ExpectedConf: ` -[transforms.loki_receiver_remap] -type = "remap" -inputs = ["application"] -source = ''' - del(.tag) -''' - -[transforms.loki_receiver_dedot] -type = "lua" -inputs = ["loki_receiver_remap"] -version = "2" -hooks.init = "init" -hooks.process = "process" -source = ''' - function init() - count = 0 - end - function process(event, emit) - count = count + 1 - event.log.openshift.sequence = count - if event.log.kubernetes == nil then - emit(event) - return - end - if event.log.kubernetes.labels == nil then - emit(event) - return - end - dedot(event.log.kubernetes.namespace_labels) - dedot(event.log.kubernetes.labels) - emit(event) - end - - function dedot(map) - if map == nil then - return - end - local new_map = {} - local changed_keys = {} - for k, v in pairs(map) do - local dedotted = string.gsub(k, "[./]", "_") - if dedotted ~= k then - new_map[dedotted] = v - changed_keys[k] = true - end - end - for k in pairs(changed_keys) do - map[k] = nil - end - for k, v in pairs(new_map) do - map[k] = v - end - end -''' - -[sinks.loki_receiver] -type = "loki" -inputs = ["loki_receiver_dedot"] -endpoint = "https://logs-us-west1.grafana.net" -out_of_order_action = "accept" -healthcheck.enabled = false - -[sinks.loki_receiver.encoding] -codec = "json" - -[sinks.loki_receiver.labels] -kubernetes_container_name = "{{kubernetes.container_name}}" -kubernetes_host = "${VECTOR_SELF_NODE_NAME}" -kubernetes_namespace_name = "{{kubernetes.namespace_name}}" -kubernetes_pod_name = "{{kubernetes.pod_name}}" -log_type = "{{log_type}}" - -# Basic Auth Config -[sinks.loki_receiver.auth] -strategy = "basic" -user = "username" -password = "password" -`, + [transforms.loki_receiver_remap] + type = "remap" + inputs = ["application"] + source = ''' + del(.tag) + ''' + + [transforms.loki_receiver_dedot] + type = "lua" + inputs = ["loki_receiver_remap"] + version = "2" + hooks.init = "init" + hooks.process = "process" + source = ''' + function init() + count = 0 + end + function process(event, emit) + count = count + 1 + event.log.openshift.sequence = count + if event.log.kubernetes == nil then + emit(event) + return + end + if event.log.kubernetes.labels == nil then + emit(event) + return + end + dedot(event.log.kubernetes.namespace_labels) + dedot(event.log.kubernetes.labels) + emit(event) + end + + function dedot(map) + if map == nil then + return + end + local new_map = {} + local changed_keys = {} + for k, v in pairs(map) do + local dedotted = string.gsub(k, "[./]", "_") + if dedotted ~= k then + new_map[dedotted] = v + changed_keys[k] = true + end + end + for k in pairs(changed_keys) do + map[k] = nil + end + for k, v in pairs(new_map) do + map[k] = v + end + end + ''' + + [sinks.loki_receiver] + type = "loki" + inputs = ["loki_receiver_dedot"] + endpoint = "https://logs-us-west1.grafana.net" + out_of_order_action = "accept" + healthcheck.enabled = false + + [sinks.loki_receiver.encoding] + codec = "json" + + [sinks.loki_receiver.labels] + kubernetes_container_name = "{{kubernetes.container_name}}" + kubernetes_host = "${VECTOR_SELF_NODE_NAME}" + kubernetes_namespace_name = "{{kubernetes.namespace_name}}" + kubernetes_pod_name = "{{kubernetes.pod_name}}" + log_type = "{{log_type}}" + + # Basic Auth Config + [sinks.loki_receiver.auth] + strategy = "basic" + user = "username" + password = "password" + `, }), Entry("with custom labels", helpers.ConfGenerateTest{ CLFSpec: logging.ClusterLogForwarderSpec{ @@ -174,82 +174,82 @@ password = "password" }, }, ExpectedConf: ` -[transforms.loki_receiver_remap] -type = "remap" -inputs = ["application"] -source = ''' - del(.tag) -''' - -[transforms.loki_receiver_dedot] -type = "lua" -inputs = ["loki_receiver_remap"] -version = "2" -hooks.init = "init" -hooks.process = "process" -source = ''' - function init() - count = 0 - end - function process(event, emit) - count = count + 1 - event.log.openshift.sequence = count - if event.log.kubernetes == nil then - emit(event) - return - end - if event.log.kubernetes.labels == nil then - emit(event) - return - end - dedot(event.log.kubernetes.namespace_labels) - dedot(event.log.kubernetes.labels) - emit(event) - end - - function dedot(map) - if map == nil then - return - end - local new_map = {} - local changed_keys = {} - for k, v in pairs(map) do - local dedotted = string.gsub(k, "[./]", "_") - if dedotted ~= k then - new_map[dedotted] = v - changed_keys[k] = true - end - end - for k in pairs(changed_keys) do - map[k] = nil - end - for k, v in pairs(new_map) do - map[k] = v - end - end -''' - -[sinks.loki_receiver] -type = "loki" -inputs = ["loki_receiver_dedot"] -endpoint = "https://logs-us-west1.grafana.net" -out_of_order_action = "accept" -healthcheck.enabled = false - -[sinks.loki_receiver.encoding] -codec = "json" - -[sinks.loki_receiver.labels] -kubernetes_container_name = "{{kubernetes.container_name}}" -kubernetes_host = "${VECTOR_SELF_NODE_NAME}" -kubernetes_labels_app = "{{kubernetes.labels.app}}" - -# Basic Auth Config -[sinks.loki_receiver.auth] -strategy = "basic" -user = "username" -password = "password" -`, + [transforms.loki_receiver_remap] + type = "remap" + inputs = ["application"] + source = ''' + del(.tag) + ''' + + [transforms.loki_receiver_dedot] + type = "lua" + inputs = ["loki_receiver_remap"] + version = "2" + hooks.init = "init" + hooks.process = "process" + source = ''' + function init() + count = 0 + end + function process(event, emit) + count = count + 1 + event.log.openshift.sequence = count + if event.log.kubernetes == nil then + emit(event) + return + end + if event.log.kubernetes.labels == nil then + emit(event) + return + end + dedot(event.log.kubernetes.namespace_labels) + dedot(event.log.kubernetes.labels) + emit(event) + end + + function dedot(map) + if map == nil then + return + end + local new_map = {} + local changed_keys = {} + for k, v in pairs(map) do + local dedotted = string.gsub(k, "[./]", "_") + if dedotted ~= k then + new_map[dedotted] = v + changed_keys[k] = true + end + end + for k in pairs(changed_keys) do + map[k] = nil + end + for k, v in pairs(new_map) do + map[k] = v + end + end + ''' + + [sinks.loki_receiver] + type = "loki" + inputs = ["loki_receiver_dedot"] + endpoint = "https://logs-us-west1.grafana.net" + out_of_order_action = "accept" + healthcheck.enabled = false + + [sinks.loki_receiver.encoding] + codec = "json" + + [sinks.loki_receiver.labels] + kubernetes_container_name = "{{kubernetes.container_name}}" + kubernetes_host = "${VECTOR_SELF_NODE_NAME}" + kubernetes_labels_app = "{{kubernetes.labels.app}}" + + # Basic Auth Config + [sinks.loki_receiver.auth] + strategy = "basic" + user = "username" + password = "password" + `, }), Entry("with tenant id", helpers.ConfGenerateTest{ CLFSpec: logging.ClusterLogForwarderSpec{ @@ -276,86 +276,86 @@ password = "password" }, }, ExpectedConf: ` -[transforms.loki_receiver_remap] -type = "remap" -inputs = ["application"] -source = ''' - del(.tag) -''' - -[transforms.loki_receiver_dedot] -type = "lua" -inputs = ["loki_receiver_remap"] -version = "2" -hooks.init = "init" -hooks.process = "process" -source = ''' - function init() - count = 0 - end - function process(event, emit) - count = count + 1 - event.log.openshift.sequence = count - if event.log.kubernetes == nil then - emit(event) - return - end - if event.log.kubernetes.labels == nil then - emit(event) - return - end - dedot(event.log.kubernetes.namespace_labels) - dedot(event.log.kubernetes.labels) - emit(event) - end - - function dedot(map) - if map == nil then - return - end - local new_map = {} - local changed_keys = {} - for k, v in pairs(map) do - local dedotted = string.gsub(k, "[./]", "_") - if dedotted ~= k then - new_map[dedotted] = v - changed_keys[k] = true - end - end - for k in pairs(changed_keys) do - map[k] = nil - end - for k, v in pairs(new_map) do - map[k] = v - end - end -''' - -[sinks.loki_receiver] -type = "loki" -inputs = ["loki_receiver_dedot"] -endpoint = "https://logs-us-west1.grafana.net" -out_of_order_action = "accept" -healthcheck.enabled = false -tenant_id = "{{foo.bar.baz}}" - -[sinks.loki_receiver.encoding] -codec = "json" - -[sinks.loki_receiver.labels] -kubernetes_container_name = "{{kubernetes.container_name}}" -kubernetes_host = "${VECTOR_SELF_NODE_NAME}" -kubernetes_namespace_name = "{{kubernetes.namespace_name}}" -kubernetes_pod_name = "{{kubernetes.pod_name}}" -log_type = "{{log_type}}" - -# Basic Auth Config -[sinks.loki_receiver.auth] -strategy = "basic" -user = "username" -password = "password" - -`, + [transforms.loki_receiver_remap] + type = "remap" + inputs = ["application"] + source = ''' + del(.tag) + ''' + + [transforms.loki_receiver_dedot] + type = "lua" + inputs = ["loki_receiver_remap"] + version = "2" + hooks.init = "init" + hooks.process = "process" + source = ''' + function init() + count = 0 + end + function process(event, emit) + count = count + 1 + event.log.openshift.sequence = count + if event.log.kubernetes == nil then + emit(event) + return + end + if event.log.kubernetes.labels == nil then + emit(event) + return + end + dedot(event.log.kubernetes.namespace_labels) + dedot(event.log.kubernetes.labels) + emit(event) + end + + function dedot(map) + if map == nil then + return + end + local new_map = {} + local changed_keys = {} + for k, v in pairs(map) do + local dedotted = string.gsub(k, "[./]", "_") + if dedotted ~= k then + new_map[dedotted] = v + changed_keys[k] = true + end + end + for k in pairs(changed_keys) do + map[k] = nil + end + for k, v in pairs(new_map) do + map[k] = v + end + end + ''' + + [sinks.loki_receiver] + type = "loki" + inputs = ["loki_receiver_dedot"] + endpoint = "https://logs-us-west1.grafana.net" + out_of_order_action = "accept" + healthcheck.enabled = false + tenant_id = "{{foo.bar.baz}}" + + [sinks.loki_receiver.encoding] + codec = "json" + + [sinks.loki_receiver.labels] + kubernetes_container_name = "{{kubernetes.container_name}}" + kubernetes_host = "${VECTOR_SELF_NODE_NAME}" + kubernetes_namespace_name = "{{kubernetes.namespace_name}}" + kubernetes_pod_name = "{{kubernetes.pod_name}}" + log_type = "{{log_type}}" + + # Basic Auth Config + [sinks.loki_receiver.auth] + strategy = "basic" + user = "username" + password = "password" + + `, }), Entry("with custom bearer token", helpers.ConfGenerateTest{ CLFSpec: logging.ClusterLogForwarderSpec{ @@ -378,195 +378,389 @@ password = "password" }, }, ExpectedConf: ` -[transforms.loki_receiver_remap] -type = "remap" -inputs = ["application"] -source = ''' - del(.tag) -''' - -[transforms.loki_receiver_dedot] -type = "lua" -inputs = ["loki_receiver_remap"] -version = "2" -hooks.init = "init" -hooks.process = "process" -source = ''' - function init() - count = 0 - end - function process(event, emit) - count = count + 1 - event.log.openshift.sequence = count - if event.log.kubernetes == nil then - emit(event) - return - end - if event.log.kubernetes.labels == nil then - emit(event) - return - end - dedot(event.log.kubernetes.namespace_labels) - dedot(event.log.kubernetes.labels) - emit(event) - end - - function dedot(map) - if map == nil then - return - end - local new_map = {} - local changed_keys = {} - for k, v in pairs(map) do - local dedotted = string.gsub(k, "[./]", "_") - if dedotted ~= k then - new_map[dedotted] = v - changed_keys[k] = true - end - end - for k in pairs(changed_keys) do - map[k] = nil - end - for k, v in pairs(new_map) do - map[k] = v - end - end -''' - -[sinks.loki_receiver] -type = "loki" -inputs = ["loki_receiver_dedot"] -endpoint = "http://lokistack-dev-gateway-http.openshift-logging.svc:8080/api/logs/v1/application" -out_of_order_action = "accept" -healthcheck.enabled = false - -[sinks.loki_receiver.encoding] -codec = "json" - -[sinks.loki_receiver.labels] -kubernetes_container_name = "{{kubernetes.container_name}}" -kubernetes_host = "${VECTOR_SELF_NODE_NAME}" -kubernetes_namespace_name = "{{kubernetes.namespace_name}}" -kubernetes_pod_name = "{{kubernetes.pod_name}}" -log_type = "{{log_type}}" - -# Bearer Auth Config -[sinks.loki_receiver.auth] -strategy = "bearer" -token = "token-for-custom-loki" -`, + [transforms.loki_receiver_remap] + type = "remap" + inputs = ["application"] + source = ''' + del(.tag) + ''' + + [transforms.loki_receiver_dedot] + type = "lua" + inputs = ["loki_receiver_remap"] + version = "2" + hooks.init = "init" + hooks.process = "process" + source = ''' + function init() + count = 0 + end + function process(event, emit) + count = count + 1 + event.log.openshift.sequence = count + if event.log.kubernetes == nil then + emit(event) + return + end + if event.log.kubernetes.labels == nil then + emit(event) + return + end + dedot(event.log.kubernetes.namespace_labels) + dedot(event.log.kubernetes.labels) + emit(event) + end + + function dedot(map) + if map == nil then + return + end + local new_map = {} + local changed_keys = {} + for k, v in pairs(map) do + local dedotted = string.gsub(k, "[./]", "_") + if dedotted ~= k then + new_map[dedotted] = v + changed_keys[k] = true + end + end + for k in pairs(changed_keys) do + map[k] = nil + end + for k, v in pairs(new_map) do + map[k] = v + end + end + ''' + + [sinks.loki_receiver] + type = "loki" + inputs = ["loki_receiver_dedot"] + endpoint = "http://lokistack-dev-gateway-http.openshift-logging.svc:8080/api/logs/v1/application" + out_of_order_action = "accept" + healthcheck.enabled = false + + [sinks.loki_receiver.encoding] + codec = "json" + + [sinks.loki_receiver.labels] + kubernetes_container_name = "{{kubernetes.container_name}}" + kubernetes_host = "${VECTOR_SELF_NODE_NAME}" + kubernetes_namespace_name = "{{kubernetes.namespace_name}}" + kubernetes_pod_name = "{{kubernetes.pod_name}}" + log_type = "{{log_type}}" + + # Bearer Auth Config + [sinks.loki_receiver.auth] + strategy = "bearer" + token = "token-for-custom-loki" + `, }), - ) -}) - -var _ = Describe("Generate vector config for in cluster loki", func() { - inputPipeline := []string{"application"} - var f = func(clspec logging.CollectionSpec, secrets map[string]*corev1.Secret, clfspec logging.ClusterLogForwarderSpec, op generator.Options) []generator.Element { - return Conf(clfspec.Outputs[0], inputPipeline, secrets[constants.LogCollectorToken], generator.NoOptions) - } - DescribeTable("for Loki output", helpers.TestGenerateConfWith(f), - Entry("with default logcollector bearer token", helpers.ConfGenerateTest{ + Entry("with TLS insecureSkipVerify=true", helpers.ConfGenerateTest{ CLFSpec: logging.ClusterLogForwarderSpec{ Outputs: []logging.OutputSpec{ { Type: logging.OutputTypeLoki, Name: "loki-receiver", - URL: "http://lokistack-dev-gateway-http.openshift-logging.svc:8080/api/logs/v1/application", + URL: "https://lokistack-dev-gateway-http.openshift-logging.svc:8080/api/logs/v1/application", + Secret: &logging.OutputSecretSpec{ + Name: "custom-loki-secret", + }, + TLS: &logging.OutputTLSSpec{ + InsecureSkipVerify: true, + }, }, }, }, Secrets: map[string]*corev1.Secret{ - constants.LogCollectorToken: { + "loki-receiver": { Data: map[string][]byte{ - "token": []byte("token-for-internal-loki"), + "ca-bundle.crt": []byte("junk"), }, }, }, ExpectedConf: ` -[transforms.loki_receiver_remap] -type = "remap" -inputs = ["application"] -source = ''' - del(.tag) -''' - -[transforms.loki_receiver_dedot] -type = "lua" -inputs = ["loki_receiver_remap"] -version = "2" -hooks.init = "init" -hooks.process = "process" -source = ''' - function init() - count = 0 - end - function process(event, emit) - count = count + 1 - event.log.openshift.sequence = count - if event.log.kubernetes == nil then - emit(event) - return - end - if event.log.kubernetes.labels == nil then - emit(event) - return - end - dedot(event.log.kubernetes.namespace_labels) - dedot(event.log.kubernetes.labels) - emit(event) - end - - function dedot(map) - if map == nil then - return - end - local new_map = {} - local changed_keys = {} - for k, v in pairs(map) do - local dedotted = string.gsub(k, "[./]", "_") - if dedotted ~= k then - new_map[dedotted] = v - changed_keys[k] = true - end - end - for k in pairs(changed_keys) do - map[k] = nil - end - for k, v in pairs(new_map) do - map[k] = v - end - end -''' - -[sinks.loki_receiver] -type = "loki" -inputs = ["loki_receiver_dedot"] -endpoint = "http://lokistack-dev-gateway-http.openshift-logging.svc:8080/api/logs/v1/application" -out_of_order_action = "accept" -healthcheck.enabled = false - -[sinks.loki_receiver.encoding] -codec = "json" - -[sinks.loki_receiver.labels] -kubernetes_container_name = "{{kubernetes.container_name}}" -kubernetes_host = "${VECTOR_SELF_NODE_NAME}" -kubernetes_namespace_name = "{{kubernetes.namespace_name}}" -kubernetes_pod_name = "{{kubernetes.pod_name}}" -log_type = "{{log_type}}" - -[sinks.loki_receiver.tls] -enabled = true -ca_file = "/var/run/secrets/kubernetes.io/serviceaccount/service-ca.crt" -# Bearer Auth Config -[sinks.loki_receiver.auth] -strategy = "bearer" -token = "token-for-internal-loki" -`, + [transforms.loki_receiver_remap] + type = "remap" + inputs = ["application"] + source = ''' + del(.tag) + ''' + + [transforms.loki_receiver_dedot] + type = "lua" + inputs = ["loki_receiver_remap"] + version = "2" + hooks.init = "init" + hooks.process = "process" + source = ''' + function init() + count = 0 + end + function process(event, emit) + count = count + 1 + event.log.openshift.sequence = count + if event.log.kubernetes == nil then + emit(event) + return + end + if event.log.kubernetes.labels == nil then + emit(event) + return + end + dedot(event.log.kubernetes.namespace_labels) + dedot(event.log.kubernetes.labels) + emit(event) + end + + function dedot(map) + if map == nil then + return + end + local new_map = {} + local changed_keys = {} + for k, v in pairs(map) do + local dedotted = string.gsub(k, "[./]", "_") + if dedotted ~= k then + new_map[dedotted] = v + changed_keys[k] = true + end + end + for k in pairs(changed_keys) do + map[k] = nil + end + for k, v in pairs(new_map) do + map[k] = v + end + end + ''' + + [sinks.loki_receiver] + type = "loki" + inputs = ["loki_receiver_dedot"] + endpoint = "https://lokistack-dev-gateway-http.openshift-logging.svc:8080/api/logs/v1/application" + out_of_order_action = "accept" + healthcheck.enabled = false + + [sinks.loki_receiver.encoding] + codec = "json" + + [sinks.loki_receiver.labels] + kubernetes_container_name = "{{kubernetes.container_name}}" + kubernetes_host = "${VECTOR_SELF_NODE_NAME}" + kubernetes_namespace_name = "{{kubernetes.namespace_name}}" + kubernetes_pod_name = "{{kubernetes.pod_name}}" + log_type = "{{log_type}}" + + [sinks.loki_receiver.tls] + enabled = true + verify_certificate = false + verify_hostname = false + ca_file = "/var/run/ocp-collector/secrets/custom-loki-secret/ca-bundle.crt" + `, + }), + Entry("with TLS insecureSkipVerify=true no certificate", helpers.ConfGenerateTest{ + CLFSpec: logging.ClusterLogForwarderSpec{ + Outputs: []logging.OutputSpec{ + { + Type: logging.OutputTypeLoki, + Name: "loki-receiver", + URL: "https://lokistack-dev-gateway-http.openshift-logging.svc:8080/api/logs/v1/application", + TLS: &logging.OutputTLSSpec{ + InsecureSkipVerify: true, + }, + }, + }, + }, + ExpectedConf: ` + [transforms.loki_receiver_remap] + type = "remap" + inputs = ["application"] + source = ''' + del(.tag) + ''' + + [transforms.loki_receiver_dedot] + type = "lua" + inputs = ["loki_receiver_remap"] + version = "2" + hooks.init = "init" + hooks.process = "process" + source = ''' + function init() + count = 0 + end + function process(event, emit) + count = count + 1 + event.log.openshift.sequence = count + if event.log.kubernetes == nil then + emit(event) + return + end + if event.log.kubernetes.labels == nil then + emit(event) + return + end + dedot(event.log.kubernetes.namespace_labels) + dedot(event.log.kubernetes.labels) + emit(event) + end + + function dedot(map) + if map == nil then + return + end + local new_map = {} + local changed_keys = {} + for k, v in pairs(map) do + local dedotted = string.gsub(k, "[./]", "_") + if dedotted ~= k then + new_map[dedotted] = v + changed_keys[k] = true + end + end + for k in pairs(changed_keys) do + map[k] = nil + end + for k, v in pairs(new_map) do + map[k] = v + end + end + ''' + + [sinks.loki_receiver] + type = "loki" + inputs = ["loki_receiver_dedot"] + endpoint = "https://lokistack-dev-gateway-http.openshift-logging.svc:8080/api/logs/v1/application" + out_of_order_action = "accept" + healthcheck.enabled = false + + [sinks.loki_receiver.encoding] + codec = "json" + + [sinks.loki_receiver.labels] + kubernetes_container_name = "{{kubernetes.container_name}}" + kubernetes_host = "${VECTOR_SELF_NODE_NAME}" + kubernetes_namespace_name = "{{kubernetes.namespace_name}}" + kubernetes_pod_name = "{{kubernetes.pod_name}}" + log_type = "{{log_type}}" + + [sinks.loki_receiver.tls] + enabled = true + verify_certificate = false + verify_hostname = false + `, }), ) }) +var _ = Describe("Generate vector config for in cluster loki", func() { + inputPipeline := []string{"application"} + var f = func(clspec logging.CollectionSpec, secrets map[string]*corev1.Secret, clfspec logging.ClusterLogForwarderSpec, op generator.Options) []generator.Element { + return Conf(clfspec.Outputs[0], inputPipeline, secrets[constants.LogCollectorToken], generator.NoOptions) + } + DescribeTable("for Loki output", helpers.TestGenerateConfWith(f)) // Entry("with default logcollector bearer token", helpers.ConfGenerateTest{ + // CLFSpec: logging.ClusterLogForwarderSpec{ + // Outputs: []logging.OutputSpec{ + // { + // Type: logging.OutputTypeLoki, + // Name: "loki-receiver", + // URL: "http://lokistack-dev-gateway-http.openshift-logging.svc:8080/api/logs/v1/application", + // }, + // }, + // }, + // Secrets: map[string]*corev1.Secret{ + // constants.LogCollectorToken: { + // Data: map[string][]byte{ + // "token": []byte("token-for-internal-loki"), + // }, + // }, + // }, + // ExpectedConf: ` + //[transforms.loki_receiver_remap] + //type = "remap" + //inputs = ["application"] + //source = ''' + // del(.tag) + //''' + // + //[transforms.loki_receiver_dedot] + //type = "lua" + //inputs = ["loki_receiver_remap"] + //version = "2" + //hooks.init = "init" + //hooks.process = "process" + //source = ''' + // function init() + // count = 0 + // end + // function process(event, emit) + // count = count + 1 + // event.log.openshift.sequence = count + // if event.log.kubernetes == nil then + // emit(event) + // return + // end + // if event.log.kubernetes.labels == nil then + // emit(event) + // return + // end + // dedot(event.log.kubernetes.namespace_labels) + // dedot(event.log.kubernetes.labels) + // emit(event) + // end + // + // function dedot(map) + // if map == nil then + // return + // end + // local new_map = {} + // local changed_keys = {} + // for k, v in pairs(map) do + // local dedotted = string.gsub(k, "[./]", "_") + // if dedotted ~= k then + // new_map[dedotted] = v + // changed_keys[k] = true + // end + // end + // for k in pairs(changed_keys) do + // map[k] = nil + // end + // for k, v in pairs(new_map) do + // map[k] = v + // end + // end + //''' + // + //[sinks.loki_receiver] + //type = "loki" + //inputs = ["loki_receiver_dedot"] + //endpoint = "http://lokistack-dev-gateway-http.openshift-logging.svc:8080/api/logs/v1/application" + //out_of_order_action = "accept" + //healthcheck.enabled = false + // + //[sinks.loki_receiver.encoding] + //codec = "json" + // + //[sinks.loki_receiver.labels] + //kubernetes_container_name = "{{kubernetes.container_name}}" + //kubernetes_host = "${VECTOR_SELF_NODE_NAME}" + //kubernetes_namespace_name = "{{kubernetes.namespace_name}}" + //kubernetes_pod_name = "{{kubernetes.pod_name}}" + //log_type = "{{log_type}}" + // + //[sinks.loki_receiver.tls] + //enabled = true + //ca_file = "/var/run/secrets/kubernetes.io/serviceaccount/service-ca.crt" + //# Bearer Auth Config + //[sinks.loki_receiver.auth] + //strategy = "bearer" + //token = "token-for-internal-loki" + //`, + // }), + +}) + func TestVectorConfGenerator(t *testing.T) { RegisterFailHandler(Fail) RunSpecs(t, "Vector Conf Generation") diff --git a/internal/generator/vector/output/security/security.go b/internal/generator/vector/output/security/security.go index 1c39c3cb5..3a8f38096 100644 --- a/internal/generator/vector/output/security/security.go +++ b/internal/generator/vector/output/security/security.go @@ -54,7 +54,7 @@ enabled = true verify_certificate = false verify_hostname = false {{- end }} -{{- end}}` +{{ end }}` } var NoSecrets = map[string]*corev1.Secret{} diff --git a/internal/generator/vector/output/splunk/splunk.go b/internal/generator/vector/output/splunk/splunk.go index 8b24548ac..4d077aada 100644 --- a/internal/generator/vector/output/splunk/splunk.go +++ b/internal/generator/vector/output/splunk/splunk.go @@ -97,9 +97,6 @@ func Encoding(o logging.OutputSpec) Element { func TLSConf(o logging.OutputSpec, secret *corev1.Secret) []Element { var conf []Element - if o.Secret == nil { - return conf - } hasTLS := false u, _ := url.Parse(o.URL) if urlhelper.IsTLSScheme(u.Scheme) { @@ -125,6 +122,9 @@ func TLSConf(o logging.OutputSpec, secret *corev1.Secret) []Element { conf = append(conf, ca) hasTLS = true } + if o.TLS != nil && o.TLS.InsecureSkipVerify { + hasTLS = true + } } if hasTLS { conf = append([]Element{security.TLSConf{ diff --git a/internal/generator/vector/output/splunk/splunk_test.go b/internal/generator/vector/output/splunk/splunk_test.go index 689ac4886..fcca1d909 100644 --- a/internal/generator/vector/output/splunk/splunk_test.go +++ b/internal/generator/vector/output/splunk/splunk_test.go @@ -1,14 +1,14 @@ package splunk import ( - "testing" - - . "github.com/onsi/ginkgo" - . "github.com/onsi/gomega" - loggingv1 "github.com/openshift/cluster-logging-operator/apis/logging/v1" - "github.com/openshift/cluster-logging-operator/internal/generator" - . "github.com/openshift/cluster-logging-operator/test/matchers" - corev1 "k8s.io/api/core/v1" + "testing" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + loggingv1 "github.com/openshift/cluster-logging-operator/apis/logging/v1" + "github.com/openshift/cluster-logging-operator/internal/generator" + . "github.com/openshift/cluster-logging-operator/test/matchers" + corev1 "k8s.io/api/core/v1" ) // #nosec G101 @@ -16,8 +16,8 @@ const hecToken = "VS0BNth3wCGF0eol0MuK07SHIrhYwCPHFWMG" var _ = Describe("Generating vector config for Splunk output", func() { - const ( - splunkDedot = ` + const ( + splunkDedot = ` [transforms.splunk_hec_dedot] type = "lua" inputs = ["pipelineName"] @@ -66,7 +66,7 @@ source = ''' end ''' ` - splunkSink = splunkDedot + ` + splunkSink = splunkDedot + ` [sinks.splunk_hec] type = "splunk_hec" inputs = ["splunk_hec_dedot"] @@ -76,7 +76,7 @@ default_token = "` + hecToken + `" [sinks.splunk_hec.encoding] codec = "json" ` - splunkSinkTls = splunkDedot + ` + splunkSinkTls = splunkDedot + ` [sinks.splunk_hec] type = "splunk_hec" inputs = ["splunk_hec_dedot"] @@ -91,7 +91,22 @@ key_file = "/var/run/ocp-collector/secrets/vector-splunk-secret-tls/tls.key" crt_file = "/var/run/ocp-collector/secrets/vector-splunk-secret-tls/tls.crt" ca_file = "/var/run/ocp-collector/secrets/vector-splunk-secret-tls/ca-bundle.crt" ` - splunkSinkPassphrase = splunkDedot + ` + splunkSinkTlsSkipVerifyNoCert = splunkDedot + ` +[sinks.splunk_hec] +type = "splunk_hec" +inputs = ["splunk_hec_dedot"] +endpoint = "https://splunk-web:8088/endpoint" +compression = "none" +default_token = "" +[sinks.splunk_hec.encoding] +codec = "json" +[sinks.splunk_hec.tls] +enabled = true +verify_certificate = false +verify_hostname = false +` + + splunkSinkPassphrase = splunkDedot + ` [sinks.splunk_hec] type = "splunk_hec" inputs = ["splunk_hec_dedot"] @@ -106,98 +121,118 @@ codec = "json" enabled = true key_pass = "junk" ` - ) - - var ( - g generator.Generator - - output = loggingv1.OutputSpec{ - Type: loggingv1.OutputTypeSplunk, - Name: "splunk_hec", - URL: "https://splunk-web:8088/endpoint", - OutputTypeSpec: loggingv1.OutputTypeSpec{ - Splunk: &loggingv1.Splunk{}, - }, - Secret: &loggingv1.OutputSecretSpec{ - Name: "vector-splunk-secret", - }, - } - - outputWithPassphrase = loggingv1.OutputSpec{ - Type: loggingv1.OutputTypeSplunk, - Name: "splunk_hec", - URL: "https://splunk-web:8088/endpoint", - OutputTypeSpec: loggingv1.OutputTypeSpec{ - Splunk: &loggingv1.Splunk{}, - }, - Secret: &loggingv1.OutputSecretSpec{ - Name: "vector-splunk-secret-passphrase", - }, - } - outputWithTls = loggingv1.OutputSpec{ - Type: loggingv1.OutputTypeSplunk, - Name: "splunk_hec", - URL: "https://splunk-web:8088/endpoint", - OutputTypeSpec: loggingv1.OutputTypeSpec{ - Splunk: &loggingv1.Splunk{}, - }, - Secret: &loggingv1.OutputSecretSpec{ - Name: "vector-splunk-secret-tls", - }, - } - - secrets = map[string]*corev1.Secret{ - output.Secret.Name: { - Data: map[string][]byte{ - "hecToken": []byte(hecToken), - }, - }, - outputWithTls.Secret.Name: { - Data: map[string][]byte{ - "hecToken": []byte(hecToken), - "tls.key": []byte("junk"), - "tls.crt": []byte("junk"), - "ca-bundle.crt": []byte("junk"), - }, - }, - outputWithPassphrase.Secret.Name: { - Data: map[string][]byte{ - "hecToken": []byte(hecToken), - "passphrase": []byte("junk"), - }, - }, - } - ) - - Context("splunk config", func() { - BeforeEach(func() { - g = generator.MakeGenerator() - }) - - It("should provide a valid config", func() { - element := Conf(output, []string{"pipelineName"}, secrets[output.Secret.Name], nil) - results, err := g.GenerateConf(element...) - Expect(err).To(BeNil()) - Expect(results).To(EqualTrimLines(splunkSink)) - }) - - It("should provide a valid config with passphrase", func() { - element := Conf(outputWithPassphrase, []string{"pipelineName"}, secrets[outputWithPassphrase.Secret.Name], nil) - results, err := g.GenerateConf(element...) - Expect(err).To(BeNil()) - Expect(results).To(EqualTrimLines(splunkSinkPassphrase)) - }) - - It("should provide a valid config with TLS", func() { - element := Conf(outputWithTls, []string{"pipelineName"}, secrets[outputWithTls.Secret.Name], nil) - results, err := g.GenerateConf(element...) - Expect(err).To(BeNil()) - Expect(results).To(EqualTrimLines(splunkSinkTls)) - }) - }) + ) + + var ( + g generator.Generator + + output = loggingv1.OutputSpec{ + Type: loggingv1.OutputTypeSplunk, + Name: "splunk_hec", + URL: "https://splunk-web:8088/endpoint", + OutputTypeSpec: loggingv1.OutputTypeSpec{ + Splunk: &loggingv1.Splunk{}, + }, + Secret: &loggingv1.OutputSecretSpec{ + Name: "vector-splunk-secret", + }, + } + + outputWithPassphrase = loggingv1.OutputSpec{ + Type: loggingv1.OutputTypeSplunk, + Name: "splunk_hec", + URL: "https://splunk-web:8088/endpoint", + OutputTypeSpec: loggingv1.OutputTypeSpec{ + Splunk: &loggingv1.Splunk{}, + }, + Secret: &loggingv1.OutputSecretSpec{ + Name: "vector-splunk-secret-passphrase", + }, + } + outputWithTls = loggingv1.OutputSpec{ + Type: loggingv1.OutputTypeSplunk, + Name: "splunk_hec", + URL: "https://splunk-web:8088/endpoint", + OutputTypeSpec: loggingv1.OutputTypeSpec{ + Splunk: &loggingv1.Splunk{}, + }, + Secret: &loggingv1.OutputSecretSpec{ + Name: "vector-splunk-secret-tls", + }, + } + + outputWithTlsSkipVerifyNoCert = loggingv1.OutputSpec{ + Type: loggingv1.OutputTypeSplunk, + Name: "splunk_hec", + URL: "https://splunk-web:8088/endpoint", + OutputTypeSpec: loggingv1.OutputTypeSpec{ + Splunk: &loggingv1.Splunk{}, + }, + TLS: &loggingv1.OutputTLSSpec{ + InsecureSkipVerify: true, + }, + } + + secrets = map[string]*corev1.Secret{ + output.Secret.Name: { + Data: map[string][]byte{ + "hecToken": []byte(hecToken), + }, + }, + outputWithTls.Secret.Name: { + Data: map[string][]byte{ + "hecToken": []byte(hecToken), + "tls.key": []byte("junk"), + "tls.crt": []byte("junk"), + "ca-bundle.crt": []byte("junk"), + }, + }, + outputWithPassphrase.Secret.Name: { + Data: map[string][]byte{ + "hecToken": []byte(hecToken), + "passphrase": []byte("junk"), + }, + }, + } + ) + + Context("splunk config", func() { + BeforeEach(func() { + g = generator.MakeGenerator() + }) + + It("should provide a valid config", func() { + element := Conf(output, []string{"pipelineName"}, secrets[output.Secret.Name], nil) + results, err := g.GenerateConf(element...) + Expect(err).To(BeNil()) + Expect(results).To(EqualTrimLines(splunkSink)) + }) + + It("should provide a valid config with passphrase", func() { + element := Conf(outputWithPassphrase, []string{"pipelineName"}, secrets[outputWithPassphrase.Secret.Name], nil) + results, err := g.GenerateConf(element...) + Expect(err).To(BeNil()) + Expect(results).To(EqualTrimLines(splunkSinkPassphrase)) + }) + + It("should provide a valid config with TLS", func() { + element := Conf(outputWithTls, []string{"pipelineName"}, secrets[outputWithTls.Secret.Name], nil) + results, err := g.GenerateConf(element...) + Expect(err).To(BeNil()) + Expect(results).To(EqualTrimLines(splunkSinkTls)) + }) + + It("should provide a valid config with tls.insecureSkipVerify=true without secret", func() { + element := Conf(outputWithTlsSkipVerifyNoCert, []string{"pipelineName"}, nil, nil) + results, err := g.GenerateConf(element...) + Expect(err).To(BeNil()) + Expect(results).To(EqualTrimLines(splunkSinkTlsSkipVerifyNoCert)) + }) + + }) }) func TestVectorConfGenerator(t *testing.T) { - RegisterFailHandler(Fail) - RunSpecs(t, "Vector for Splunk Conf Generation") + RegisterFailHandler(Fail) + RunSpecs(t, "Vector for Splunk Conf Generation") } diff --git a/internal/validations/clusterlogforwarder/suite_test.go b/internal/validations/clusterlogforwarder/suite_test.go index 7c310ea69..74a30914d 100644 --- a/internal/validations/clusterlogforwarder/suite_test.go +++ b/internal/validations/clusterlogforwarder/suite_test.go @@ -1,12 +1,13 @@ package clusterlogforwarder import ( + "testing" + . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" - "testing" ) func TestInternalValidationsClusterLogForwarder(t *testing.T) { RegisterFailHandler(Fail) - RunSpecs(t, "[internal][validations][clustrelogforwarder] Suite") + RunSpecs(t, "[internal][validations][clusterlogforwarder] Suite") } diff --git a/internal/validations/clusterlogforwarder/validate_url_to_output_tls_config.go b/internal/validations/clusterlogforwarder/validate_url_to_output_tls_config.go new file mode 100644 index 000000000..ff03bd987 --- /dev/null +++ b/internal/validations/clusterlogforwarder/validate_url_to_output_tls_config.go @@ -0,0 +1,24 @@ +package clusterlogforwarder + +import ( + "fmt" + log "github.com/ViaQ/logerr/v2/log/static" + "github.com/openshift/cluster-logging-operator/apis/logging/v1" + "github.com/openshift/cluster-logging-operator/internal/url" + "strings" +) + +// validateUrlAccordingToTls validate that if Output has TLS configuration Output URL scheme must be secure e.g. https, tls etc +func validateUrlAccordingToTls(clf v1.ClusterLogForwarder) error { + for i, output := range clf.Spec.Outputs { + _, output := i, output // Don't bind range variable. + u, _ := url.Parse(output.URL) + scheme := strings.ToLower(u.Scheme) + if !url.IsTLSScheme(scheme) && output.TLS != nil && output.TLS.InsecureSkipVerify { + log.V(3).Info("validateUrlAccordingToTls failed", "reason", "URL not secure but output has TLS configuration parameters", + "output URL", output.URL, "output Name", output.Name) + return fmt.Errorf("URL not secure: %v, but output %s has TLS configuration parameters", u, output.Name) + } + } + return nil +} diff --git a/internal/validations/clusterlogforwarder/validate_url_to_output_tls_test.go b/internal/validations/clusterlogforwarder/validate_url_to_output_tls_test.go new file mode 100644 index 000000000..c073e65a8 --- /dev/null +++ b/internal/validations/clusterlogforwarder/validate_url_to_output_tls_test.go @@ -0,0 +1,55 @@ +package clusterlogforwarder + +import ( + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "github.com/openshift/cluster-logging-operator/apis/logging/v1" +) + +var _ = Describe("[internal][validations] ClusterLogForwarder: Output URL vs Output TLS", func() { + var clf = &v1.ClusterLogForwarder{ + Spec: v1.ClusterLogForwarderSpec{ + Outputs: []v1.OutputSpec{ + { + Name: "myOutput", + }, + }, + }, + } + + Context("#validateUrlAccordingToTls", func() { + It("should fail validation when not secure URL and tls.InsecureSkipVerify=true", func() { + clf.Spec.Outputs[0].URL = "http://local.svc:514" + clf.Spec.Outputs[0].TLS = &v1.OutputTLSSpec{ + InsecureSkipVerify: true, + } + Expect(validateUrlAccordingToTls(*clf)).To(Not(Succeed())) + }) + It("should pass validation when not secure URL and no TLS config", func() { + clf.Spec.Outputs[0].URL = "http://local.svc:514" + clf.Spec.Outputs[0].TLS = nil + Expect(validateUrlAccordingToTls(*clf)).To(Succeed()) + }) + It("should pass validation when when not secure URL and tls.InsecureSkipVerify=false", func() { + clf.Spec.Outputs[0].URL = "http://local.svc:514" + clf.Spec.Outputs[0].TLS = &v1.OutputTLSSpec{ + InsecureSkipVerify: false, + } + Expect(validateUrlAccordingToTls(*clf)).To(Succeed()) + }) + It("should pass validation when secure URL and exist TLS config: tls.InsecureSkipVerify=true", func() { + clf.Spec.Outputs[0].URL = "https://local.svc:514" + clf.Spec.Outputs[0].TLS = &v1.OutputTLSSpec{ + InsecureSkipVerify: true, + } + Expect(validateUrlAccordingToTls(*clf)).To(Succeed()) + }) + It("should pass pass validation when secure URL and exist TLS config: tls.InsecureSkipVerify=false", func() { + clf.Spec.Outputs[0].URL = "https://local.svc:514" + clf.Spec.Outputs[0].TLS = &v1.OutputTLSSpec{ + InsecureSkipVerify: false, + } + Expect(validateUrlAccordingToTls(*clf)).To(Succeed()) + }) + }) +}) diff --git a/internal/validations/clusterlogforwarder/validations.go b/internal/validations/clusterlogforwarder/validations.go index 3d7ac8ec8..dd2ad629e 100644 --- a/internal/validations/clusterlogforwarder/validations.go +++ b/internal/validations/clusterlogforwarder/validations.go @@ -16,4 +16,5 @@ func Validate(clf v1.ClusterLogForwarder) error { var validations = []func(clf v1.ClusterLogForwarder) error{ validateSingleton, validateJsonParsingToElasticsearch, + validateUrlAccordingToTls, }