From 6ed9f10da5b86688a57867e304e603df2eaef503 Mon Sep 17 00:00:00 2001 From: Aliaksandr Valialkin Date: Mon, 13 Sep 2021 13:03:42 +0300 Subject: [PATCH] lib/promscrape/discovery/kubernetes: properly use https scheme for wildcard TLS certificates in ingress target discovery See https://github.com/prometheus/prometheus/issues/8902 --- docs/CHANGELOG.md | 1 + .../discovery/kubernetes/ingress.go | 39 ++++++++++++++----- .../discovery/kubernetes/ingress_test.go | 20 ++++++++++ 3 files changed, 50 insertions(+), 10 deletions(-) diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 405b289023..59cdb9e770 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -20,6 +20,7 @@ sort: 15 * BUGFIX: properly handle queries with multiple filters matching empty labels such as `metric{label1=~"foo|",label2="bar|"}`. This filter must match the following series: `metric`, `metric{label1="foo"}`, `metric{label2="bar"}` and `metric{label1="foo",label2="bar"}`. Previously it was matching only `metric{label1="foo",label2="bar"}`. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/1601). * BUGFIX: vmselect: reset connection timeouts after each request to `vmstorage`. This should prevent from `cannot read data in 0.000 seconds: unexpected EOF` warning in logs. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/1562). Thanks to @mxlxm . * BUGFIX: keep metric name for time series returned from [rollup_candlestick](https://docs.victoriametrics.com/MetricsQL.html#rollup_candlestick) function, since the returned series don't change the meaning of the original series. See [this issue](https://github.com/VictoriaMetrics/VictoriaMetrics/issues/1600). +* BUGFIX: vmagent: properly use `https` scheme for wildcard TLS certificates for `role: ingress` targets in Kubernetes service discovery. See [this issue](https://github.com/prometheus/prometheus/issues/8902). ## [v1.65.0](https://github.com/VictoriaMetrics/VictoriaMetrics/releases/tag/v1.65.0) diff --git a/lib/promscrape/discovery/kubernetes/ingress.go b/lib/promscrape/discovery/kubernetes/ingress.go index deedd32f2f..71b398bd42 100644 --- a/lib/promscrape/discovery/kubernetes/ingress.go +++ b/lib/promscrape/discovery/kubernetes/ingress.go @@ -4,6 +4,7 @@ import ( "encoding/json" "fmt" "io" + "strings" ) func (ig *Ingress) key() string { @@ -88,19 +89,10 @@ type HTTPIngressPath struct { // // See https://prometheus.io/docs/prometheus/latest/configuration/configuration/#ingress func (ig *Ingress) getTargetLabels(gw *groupWatcher) []map[string]string { - tlsHosts := make(map[string]bool) - for _, tls := range ig.Spec.TLS { - for _, host := range tls.Hosts { - tlsHosts[host] = true - } - } var ms []map[string]string for _, r := range ig.Spec.Rules { paths := getIngressRulePaths(r.HTTP.Paths) - scheme := "http" - if tlsHosts[r.Host] { - scheme = "https" - } + scheme := getSchemeForHost(r.Host, ig.Spec.TLS) for _, path := range paths { m := getLabelsForIngressPath(ig, scheme, r.Host, path) ms = append(ms, m) @@ -109,6 +101,33 @@ func (ig *Ingress) getTargetLabels(gw *groupWatcher) []map[string]string { return ms } +func getSchemeForHost(host string, tlss []IngressTLS) string { + for _, tls := range tlss { + for _, hostPattern := range tls.Hosts { + if matchesHostPattern(hostPattern, host) { + return "https" + } + } + } + return "http" +} + +func matchesHostPattern(pattern, host string) bool { + if pattern == host { + return true + } + if !strings.HasPrefix(pattern, "*.") { + return false + } + pattern = pattern[len("*."):] + n := strings.IndexByte(host, '.') + if n < 0 { + return false + } + host = host[n+1:] + return pattern == host +} + func getLabelsForIngressPath(ig *Ingress, scheme, host, path string) map[string]string { m := map[string]string{ "__address__": host, diff --git a/lib/promscrape/discovery/kubernetes/ingress_test.go b/lib/promscrape/discovery/kubernetes/ingress_test.go index 149660b80f..87a734d05e 100644 --- a/lib/promscrape/discovery/kubernetes/ingress_test.go +++ b/lib/promscrape/discovery/kubernetes/ingress_test.go @@ -8,6 +8,26 @@ import ( "github.com/VictoriaMetrics/VictoriaMetrics/lib/promscrape/discoveryutils" ) +func TestMatchesHostPattern(t *testing.T) { + f := func(pattern, host string, resultExpected bool) { + t.Helper() + result := matchesHostPattern(pattern, host) + if result != resultExpected { + t.Fatalf("unexpected result for matchesHostPattern(%q, %q); got %v; want %v", pattern, host, result, resultExpected) + } + } + f("", "", true) + f("", "foo", false) + f("foo", "", false) + f("localhost", "localhost", true) + f("localhost", "localhost2", false) + f("*.foo", "bar", false) + f("foo.bar", "foo.bar", true) + f("foo.baz", "foo.bar", false) + f("a.x.yyy", "b.x.yyy", false) + f("*.x.yyy", "b.x.yyy", true) +} + func TestParseIngressListFailure(t *testing.T) { f := func(s string) { t.Helper()