diff --git a/go.mod b/go.mod index 3d684cbfbe088..8cbf50485aa6a 100644 --- a/go.mod +++ b/go.mod @@ -102,6 +102,7 @@ require ( github.com/huandu/xstrings v1.4.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/josharian/intern v1.0.0 // indirect + github.com/jpillora/backoff v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/compress v1.17.9 // indirect github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect @@ -116,6 +117,7 @@ require ( github.com/modern-go/reflect2 v1.0.2 // indirect github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f // indirect github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.0-rc6 // indirect diff --git a/viz/charts/linkerd-viz/README.md b/viz/charts/linkerd-viz/README.md index 8ed126c478826..178b014f94935 100644 --- a/viz/charts/linkerd-viz/README.md +++ b/viz/charts/linkerd-viz/README.md @@ -160,6 +160,7 @@ Kubernetes: `>=1.22.0-0` | prometheus.scrapeConfigs | string | `nil` | A scrapeConfigs section specifies a set of targets and parameters describing how to scrape them. | | prometheus.sidecarContainers | string | `nil` | A sidecarContainers section specifies a list of secondary containers to run in the prometheus pod e.g. to export data to non-prometheus systems | | prometheus.tolerations | string | `nil` | Tolerations section, See the [K8S documentation](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/) for more information | +| prometheusCredsSecret | string | `""` | Name of the prometheus credentials secret. If this is set, the metrics-api will use basic auth to connect to prometheus and load the user and password from the "user" and "password" keys respectively in the given secret. The secret must be in the same namespace and must exist before the metrics-api is deployed. | | prometheusUrl | string | `""` | url of external prometheus instance | | revisionHistoryLimit | int | `10` | Specifies the number of old ReplicaSets to retain to allow rollback. | | tap.GID | string | `nil` | GID for the tap component | diff --git a/viz/charts/linkerd-viz/templates/metrics-api.yaml b/viz/charts/linkerd-viz/templates/metrics-api.yaml index 7a0da53d4f3c6..526bb78f832c1 100644 --- a/viz/charts/linkerd-viz/templates/metrics-api.yaml +++ b/viz/charts/linkerd-viz/templates/metrics-api.yaml @@ -88,6 +88,10 @@ spec: {{- else }} {{ fail "Please enable `linkerd-prometheus` or provide `prometheusUrl` for the viz extension to function properly"}} {{- end }} + {{- if .Values.prometheusCredsSecret }} + - -prometheus-user-file=/var/prometheus/user + - -prometheus-password-file=/var/prometheus/password + {{- end}} - -enable-pprof={{.Values.enablePprof | default false}} image: {{.Values.metricsAPI.image.registry | default .Values.defaultRegistry}}/{{.Values.metricsAPI.image.name}}:{{.Values.metricsAPI.image.tag | default .Values.linkerdVersion}} imagePullPolicy: {{.Values.metricsAPI.image.pullPolicy | default .Values.defaultImagePullPolicy}} @@ -121,10 +125,22 @@ spec: runAsGroup: {{.Values.metricsAPI.GID | default .Values.defaultGID}} seccompProfile: type: RuntimeDefault + {{- if .Values.prometheusCredsSecret }} + volumeMounts: + - mountPath: /var/prometheus + name: prom-creds + readOnly: true + {{- end}} securityContext: seccompProfile: type: RuntimeDefault serviceAccountName: metrics-api + {{- with .Values.prometheusCredsSecret }} + volumes: + - name: prom-creds + secret: + secretName: {{ . }} + {{- end }} {{- if and .Values.enablePodDisruptionBudget (gt (int .Values.metricsAPI.replicas) 1) }} --- kind: PodDisruptionBudget diff --git a/viz/charts/linkerd-viz/values.yaml b/viz/charts/linkerd-viz/values.yaml index c3ebc6af59950..008e207b497ef 100644 --- a/viz/charts/linkerd-viz/values.yaml +++ b/viz/charts/linkerd-viz/values.yaml @@ -75,6 +75,13 @@ enablePSP: false # -- url of external prometheus instance prometheusUrl: "" +# -- Name of the prometheus credentials secret. If this is set, the metrics-api +# will use basic auth to connect to prometheus and load the user and password +# from the "user" and "password" keys respectively in the given secret. The +# secret must be in the same namespace and must exist before the metrics-api is +# deployed. +prometheusCredsSecret: "" + # -- url of external jaeger instance # Set this to `jaeger.linkerd-jaeger.svc.:16686` if you plan to use jaeger extension jaegerUrl: "" diff --git a/viz/metrics-api/cmd/main.go b/viz/metrics-api/cmd/main.go index 7a72a6692354c..76ef145020633 100644 --- a/viz/metrics-api/cmd/main.go +++ b/viz/metrics-api/cmd/main.go @@ -16,6 +16,7 @@ import ( api "github.com/linkerd/linkerd2/viz/metrics-api" promApi "github.com/prometheus/client_golang/api" promv1 "github.com/prometheus/client_golang/api/prometheus/v1" + "github.com/prometheus/common/config" log "github.com/sirupsen/logrus" ) @@ -25,6 +26,8 @@ func main() { addr := cmd.String("addr", ":8085", "address to serve on") kubeConfigPath := cmd.String("kubeconfig", "", "path to kube config") prometheusURL := cmd.String("prometheus-url", "", "prometheus url") + prometheusUser := cmd.String("prometheus-user-file", "", "file containing username for prometheus basic auth") + prometheusPassword := cmd.String("prometheus-password-file", "", "file containing password for prometheus basic auth") metricsAddr := cmd.String("metrics-addr", ":9995", "address to serve scrapable metrics on") controllerNamespace := cmd.String("controller-namespace", "linkerd", "namespace in which Linkerd is installed") ignoredNamespaces := cmd.String("ignore-namespaces", "kube-system", "comma separated list of namespaces to not list pods from") @@ -63,7 +66,25 @@ func main() { var prometheusClient promApi.Client if *prometheusURL != "" { - prometheusClient, err = promApi.NewClient(promApi.Config{Address: *prometheusURL}) + promConfig := promApi.Config{Address: *prometheusURL} + if *prometheusUser != "" && *prometheusPassword != "" { + user, err := os.ReadFile(*prometheusUser) + if err != nil { + log.Fatalf("failed to read file containing username for prometheus basic auth: %s", err) + } + password, err := os.ReadFile(*prometheusPassword) + if err != nil { + log.Fatalf("failed to read file containing password for prometheus basic auth: %s", err) + } + promConfig.RoundTripper = config.NewBasicAuthRoundTripper( + config.NewInlineSecret(string(user)), + config.NewInlineSecret(string(password)), + promApi.DefaultRoundTripper, + ) + } else if *prometheusUser != "" || *prometheusPassword != "" { + log.Fatal("both prometheus-user-file and prometheus-password-file must be set") + } + prometheusClient, err = promApi.NewClient(promConfig) if err != nil { log.Fatal(err.Error()) }