golang

Ограничение доступа к метрикам Node Exporter по IP-адресам

  • воскресенье, 23 февраля 2025 г. в 00:00:09
https://habr.com/ru/articles/884786/

В современных инфраструктурах информационной безопасности одной из ключевых задач является ограничение доступа к системным метрикам. По умолчанию Prometheus Node Exporter предоставляет метрики в открытом доступе, что может привести к утечке информации о состоянии системы или атаке на сервис мониторинга.

Для повышения безопасности необходимо реализовать возможность ограничения доступа к метрикам только для определённых IP-адресов, что позволит контролировать, какие клиенты могут запрашивать метрики.

В данной статье рассмотрим, как внести соответствующие изменения в код Node Exporter, а также процесс сборки обновленного пакета.

Изменение кода

Добавление нового флага командной строки

Для управления доступом по IP-адресам добавим новый аргумент --web.client-ip-only, который будет содержать список разрешённых IP-адресов, разделённых запятыми. Если параметр не указан, метрики будут доступны для всех.

В файле main.go регистрируем новый флаг:

clientIPOnly = kingpin.Flag(
    "web.client-ip-only",
    "Comma-separated list of allowed client IPs (e.g., '192.168.1.1,10.0.0.2'). Leave empty to allow all.",
).Default("").String()

Реализация фильтрации IP

Добавим middleware для обработки входящих HTTP-запросов и проверки IP-адреса клиента:

func ipFilterMiddleware(next http.Handler, allowedIPs map[string]struct{}, logger *slog.Logger) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        clientIP, _, err := net.SplitHostPort(r.RemoteAddr)
        if err != nil {
            logger.Warn("Failed to parse client IP", "error", err)
            http.Error(w, "Forbidden", http.StatusForbidden)
            return
        }

        if len(allowedIPs) > 0 {
            if _, allowed := allowedIPs[clientIP]; !allowed {
                logger.Warn("Access denied", "client_ip", clientIP)
                http.Error(w, "Forbidden", http.StatusForbidden)
                return
            }
        }

        next.ServeHTTP(w, r)
    })
}

Добавление middleware в обработчик метрик

В main.go изменим обработчик HTTP-запросов:

allowedIPs := make(map[string]struct{})
if *clientIPOnly != "" {
    for _, ip := range strings.Split(*clientIPOnly, ",") {
        allowedIPs[strings.TrimSpace(ip)] = struct{}{}
    }
}

http.Handle(*metricsPath, ipFilterMiddleware(newHandler(!*disableExporterMetrics, *maxRequests, logger), allowedIPs, logger))

Обновление главной страницы

Добавим отображение разрешённых IP-адресов на веб-странице:

clientIPDisplay := "*"
if *clientIPOnly != "" {
    clientIPDisplay = *clientIPOnly
}

landingConfig := web.LandingConfig{
    Name:        "Node Exporter",
    Description: "Prometheus Node Exporter",
    Version:     version.Info(),
    Links: []web.LandingLinks{
        {
            Address: *metricsPath,
            Text:    "Metrics",
        },
        {
            Address: "#",
            Text:    "Allowed IPs: " + clientIPDisplay,
        },
    },
}

Сборка пакета для распространения

После внесения изменений необходимо пересобрать Node Exporter. Для этого выполните следующие шаги:

  1. Установите Go и зависимости:

    sudo apt update && sudo apt install -y golang
  2. Склонируйте исходный код Node Exporter:

    git clone https://github.com/prometheus/node_exporter.git
    cd node_exporter
  3. Скомпилируйте бинарный файл:

    make build
  4. Проверяем версию и новые параметры:

    ./node_exporter --version
  5. Запускаем с ограничением по IP:

    ./node_exporter --web.client-ip-only="192.168.1.1,10.0.0.2"

Добавление параметра --web.client-ip-only позволяет ограничить доступ к метрикам только для указанных IP-адресов. Это значительно повышает уровень безопасности и снижает риск несанкционированного доступа к системной информации.

Теперь, благодаря middleware-фильтрации, Node Exporter будет обслуживать только доверенные IP-адреса, а пользователи смогут легко настраивать этот параметр через командную строку.

Кому лень всем этим заниматься, можете воспользоваться готовым из моего репозитория:

https://github.com/MaxSimba/node-exporter

З.Ы. Просьба не пинать сильно, я не волшебник только учусь! Но за конструктивные предложения, плюс в карму! За сим откланиваюсь! По просьбам могу собрать пакет для deb или RPM репозитория.