Перейти к содержимому
Калькуляторы

Вопрос по проксированию в nginx

Возникла у меня тут специфичная задача.

Есть веб-сервер с REST API, на котором потребовалось контролировать его использование (внешними пользователями), а штатные логи нужную информацию не сохраняют.

Не придумал другого способа, как закрыть этот сервер снаружи, а перед ним поставить прокси-сервер, который будет логгировать нужную информацию.

Мне нужно перехватывать обращения к ресурсу /method1?p1=v1&p2=v2 и писать в логи следующую информацию:

- дата/время, IP-адрес посетителя, адрес ресурса (method1);

- параметры запроса p1 и p2 (точнее значения этих параметров);

- заголовок User-Agent;

- декодированное имя пользователя из заголовка Authorization;

- значения заголовков ClientType и ClientId;

- если возможно, то ответный status code;

- если возможно, то содержимое некоторых узлов в возвращаемом XML;

- было бы хорошо, если логи писать не в один общий файл, а в файл с именем пользователя (из заголовка авторизации)

Возможно, нужно будет также подменять Host в запросе, пересылаемом на проксируемый сервер.

 

Насколько я понимаю, это все реализуемо штатными возможностями nginx, директивами proxy_pass и access_log.

Не ткнете в ссылку, где был бы пример подобной конфигурации?

Я пока не понимаю, как мне декодировать заголовки (имя пользователя) и как логгировать ответы.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Я решал задачу логгирования для дебага 

https://noname.com.ua/mediawiki/index.php/Nginx_Log_RequestHeaders

 

Штатными средствами нельзя залоггировать заголовки о которых вы не знаете заранее

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

У меня nginx заменял сквид долгое время, цель была фильтровать некоторые запросы к определённым сайтам а так же проксировать через спрокси сободного мира если возвращалась ошибка (провайдер одно время держал сквид для заблоченых сайтов, и нгинх это ловил и сразу перезапрашивал сам через прокси).

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Вы хотите полный дебаг включая ответы от сервера. nginx тут не поможет.

простой вариант запустить tcpdump и писать в файл.

Более продвинутый вариант начать использовать log-коллекторы. Можно взять тот же elasticsearch с агентами filebeat (файловые логи), packetbeat (сетевой трафик). Выглядят страшно, но на самом деле несложно там. 

Изменено пользователем naves

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

В 03.10.2022 в 01:58, naves сказал:

Вы хотите полный дебаг включая ответы от сервера.

Это пожелание.

В первую очередь нужны все же запросы.

 

В 02.10.2022 в 15:49, sirmax сказал:

Штатными средствами нельзя залоггировать заголовки о которых вы не знаете заранее

Заголовки я знаю, но заголовки могут отсутствовать, тогда нужно писать в лог что-нибудь понятное (например прочерк).

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

дата/время, IP-адрес посетителя, адрес ресурса (method1);

$time_local $remote_addr $uri

- параметры запроса p1 и p2 (точнее значения этих параметров);

$arg_p1 $arg_p2

- заголовок User-Agent;

$http_user_agent

- декодированное имя пользователя из заголовка Authorization;

$remote_user

- значения заголовков ClientType и ClientId;

$http_clienttype $http_clientid

- если возможно, то ответный status code;

$status

- если возможно, то содержимое некоторых узлов в возвращаемом XML;

 

- было бы хорошо, если логи писать не в один общий файл, а в файл с именем пользователя (из заголовка авторизации)

 

access_log "/logs/blablabla/custom_${remote_user}_log";

но тут могут попихать всяких ../../..//etc/passwd тоесть надо бы сначала прогнать через фильтр

 

map $remote_user $t_remote_user {

 default 'unknown';

 ~^$[a-zA-Z0-9_-]{1,99}  $remote_user;

}

 

и в имени уже $t_remote_user

 

НО должны быть права у воркера на создание файлов с логами.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

В 03.10.2022 в 17:28, st_re сказал:

access_log "/logs/blablabla/custom_${remote_user}_log"

Не был уверен, что на этот момент известны заголовки запроса.

 

В 03.10.2022 в 17:28, st_re сказал:

map $remote_user $t_remote_user

А вот это отлично, спасибо.

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

лог пишется в момент окончания обработки запроса..

если в пути на лог файл есть переменные. то он открывается (создаётся) в момент записи лога

 

перебирая имена юзеров можно будет забить ФС околопустыми файлами...

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

В 30.09.2022 в 09:26, alibek сказал:

Я пока не понимаю, как мне декодировать заголовки (имя пользователя) и как логгировать ответы.

Если именно нгинкс, можно посмотреть в сторону lua. Или написать свой прокси на знакомом языке

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

19 часов назад, naves сказал:

Вы хотите полный дебаг включая ответы от сервера. nginx тут не поможет.

простой вариант запустить tcpdump и писать в файл.

