From 5d2fa25304ead15dd8d91aaf364bf223de4e40ce Mon Sep 17 00:00:00 2001 From: rwxd Date: Fri, 9 Feb 2024 14:11:54 +0100 Subject: [PATCH] feat(metrics): use basic auth instead of api token --- README.md | 7 +++++-- powerdns_api_proxy/config.py | 21 ++++++++++++++++----- powerdns_api_proxy/models.py | 2 +- powerdns_api_proxy/proxy.py | 6 +----- 4 files changed, 23 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index c5a83d4..69ac065 100644 --- a/README.md +++ b/README.md @@ -216,8 +216,6 @@ metrics_require_auth: false # default is true When the `metrics_proxy` option is set to `true`, the environment has access to the `/metrics` endpoint of the proxy. -That is needed, when the `metrics_require_auth` option is set to `true` (default). - ```yaml ... environments: @@ -225,6 +223,11 @@ environments: metrics_proxy: true ``` +When `metrics_require_auth` is enabled, basic auth needs to be used. + +* username: name of the environment +* password: token + #### Metrics The [prometheus-fastapi-instrumentator](https://github.com/trallnag/prometheus-fastapi-instrumentator) is used for the default metrics. diff --git a/powerdns_api_proxy/config.py b/powerdns_api_proxy/config.py index dc64ce9..54969ce 100644 --- a/powerdns_api_proxy/config.py +++ b/powerdns_api_proxy/config.py @@ -2,9 +2,10 @@ import os from functools import lru_cache from pathlib import Path -from typing import Optional +from typing import Annotated, Optional -from fastapi import Header, HTTPException +from fastapi import Depends, Header, HTTPException +from fastapi.security import HTTPBasic, HTTPBasicCredentials from yaml import safe_load from powerdns_api_proxy.logging import logger @@ -58,15 +59,25 @@ def dependency_check_token_defined( check_token_defined(load_config(), X_API_Key) +security = HTTPBasic() + + def dependency_metrics_proxy_enabled( - X_API_Key: str = Header(description='API Key for the proxy.'), + credentials: Annotated[HTTPBasicCredentials, Depends(security)] = Header( + description='API Key for the proxy.' + ), ): + username = credentials.username + password = credentials.password + try: - environment = get_environment_for_token(load_config(), X_API_Key) + environment = get_environment_for_token(load_config(), password) + if not environment.name == username: + raise NotAuthorizedException() if not environment.metrics_proxy: raise MetricsNotAllowedException() except ValueError: - raise MetricsNotAllowedException() + raise NotAuthorizedException() def get_environment_for_token( diff --git a/powerdns_api_proxy/models.py b/powerdns_api_proxy/models.py index b0b7117..efe6425 100644 --- a/powerdns_api_proxy/models.py +++ b/powerdns_api_proxy/models.py @@ -210,7 +210,7 @@ def __init__(self): class NotAuthorizedException(HTTPException): def __init__(self): self.status_code = 401 - self.detail = 'Not authorized' + self.detail = 'Unauthorized' class SearchNotAllowedException(HTTPException): diff --git a/powerdns_api_proxy/proxy.py b/powerdns_api_proxy/proxy.py index 9ed27ec..5016667 100644 --- a/powerdns_api_proxy/proxy.py +++ b/powerdns_api_proxy/proxy.py @@ -79,11 +79,7 @@ async def _startup(app: FastAPI): if config.metrics_require_auth: logger.info('Enabling metrics authentication') instrumentator.expose( - app, - dependencies=[ - Depends(dependency_check_token_defined), - Depends(dependency_metrics_proxy_enabled), - ], + app, dependencies=[Depends(dependency_metrics_proxy_enabled)] ) else: instrumentator.expose(app)