Skip to content

Commit 301fda3

Browse files
committed
Ensure Platform Prometheus targets are protected
1 parent 848143e commit 301fda3

File tree

2 files changed

+103
-0
lines changed

2 files changed

+103
-0
lines changed

test/extended/prometheus/prometheus.go

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import (
55
"context"
66
"encoding/json"
77
"fmt"
8+
"net/http"
9+
"os"
810
"regexp"
911
"strings"
1012
"time"
@@ -49,6 +51,92 @@ type TelemeterClientConfig struct {
4951
Enabled *bool `json:"enabled"`
5052
}
5153

54+
// Set $MONITORING_AUTH_TEST_NAMESPACE to focus on the targets from a single namespace
55+
var monitoringAuthTestNamespace = os.Getenv("MONITORING_AUTH_TEST_NAMESPACE")
56+
57+
var _ = g.Describe("[sig-instrumentation][Late] Platform Prometheus targets", func() {
58+
defer g.GinkgoRecover()
59+
var (
60+
oc = exutil.NewCLIWithPodSecurityLevel("prometheus", admissionapi.LevelBaseline)
61+
prometheusURL, bearerToken string
62+
63+
// TODO: remove the namespace when the bug is fixed.
64+
namespacesToSkip = sets.New[string]("openshift-marketplace", // https://issues.redhat.com/browse/OCPBUGS-59763
65+
"openshift-image-registry", // https://issues.redhat.com/browse/OCPBUGS-59767
66+
"openshift-operator-lifecycle-manager", // https://issues.redhat.com/browse/OCPBUGS-59768
67+
"openshift-cluster-samples-operator", // https://issues.redhat.com/browse/OCPBUGS-59769
68+
"openshift-cluster-version", // https://issues.redhat.com/browse/OCPBUGS-57585
69+
"openshift-cluster-csi-drivers", // https://issues.redhat.com/browse/OCPBUGS-60159
70+
"openshift-cluster-node-tuning-operator", // https://issues.redhat.com/browse/OCPBUGS-60258
71+
"openshift-etcd", // https://issues.redhat.com/browse/OCPBUGS-60263
72+
)
73+
)
74+
75+
g.BeforeEach(func(ctx g.SpecContext) {
76+
var err error
77+
prometheusURL, err = helper.PrometheusRouteURL(ctx, oc)
78+
o.Expect(err).NotTo(o.HaveOccurred(), "Get public url of prometheus")
79+
bearerToken, err = helper.RequestPrometheusServiceAccountAPIToken(ctx, oc)
80+
o.Expect(err).NotTo(o.HaveOccurred(), "Request prometheus service account API token")
81+
82+
if namespacesToSkip.Has(monitoringAuthTestNamespace) {
83+
e2e.Logf("The namespace %s is not skipped because $MONITORING_AUTH_TEST_NAMESPACE is set to it", monitoringAuthTestNamespace)
84+
namespacesToSkip.Delete(monitoringAuthTestNamespace)
85+
}
86+
})
87+
88+
g.It("should not be accessible without auth [Serial]", func() {
89+
var errs []error
90+
91+
g.By("checking that targets reject the requests with 401 or 403")
92+
execPod := exutil.CreateExecPodOrFail(oc.AdminKubeClient(), oc.Namespace(), "execpod-targets-authorization")
93+
defer func() {
94+
err := oc.AdminKubeClient().CoreV1().Pods(execPod.Namespace).Delete(context.Background(), execPod.Name, *metav1.NewDeleteOptions(1))
95+
o.Expect(err).NotTo(o.HaveOccurred(), fmt.Sprintf("Delete pod %s/%s", execPod.Namespace, execPod.Name))
96+
}()
97+
98+
contents, err := helper.GetURLWithToken(helper.MustJoinUrlPath(prometheusURL, "api/v1/targets"), bearerToken)
99+
o.Expect(err).NotTo(o.HaveOccurred())
100+
101+
targets := &prometheusTargets{}
102+
err = json.Unmarshal([]byte(contents), targets)
103+
o.Expect(err).NotTo(o.HaveOccurred())
104+
o.Expect(len(targets.Data.ActiveTargets)).Should(o.BeNumerically(">=", 5))
105+
106+
expected := sets.New[int](http.StatusUnauthorized, http.StatusForbidden)
107+
for _, target := range targets.Data.ActiveTargets {
108+
ns := target.Labels["namespace"]
109+
o.Expect(ns).NotTo(o.BeEmpty())
110+
if monitoringAuthTestNamespace != "" && ns != monitoringAuthTestNamespace {
111+
continue
112+
}
113+
pod := target.Labels["pod"]
114+
e2e.Logf("Checking via pod exec status code from the scaple url %s for pod %s/%s without authorization (skip=%t)", target.ScrapeUrl, ns, pod, namespacesToSkip.Has(ns))
115+
err := wait.PollUntilContextTimeout(context.Background(), 10*time.Second, 5*time.Minute, true, func(context.Context) (bool, error) {
116+
statusCode, execError := helper.URLStatusCodeExecViaPod(execPod.Namespace, execPod.Name, target.ScrapeUrl)
117+
e2e.Logf("The scaple url %s for pod %s/%s without authorization returned %d, %v (skip=%t)", target.ScrapeUrl, ns, pod, statusCode, execError, namespacesToSkip.Has(ns))
118+
if expected.Has(statusCode) {
119+
return true, nil
120+
}
121+
// retry on those cases
122+
if execError != nil ||
123+
statusCode/100 == 5 ||
124+
statusCode == http.StatusRequestTimeout ||
125+
statusCode == http.StatusTooManyRequests {
126+
return false, nil
127+
}
128+
return false, fmt.Errorf("expecting status code %v but returned %d", expected.UnsortedList(), statusCode)
129+
})
130+
if err != nil && !namespacesToSkip.Has(ns) {
131+
errs = append(errs, fmt.Errorf("the scaple url %s for pod %s/%s is accessible without authorization: %w", target.ScrapeUrl, ns, pod, err))
132+
}
133+
}
134+
135+
o.Expect(errs).To(o.BeEmpty())
136+
})
137+
138+
})
139+
52140
var _ = g.Describe("[sig-instrumentation][Late] OpenShift alerting rules [apigroup:image.openshift.io]", func() {
53141
defer g.GinkgoRecover()
54142

test/extended/util/prometheus/helpers.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,21 @@ func ExpectURLStatusCodeExecViaPod(ns, execPodName, url string, statusCodes ...i
299299
return fmt.Errorf("last response from server was not in %v: %s", statusCodes, output)
300300
}
301301

302+
// URLStatusCodeExecViaPod attempts connection to url via exec pod and returns the status code
303+
// or an error if any errors happens during the process.
304+
func URLStatusCodeExecViaPod(ns, name, url string) (int, error) {
305+
cmd := fmt.Sprintf("curl -k -s -o /dev/null -w '%%{http_code}' %q", url)
306+
output, err := e2eoutput.RunHostCmd(ns, name, cmd)
307+
if err != nil {
308+
return 0, fmt.Errorf("host command failed: %v\n%s", err, output)
309+
}
310+
ret, err := strconv.Atoi(output)
311+
if err != nil {
312+
return 0, fmt.Errorf("unable to parse status code out of the command's ouput: %v\n%s", err, output)
313+
}
314+
return ret, nil
315+
}
316+
302317
// ExpectPrometheusEndpoint attempts to connect to the metrics endpoint with
303318
// delayed retries upon failure.
304319
func ExpectPrometheusEndpoint(url string) {

0 commit comments

Comments
 (0)