Более продвинутый вариант начать использовать log-коллекторы. Можно взять тот же elasticsearch с агентами filebeat (файловые логи), packetbeat (сетевой трафик). Выглядят страшно, но на самом деле несложно там. 

Все делается на нжинксе с луа

 

дам пример как дойду до компа, с телефона неудобно 

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

зачем тут lua?

идём на http://nginx.org/en/docs/varindex.html

всё есть, кроме «содержимое некоторых узлов в возвращаемом XML»

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Частично заработало, но никак не получается решить один момент.

 

Речь идет про проксирование сервера Макроскоп.

Проксирование нужно для того, чтобы контролировать использование учетных записей — штатных инструментов в Макроскопе для этого нет.

Поэтому прокси-сервер будет логгировать доступ, а отдельный скрипт будет анализировать логи и выдавать уведомления при срабатывании.

Для проксирования использую nginx примерно с такой конфигурацией:

proxy_max_temp_file_size  0;
proxy_pass_request_headers  on;
proxy_buffering  off;

server {
    listen       80;
    listen       8080;

    location / {
        proxy_pass http://10.102.0.41:8080;
    }

    location = /configex {
        access_log /data/cybereye/log/macroscop.$remote_user_filter.connect.$logdate.log  macroscop_connect;
        proxy_pass http://10.102.0.41:8080/configex?$query_string;
    }

    location = /command {
        access_log /data/cybereye/log/macroscop.$remote_user_filter.command.$logdate.log  macroscop_command;
        proxy_pass http://10.102.0.41:8080/command?$query_string;
    }

    location = /connecttosmartassistant {
        access_log /data/cybereye/log/macroscop.$remote_user_filter.assistant.$logdate.log  macroscop_assistant;
        proxy_pass http://10.102.0.41:8080/connecttosmartassistant?$query_string;
    }

    location = /mobile {
        access_log /data/cybereye/log/macroscop.$remote_user_filter.mobile.$logdate.log  macroscop_mobile;
        proxy_pass http://10.102.0.41:8080/mobile?$query_string;
    }

    location = /mobilepush {
        access_log /data/cybereye/log/macroscop.$remote_user_filter.push.$logdate.log  macroscop_push;
        proxy_pass http://10.102.0.41:8080/mobilepush?$query_string;
    }

    location = /ptz {
        access_log /data/cybereye/log/macroscop.$remote_user_filter.ptz.$logdate.log  macroscop_ptz;
        proxy_pass http://10.102.0.41:8080/ptz?$query_string;
    }

}

 

При такой конфигурации я успешно подключаюсь к Макроскопу (как мобильным приложением, так и веб-версией), получаю список камер. Но ни одна из камер не работает, не отдает видеопоток.
Скорее всего это связано с тем, что видеопотоки тоже должны проксироваться.
 
В дампе трафика (при нормальном подключении к Макроскопу, не через прокси) происходит следующее.
 
Вначале выполняется авторизация через configex и запрашиваются серверные данные (списки серверов и камер).
 
Затем выполняется mobilepush, если это мобильное устройство.
 
Затем к каждой камере (из ранее полученного списка) отправляется запрос mobile и в ответ приходит примерно такое содержание:
HTTP/1.1 200 OK
Cache-Control: no-cache,no-store,max-age=0,must-revalidate
Pragma: no-cache
Transfer-Encoding: chunked
Expires: Sat, 26 Jul 1997 05:00:00 GMT
Server: Microsoft-HTTPAPI/2.0 Microsoft-HTTPAPI/2.0
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: *
Date: Thu, 29 Sep 2022 11:23:39 GMT

1000
--myboundary
Content-Type: image/jpeg
Timestamp: 29.09.2022 11:23:40
BinaryTimestamp: 5249686492630663846
ZonedTimeStamp: 29.09.2022 11:23:40.327 ZZZZ
Content-Length: 45396
...

 

 

Видимо это и есть видеопоток, который постоянно передается в незакрываемой сессии.
Но в моем случае он не передается.
Не подскажите, что нужно исправить, чтобы проксирование заработало?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Посмотрите в отладочной консоли браузера что происходит и станет всё понятно.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

В 11.10.2022 в 11:58, alibek сказал:

Частично заработало, но никак не получается решить один момент.

 

Речь идет про проксирование сервера Макроскоп.

Проксирование нужно для того, чтобы контролировать использование учетных записей — штатных инструментов в Макроскопе для этого нет.

Поэтому прокси-сервер будет логгировать доступ, а отдельный скрипт будет анализировать логи и выдавать уведомления при срабатывании.

Для проксирования использую nginx примерно с такой конфигурацией:

proxy_max_temp_file_size  0;
proxy_pass_request_headers  on;
proxy_buffering  off;

