4
4
import re
5
5
import warnings
6
6
from enum import Enum
7
- from typing import Any , Awaitable , Callable , List , Optional , Sequence , Union , cast
7
+ from typing import Any , Awaitable , Callable , List , Optional , Sequence , Union , cast , Tuple
8
+ from base64 import b64encode
8
9
9
- from fastapi import FastAPI
10
+ from fastapi import FastAPI , HTTPException
10
11
from prometheus_client import (
11
12
CONTENT_TYPE_LATEST ,
12
13
REGISTRY ,
@@ -227,6 +228,7 @@ def expose(
227
228
endpoint : str = "/metrics" ,
228
229
include_in_schema : bool = True ,
229
230
tags : Optional [List [Union [str , Enum ]]] = None ,
231
+ basic_auth : Optional [Tuple [str , str ]] = None ,
230
232
** kwargs : Any ,
231
233
) -> "PrometheusFastApiInstrumentator" :
232
234
"""Exposes endpoint for metrics.
@@ -246,6 +248,9 @@ def expose(
246
248
247
249
tags (List[str], optional): If you manage your routes with tags.
248
250
Defaults to None.
251
+
252
+ basic_auth (Tuple[str, str], optional): username and password for
253
+ HTTP basic authentication. Disabled if None.
249
254
250
255
kwargs: Will be passed to FastAPI route annotation.
251
256
@@ -256,10 +261,23 @@ def expose(
256
261
if self .should_respect_env_var and not self ._should_instrumentate ():
257
262
return self
258
263
264
+ authorization_value = None
265
+ if basic_auth is not None :
266
+ username , password = basic_auth
267
+ encoded_cred = b64encode (f'{ username } :{ password } ' .encode ('utf-8' )).decode ('ascii' )
268
+ authorization_value = f"Basic { encoded_cred } "
269
+
259
270
@app .get (endpoint , include_in_schema = include_in_schema , tags = tags , ** kwargs )
260
271
def metrics (request : Request ) -> Response :
261
272
"""Endpoint that serves Prometheus metrics."""
262
273
274
+ authorization_header = request .headers .get ('authorization' , None )
275
+ if authorization_header != authorization_value :
276
+ raise HTTPException (
277
+ status_code = 401 ,
278
+ headers = {'WWW-Authenticate' : 'Basic realm="Access to metrics endpoint"' }
279
+ )
280
+
263
281
ephemeral_registry = self .registry
264
282
if "PROMETHEUS_MULTIPROC_DIR" in os .environ :
265
283
ephemeral_registry = CollectorRegistry ()
0 commit comments