← Back to Topics
defensive 3 min read Created: Apr 12, 2026

Restricting Prometheus Endpoint Access

Preventing unauthenticated access to Prometheus metrics that expose cluster topology, pod identities, and internal service addresses

Prometheus ships with no authentication enabled by default. Any pod in the cluster that can reach the Prometheus service can query the full metrics database, retrieve container image inventories, map internal services, and read node details, all without touching the Kubernetes API. Two controls close this gap: enabling authentication on the Prometheus HTTP endpoint and restricting network access via NetworkPolicy.

Enabling Basic Auth via web.config.file

Prometheus supports basic auth through a web configuration file passed via the --web.config.file flag. The file uses bcrypt-hashed passwords.

Generate a bcrypt hash for the password:

python3 -c "import bcrypt; print(bcrypt.hashpw(b'your-password', bcrypt.gensalt(rounds=10)).decode())"
$2b$10$OFBLW.e.aIu5vio8uMN3TO4qXzs9BuIj970yGTmOezdwfVavwhLTW

Create the web configuration file:

basic_auth_users:
  admin: $2b$10$OFBLW.e.aIu5vio8uMN3TO4qXzs9BuIj970yGTmOezdwfVavwhLTW

Store it as a ConfigMap and mount it into the Prometheus pod:

apiVersion: v1
kind: ConfigMap
metadata:
  name: prometheus-web-config
  namespace: monitoring
data:
  web.yml: |
    basic_auth_users:
      admin: $2b$10$OFBLW.e.aIu5vio8uMN3TO4qXzs9BuIj970yGTmOezdwfVavwhLTW

Pass the flag and mount the volume in the Prometheus deployment:

containers:
  - name: prometheus-server
    args:
      - --web.config.file=/etc/prometheus/web-config/web.yml
    volumeMounts:
      - name: web-config
        mountPath: /etc/prometheus/web-config
volumes:
  - name: web-config
    configMap:
      name: prometheus-web-config

Once the pod restarts, unauthenticated requests return 401 Unauthorized:

HTTP/1.1 401 Unauthorized

Requests with valid credentials return 200 OK:

HTTP/1.1 200 OK

If you are using the prometheus-community Helm chart, pass the flag via server.extraFlags and mount the ConfigMap via server.extraVolumes and server.extraVolumeMounts. The chart’s default liveness and readiness probes hit /-/healthy via plain HTTP without credentials. After enabling basic auth, those probes return 401 and the kubelet restarts the container in a loop. Set server.probeHeaders to inject the Authorization header into both probes:

server:
  probeHeaders:
    - name: "Authorization"
      value: "Basic <base64-encoded-user:password>"

Restricting Access with NetworkPolicy

A NetworkPolicy limits which pods can initiate connections to the Prometheus pod. The following policy denies all ingress to the Prometheus pod except from pods carrying the label role: monitoring-access:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: prometheus-restrict-ingress
  namespace: monitoring
spec:
  podSelector:
    matchLabels:
      app.kubernetes.io/name: prometheus
      app.kubernetes.io/component: server
  policyTypes:
  - Ingress
  ingress:
  - from:
    - podSelector:
        matchLabels:
          role: monitoring-access
    ports:
    - protocol: TCP
      port: 9090

To also allow access from a specific namespace such as a dedicated Grafana namespace:

  ingress:
  - from:
    - namespaceSelector:
        matchLabels:
          kubernetes.io/metadata.name: grafana
    - podSelector:
        matchLabels:
          role: monitoring-access
    ports:
    - protocol: TCP
      port: 9090

NetworkPolicy enforcement depends on the CNI plugin. Calico and Cilium enforce NetworkPolicy rules.

Limitations

Basic auth credentials are transmitted in the Authorization header as a base64-encoded string. Without TLS, credentials are readable on the network. Configure TLS on the Prometheus endpoint alongside basic auth, or terminate TLS at an ingress or sidecar proxy in front of the service.

NetworkPolicy restricts pod-to-pod access but does not protect against connections initiated by users with kubectl port-forward access to the Prometheus pod or namespace. Restricting the pods/portforward verb via RBAC covers that path. A role that grants read access to pods without allowing port-forward:

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: prometheus-read-only
  namespace: monitoring
rules:
  - apiGroups: [""]
    resources: ["pods"]
    verbs: ["get", "list"]

Any attempt to port-forward without the pods/portforward verb is rejected at the API server:

error: pods "prometheus-server-8545d4469-dq4td" is forbidden: User "system:serviceaccount:monitoring:restricted-user" cannot create resource "pods/portforward" in API group "" in the namespace "monitoring"

Basic auth credentials are transmitted in the Authorization header as a base64-encoded username:password string. The value Basic YWRtaW46cHJvbS1zZWNyZXQ= decodes to admin:prom-secret. Without TLS on the connection, any party observing the traffic can read the credentials. Configure TLS on the Prometheus endpoint or terminate it at an ingress or sidecar proxy in front of the service.

Impact

An open Prometheus endpoint gives an attacker inside the cluster a full map of namespaces, pod names, container images, service IPs, and node details without making a single Kubernetes API call. Enabling authentication and restricting network access removes that passive reconnaissance path.

Mitigation

  • Enable basic auth or TLS on the Prometheus HTTP endpoint using the --web.config.file flag
  • Apply a NetworkPolicy that restricts ingress to the Prometheus pod to only authorized namespaces or pods, blocking arbitrary workloads from querying the metrics API
  • Treat port-forward access to the Prometheus pod as a sensitive operation subject to the same RBAC controls as other privileged resources