server {
    listen       80;
    listen       8080;

    location / {
        proxy_pass http://10.102.0.41:8080;
    }

    location = /configex {
        access_log /data/cybereye/log/macroscop.$remote_user_filter.connect.$logdate.log  macroscop_connect;
        proxy_pass http://10.102.0.41:8080/configex?$query_string;
    }

    location = /command {
        access_log /data/cybereye/log/macroscop.$remote_user_filter.command.$logdate.log  macroscop_command;
        proxy_pass http://10.102.0.41:8080/command?$query_string;
    }

    location = /connecttosmartassistant {
        access_log /data/cybereye/log/macroscop.$remote_user_filter.assistant.$logdate.log  macroscop_assistant;
        proxy_pass http://10.102.0.41:8080/connecttosmartassistant?$query_string;
    }

    location = /mobile {
        access_log /data/cybereye/log/macroscop.$remote_user_filter.mobile.$logdate.log  macroscop_mobile;
        proxy_pass http://10.102.0.41:8080/mobile?$query_string;
    }

    location = /mobilepush {
        access_log /data/cybereye/log/macroscop.$remote_user_filter.push.$logdate.log  macroscop_push;
        proxy_pass http://10.102.0.41:8080/mobilepush?$query_string;
    }

    location = /ptz {
        access_log /data/cybereye/log/macroscop.$remote_user_filter.ptz.$logdate.log  macroscop_ptz;
        proxy_pass http://10.102.0.41:8080/ptz?$query_string;
    }

}

 

При такой конфигурации я успешно подключаюсь к Макроскопу (как мобильным приложением, так и веб-версией), получаю список камер. Но ни одна из камер не работает, не отдает видеопоток.
Скорее всего это связано с тем, что видеопотоки тоже должны проксироваться.
 
В дампе трафика (при нормальном подключении к Макроскопу, не через прокси) происходит следующее.
 
Вначале выполняется авторизация через configex и запрашиваются серверные данные (списки серверов и камер).
 
Затем выполняется mobilepush, если это мобильное устройство.
 
Затем к каждой камере (из ранее полученного списка) отправляется запрос mobile и в ответ приходит примерно такое содержание:
HTTP/1.1 200 OK
Cache-Control: no-cache,no-store,max-age=0,must-revalidate
Pragma: no-cache
Transfer-Encoding: chunked
Expires: Sat, 26 Jul 1997 05:00:00 GMT
Server: Microsoft-HTTPAPI/2.0 Microsoft-HTTPAPI/2.0
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: *
Date: Thu, 29 Sep 2022 11:23:39 GMT

1000
--myboundary
Content-Type: image/jpeg
Timestamp: 29.09.2022 11:23:40
BinaryTimestamp: 5249686492630663846
ZonedTimeStamp: 29.09.2022 11:23:40.327 ZZZZ
Content-Length: 45396
...

 

 

Видимо это и есть видеопоток, который постоянно передается в незакрываемой сессии.
Но в моем случае он не передается.
Не подскажите, что нужно исправить, чтобы проксирование заработало?

ДО этого должен быть запрос.. (ну и убедиться, что запрос идёт туда же, куда и остальной трафик.)

 

ну и да, открыть нетворк монитор в браузере, и смотреть что посылается и что в ответ.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Это не через браузер происходит, а через мобильное приложение.

Посмотреть будет сложно, разве что трафик сниффером записать.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

В 11.10.2022 в 11:58, alibek сказал:

так и веб-версией

 

В 12.10.2022 в 00:46, alibek сказал:

Это не через браузер происходит

что-то не сходится

 

В 12.10.2022 в 00:46, alibek сказал:

разве что трафик сниффером записать

тоже вариант

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

В 11.10.2022 в 11:58, alibek сказал:

Не подскажите, что нужно исправить, чтобы проксирование заработало?

попробуйте proxy_http_version 1.1;

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Наиболее вероятно что откуда лится видео - отдаётся отдельной ссылкой, целиком url, и там либо ip либо хост, который разумеется за пределами локалки не достижим.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

В 11.10.2022 в 13:58, alibek сказал:

Не подскажите, что нужно исправить, чтобы проксирование заработало?

1. для начала настройте самое тупое проксирование и убедитесь что оно работает

 

   location / {
        proxy_pass http://10.102.0.41:8080;
    }
 

пока не заработает, дальнейшие упражнения не имеют смысла.

 

2. строчка   "proxy_pass http://10.102.0.41:8080/configex?$query_string;" избыточна и неверна, достаточно "proxy_pass http://10.102.0.41:8080;". uri и request_uri подставляются автомагически:

 

If proxy_pass is specified without a URI, the request URI is passed to the server in the same form as sent by a client when the original request is processed, or the full normalized request URI is passed when processing the changed URI

 

3. вся ваша куча локаций различается тока форматом лога. используйте вложенные локации и тот факт, что директивы (в т.ч. proxy_pass) переходит во вложенную локацию из родительской

