alibek Posted September 30, 2022 · Report post Возникла у меня тут специфичная задача. Есть веб-сервер с 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. Не ткнете в ссылку, где был бы пример подобной конфигурации? Я пока не понимаю, как мне декодировать заголовки (имя пользователя) и как логгировать ответы. Вставить ник Quote Ответить с цитированием Share this post Link to post Share on other sites More sharing options...
boco Posted October 1, 2022 · Report post http://nginx.org/ru/docs/varindex.html $remote_user $arg_ $http_ https://mailman.nginx.org/mailman3/lists/ Вставить ник Quote Ответить с цитированием Share this post Link to post Share on other sites More sharing options...
sirmax Posted October 2, 2022 · Report post Я решал задачу логгирования для дебага https://noname.com.ua/mediawiki/index.php/Nginx_Log_RequestHeaders Штатными средствами нельзя залоггировать заголовки о которых вы не знаете заранее Вставить ник Quote Ответить с цитированием Share this post Link to post Share on other sites More sharing options...
Ivan_83 Posted October 2, 2022 · Report post У меня nginx заменял сквид долгое время, цель была фильтровать некоторые запросы к определённым сайтам а так же проксировать через спрокси сободного мира если возвращалась ошибка (провайдер одно время держал сквид для заблоченых сайтов, и нгинх это ловил и сразу перезапрашивал сам через прокси). Вставить ник Quote Ответить с цитированием Share this post Link to post Share on other sites More sharing options...
naves Posted October 2, 2022 (edited) · Report post Вы хотите полный дебаг включая ответы от сервера. nginx тут не поможет. простой вариант запустить tcpdump и писать в файл. Более продвинутый вариант начать использовать log-коллекторы. Можно взять тот же elasticsearch с агентами filebeat (файловые логи), packetbeat (сетевой трафик). Выглядят страшно, но на самом деле несложно там. Edited October 2, 2022 by naves Вставить ник Quote Ответить с цитированием Share this post Link to post Share on other sites More sharing options...
alibek Posted October 3, 2022 · Report post В 03.10.2022 в 01:58, naves сказал: Вы хотите полный дебаг включая ответы от сервера. Это пожелание. В первую очередь нужны все же запросы. В 02.10.2022 в 15:49, sirmax сказал: Штатными средствами нельзя залоггировать заголовки о которых вы не знаете заранее Заголовки я знаю, но заголовки могут отсутствовать, тогда нужно писать в лог что-нибудь понятное (например прочерк). Вставить ник Quote Ответить с цитированием Share this post Link to post Share on other sites More sharing options...
st_re Posted October 3, 2022 · Report post дата/время, 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 НО должны быть права у воркера на создание файлов с логами. Вставить ник Quote Ответить с цитированием Share this post Link to post Share on other sites More sharing options...
alibek Posted October 3, 2022 · Report post В 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 А вот это отлично, спасибо. Вставить ник Quote Ответить с цитированием Share this post Link to post Share on other sites More sharing options...
st_re Posted October 3, 2022 · Report post лог пишется в момент окончания обработки запроса.. если в пути на лог файл есть переменные. то он открывается (создаётся) в момент записи лога перебирая имена юзеров можно будет забить ФС околопустыми файлами... Вставить ник Quote Ответить с цитированием Share this post Link to post Share on other sites More sharing options...
ixi Posted October 3, 2022 · Report post В 30.09.2022 в 09:26, alibek сказал: Я пока не понимаю, как мне декодировать заголовки (имя пользователя) и как логгировать ответы. Если именно нгинкс, можно посмотреть в сторону lua. Или написать свой прокси на знакомом языке Вставить ник Quote Ответить с цитированием Share this post Link to post Share on other sites More sharing options...
sirmax Posted October 3, 2022 · Report post 19 часов назад, naves сказал: Вы хотите полный дебаг включая ответы от сервера. nginx тут не поможет. простой вариант запустить tcpdump и писать в файл. Более продвинутый вариант начать использовать log-коллекторы. Можно взять тот же elasticsearch с агентами filebeat (файловые логи), packetbeat (сетевой трафик). Выглядят страшно, но на самом деле несложно там. Все делается на нжинксе с луа дам пример как дойду до компа, с телефона неудобно Вставить ник Quote Ответить с цитированием Share this post Link to post Share on other sites More sharing options...
edo Posted October 10, 2022 · Report post зачем тут lua? идём на http://nginx.org/en/docs/varindex.html всё есть, кроме «содержимое некоторых узлов в возвращаемом XML» Вставить ник Quote Ответить с цитированием Share this post Link to post Share on other sites More sharing options...
alibek Posted October 11, 2022 · Report post Частично заработало, но никак не получается решить один момент. Речь идет про проксирование сервера Макроскоп. Проксирование нужно для того, чтобы контролировать использование учетных записей — штатных инструментов в Макроскопе для этого нет. Поэтому прокси-сервер будет логгировать доступ, а отдельный скрипт будет анализировать логи и выдавать уведомления при срабатывании. Для проксирования использую 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 ... Видимо это и есть видеопоток, который постоянно передается в незакрываемой сессии. Но в моем случае он не передается. Не подскажите, что нужно исправить, чтобы проксирование заработало? Вставить ник Quote Ответить с цитированием Share this post Link to post Share on other sites More sharing options...
Ivan_83 Posted October 11, 2022 · Report post Посмотрите в отладочной консоли браузера что происходит и станет всё понятно. Вставить ник Quote Ответить с цитированием Share this post Link to post Share on other sites More sharing options...
st_re Posted October 11, 2022 · Report post В 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 ... Видимо это и есть видеопоток, который постоянно передается в незакрываемой сессии. Но в моем случае он не передается. Не подскажите, что нужно исправить, чтобы проксирование заработало? ДО этого должен быть запрос.. (ну и убедиться, что запрос идёт туда же, куда и остальной трафик.) ну и да, открыть нетворк монитор в браузере, и смотреть что посылается и что в ответ. Вставить ник Quote Ответить с цитированием Share this post Link to post Share on other sites More sharing options...
alibek Posted October 11, 2022 · Report post Это не через браузер происходит, а через мобильное приложение. Посмотреть будет сложно, разве что трафик сниффером записать. Вставить ник Quote Ответить с цитированием Share this post Link to post Share on other sites More sharing options...
edo Posted October 12, 2022 · Report post В 11.10.2022 в 11:58, alibek сказал: так и веб-версией В 12.10.2022 в 00:46, alibek сказал: Это не через браузер происходит что-то не сходится В 12.10.2022 в 00:46, alibek сказал: разве что трафик сниффером записать тоже вариант Вставить ник Quote Ответить с цитированием Share this post Link to post Share on other sites More sharing options...
ixi Posted October 13, 2022 · Report post В 11.10.2022 в 11:58, alibek сказал: Не подскажите, что нужно исправить, чтобы проксирование заработало? попробуйте proxy_http_version 1.1; Вставить ник Quote Ответить с цитированием Share this post Link to post Share on other sites More sharing options...
st_re Posted October 13, 2022 · Report post ну для начала понять откуда всётаки льётся видео. во многих системах, типа камер, видео льётся не по http и с другого порта, причем имя хоста может оказаться придётся подделать, чтобы за потоком оно пошло куда надо.. даже если отсю да же, то возможно не хватает локейшнов.. Вставить ник Quote Ответить с цитированием Share this post Link to post Share on other sites More sharing options...
Ivan_83 Posted October 14, 2022 · Report post Наиболее вероятно что откуда лится видео - отдаётся отдельной ссылкой, целиком url, и там либо ip либо хост, который разумеется за пределами локалки не достижим. Вставить ник Quote Ответить с цитированием Share this post Link to post Share on other sites More sharing options...
boco Posted October 14, 2022 · Report post В 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; } } Вставить ник Quote Ответить с цитированием Share this post Link to post Share on other sites More sharing options...
alibek Posted October 14, 2022 · Report post В 14.10.2022 в 14:26, boco сказал: вся ваша куча локаций различается тока форматом лога. используйте вложенные локации О, спасибо, так намного удобнее. В 14.10.2022 в 14:26, boco сказал: для начала настройте самое тупое проксирование и убедитесь что оно работает Так оно и не работает. Возможно потому, что сервер отдает потоки в бесконечной сессии. Вставить ник Quote Ответить с цитированием Share this post Link to post Share on other sites More sharing options...
alibek Posted October 14, 2022 · Report post Обновленный конфиг: Скрытый текст 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), я не вижу, чтобы шли какие-то обращения. Как бы проверить, почему проксирование не работает? Вставить ник Quote Ответить с цитированием Share this post Link to post Share on other sites More sharing options...
alibek Posted October 14, 2022 · Report post В 14.10.2022 в 16:01, alibek сказал: одновременно смотреть их через tcpdump нельзя -i any До чего техника дошла. Да, судя по трафику, все что соответствует вложенным location — не проксируется. Все что под них не попадает (то есть соответствует корневому location /) проксируется нормально. P.S. Если продублировать proxy_pass в каждом вложенном location, то возвращаюсь к тому, с чего начал — подключаюсь, получаю конфигурацию с сервера, но видеопотоки не работают. Но зато увидел в tcpdump, что нужно проксировать веб-сокет. Хотя бы ясно теперь, в какую сторону копать. P.P.S. Йес! Правда изображение тупит, но это уже настройки и тюнинг. Вставить ник Quote Ответить с цитированием Share this post Link to post Share on other sites More sharing options...
boco Posted October 15, 2022 · Report post В 14.10.2022 в 18:01, alibek сказал: Такое впечатление, как будто proxy_pass не срабатывает. я был неправ. нужно добавлять proxy_pass во вложенные локации, эта директива не наследуется, в отличие от proxy_set_header Вставить ник Quote Ответить с цитированием Share this post Link to post Share on other sites More sharing options...