location / {

  proxy_pass http://10.102.0.41:8080;

  location /blabla {
    access_log blablabla;
  }
}

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

В 14.10.2022 в 14:26, boco сказал:

вся ваша куча локаций различается тока форматом лога. используйте вложенные локации

О, спасибо, так намного удобнее.

 

В 14.10.2022 в 14:26, boco сказал:

для начала настройте самое тупое проксирование и убедитесь что оно работает

Так оно и не работает.

Возможно потому, что сервер отдает потоки в бесконечной сессии.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Обновленный конфиг:

Скрытый текст
    proxy_max_temp_file_size  0;
    proxy_pass_request_headers  on;
    proxy_buffering  off;

    map $remote_user $remote_user_filter {
        default '_unknown';
        ~^[a-zA-Z0-9_-]+$  $remote_user;
        * '_invalid';
    }

    map $time_iso8601 $logdate {
        default '0000-00-00';
        "~^(\d{4})-(\d{2})-(\d{2})" $1-$2-$3;
    }

    log_format macroscop
    '$time_iso8601: '
    '#$status '
    '$remote_addr ($remote_user) '
    '[$connection_requests:$connection] '
    '"$request"'
    ' ua="$http_user_agent"'
    ' recv=$request_length'
    ' sent=$bytes_sent'
    ' body=$body_bytes_sent'
    ;
...
server {
...
    error_log   /log/error.log notice;
    access_log  off;

    location / {
        root   /site;
        proxy_pass http://10.102.0.41:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        access_log /log/macroscop.log  macroscop;

        location = /configex {
            access_log /log/macroscop.$remote_user_filter.connect.$logdate.log  macroscop_connect;
        }
        location = /command {
            access_log /log/macroscop.$remote_user_filter.command.$logdate.log  macroscop_command;
        }
        location = /connecttosmartassistant {
            access_log /log/macroscop.$remote_user_filter.assistant.$logdate.log  macroscop_assistant;
        }
        location = /mobile {
            access_log /log/macroscop.$remote_user_filter.mobile.$logdate.log  macroscop_mobile;
        }
        location = /mobilepush {
            access_log /log/macroscop.$remote_user_filter.push.$logdate.log  macroscop_push;
        }
        location = /ptz {
            access_log /log/macroscop.$remote_user_filter.ptz.$logdate.log  macroscop_ptz;
        }

    }

}

 

Вложенные location срабатывают, потому что запросы пишутся в соответствующие файлы.

Но почему-то везде сервер возвращает ошибку 404.

В error.log примерно так:

Цитата

2022/10/14 15:48:26 [error] 27240#27240: *11 open() "/site/configex" failed (2: No such file or directory), client: xx.xx.xx.80, server: xxxx, request: "GET /configex?responsetype=json HTTP/1.1", host: "xxxx", referrer: "http://xxxx/web/index.html?v=3.6.69"

Такое впечатление, как будто proxy_pass не срабатывает.

На сервере несколько интерфейсов, одновременно смотреть их через tcpdump нельзя.

Если запускать tcpdump на внешнем интерфейсе, то вижу то же, что в логах — внешний http-запрос, на который сервер отвечает кодом 404.

Если запускать tcpdump на интерфейсе 10.102.0.41, то там тишина (на порту 8080), я не вижу, чтобы шли какие-то обращения.

Как бы проверить, почему проксирование не работает?

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

В 14.10.2022 в 16:01, alibek сказал:

одновременно смотреть их через tcpdump нельзя

-i any

До чего техника дошла.

 

Да, судя по трафику, все что соответствует вложенным location — не проксируется.

Все что под них не попадает (то есть соответствует корневому location /) проксируется нормально.

 

P.S. Если продублировать proxy_pass в каждом вложенном location, то возвращаюсь к тому, с чего начал — подключаюсь, получаю конфигурацию с сервера, но видеопотоки не работают.

Но зато увидел в tcpdump, что нужно проксировать веб-сокет.

Хотя бы ясно теперь, в какую сторону копать.

 

P.P.S. Йес! Правда изображение тупит, но это уже настройки и тюнинг.

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

В 14.10.2022 в 18:01, alibek сказал:

Такое впечатление, как будто proxy_pass не срабатывает.

я был неправ. нужно добавлять proxy_pass во вложенные локации, эта директива не наследуется, в отличие от proxy_set_header

Поделиться сообщением


Ссылка на сообщение
Поделиться на других сайтах

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Гость
Ответить в тему...

×   Вставлено в виде отформатированного текста.   Вставить в виде обычного текста

  Разрешено не более 75 смайлов.

×   Ваша ссылка была автоматически встроена.   Отобразить как ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставить изображения напрямую. Загрузите или вставьте изображения по ссылке.