Github – intika-web-apps/nginx-auth-request-module: a nginx module that enables authorizations on sub-requests

Acknowledgments

Thanks to Maxim Dounin for making the module
available and being so helpful on the
Nginx mailing list answering all
kinds of issues and particularly regarding this module.

Auth-server

We are running the open source auth-server (written by myself). In summary, it listens on port 3000 for the following requests:

Caveats

Note that the module discards the request body. Therefore if you’re
proxying to an upstream you must set
proxy_pass_request_body
to off and set the Content-Length header to a null string. Here’s
and example:

You cannot use
proxy_cache/proxy_store
or
fastcgi_cache/fastcgi_store
for requests involving auth_request.

Fakenetscaler

So far, we have only played with NGINX server configuration. Let’s look at the FakeNetscaler authorization server. As I mentioned earlier, NGINX only provides an authorization framework, the authorization server needs to be custom build and tailored to customer’s requirements:

Module directives

auth_requesturi | off

default:off

Nginx google-authenticator или не все не так просто…

Авторизация в nginx на базе google одноразовых паролей.

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

Подсказали решение на базе Nginx (http_auth_request_module) Apache (google-authenticator-apache-module).

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

GitHub - Intika-Web-Apps/Nginx-Auth-Request-Module: A Nginx module that enables authorizations on sub-requests

Идея в следующем. Проверка авторизации происходит не на самом nginx а на сервере apache. Nginx посылает подзапрос auth_request на ‘Сервер авторизации’ apache, если авторизация пройдена apache отвечает HTTP 200, и nginx радостно считает что пользователь авторизацию прошел.

Как это работает. На ‘Сервере авторизации’ вы создаете файл(Имя файла — логин) для каждого пользователя который содержит некий secure key.
Не вдаваясь в подробности будем считать что на базе этого secure key и текущего времени, на стороне сервера и на стороне клиента, независимо друг от друга, каждую минуту генерируются одноразовые пароли.

В качестве приложения генерирующего пароли используется:

Google Authenticator for Android.
Google Authenticator for iOS.
Если у вас нет телефона, то есть приложение и под Windows:
Google Authenticator for Windows.
Тамже есть и под java…

Как синхронизировать приложение с сервером чуть позже, а сейчас что же надо настроить на сервере.

К сожалению модуля под Nginx нету и быть не может из-за особенностей реализации Nginx. Почему точно сказать не могу, но мне говорили слова про state mashine и тд… 🙂

Но под Apache модуль есть!!! Зовется google-authenticator-apache-module

Там есть и бинарные сборки под centsOS 6 — работает проверил. Есть и исходники и есть более свежее в репо. Я поигрался с бинарной сборкой а потом собрал модуль из исходников.

Значит так на apache google-authenticator-apache-module делаем «сервер авторизации» (можно даже 2 сервера для надежности) и к нему подключаем Nginx_ы на всех серверах где нам надо.

Итак берем apache2, собираем или берем бинарный модуль google-authenticator-apache-module.

и пишем такой конфиг:

Loadmodule authn_google_module  modules/mod_authn_google.so
Listen *:8888

<Location ~ "/(|_auth/)" >
# разрешаем только сети где у нас стоят Nginx_ы. Я еще и файрволом прикрыл на всякий случай :)
   Order deny,allow
   Deny from all
   Allow from 10.0.0.0/8
   Allow from 192.168.0.0/24

   AuthType Basic
   AuthName "My Closed Zone  Gauth"
   AuthBasicProvider "google_authenticator"
   Require valid-user
   GoogleAuthUserPath /etc/httpd/ga_auth
   GoogleAuthCookieLife 600
   GoogleAuthEntryWindow 3
   #  GoogleAuthLogLevel - работает только в последней версии собранной из исходников.
   GoogleAuthLogLevel 1
</Location>

Рестартуем apache, пробуем в браузере отрыть его — есть запрос авторизации? Прекрасно!!!

Дальше…

/etc/httpd/ga_auth — директория где лежат файлы с секретными ключами.

Как и чем их создавать: google-authenticator

Качаем, libpam-google-authenticator, собираем получаем google-authenticator. Вот она может генерировать то что нам надо.

Я сделал скрипт чтоб файл ложился сразу куда надо.

#!/bin/bash
/usr/bin/google-authenticator -t -D -f [email protected] -r3 -R600 -s /etc/httpd/ga_auth/$1 -w2
/bin/chown apache:apache  /etc/httpd/ga_auth/$1

Скрипту передаем параметром логин пользователя.

Отработав скрипт создаст файл и выдаст в консоль:

https://www.google.com/chart?chs=200x200&chld=M|0&cht=qr&chl=otpauth://totp/[email protected]?secret=QYYY34XXXX534A4QA
Your new secret key is: DQYYY34XXXX534A4QA
Your verification code is 123456
Your emergency scratch codes are:
  99942105
  28654999
  45999608
  33300650
  99907825

в файл /etc/httpd/ga_auth/_user_login_ пришется много разного но ничего не влияет на работу google-authenticator-apache-module кроме «Your new secret key is:», по крайне мере я экспериментировал — ничего… так что можно оставить только первую строку с QUCFKE6AK3PBA4QA а можно и не трогать файл.

дальше открываем ссылку https://www.google.com/chart?chs=200×200&chld=M|0&cht=qr&chl=otpauth://totp/[email protected]?secret=QYYY34XXXX534A4QA
(ссылка намеренно кривая)
и видим

GitHub - Intika-Web-Apps/Nginx-Auth-Request-Module: A Nginx module that enables authorizations on sub-requests

Устанавливаем на телефон (если пока еще не установили) Google Authenticator. Сканируем QR код, и все телефон начинает каждую минуту генерировать одноразовый пароль.

Можете попробовать авторизоваться в apache, должно сработать, но может выдать 404 — т.к. после авторизации apache хочет показать какой нибудь index.html а его у вас возможно нет.

Кстати google-authenticator-apache-module модуль честно пишет в /var/log/httpd/error_log.

И так, у нас есть «сервер авторизации» и телефон — оба генерируют одинаковую последовательность одноразовых паролей.

Перейдем к настройке nginx.

берем Nginx посвежее, я взял последний стабильный 1.5.7, собираем с –with-http_auth_request_module (http_auth_request_module ключевой момент).

        auth_request_set $auth_cookie $upstream_http_set_cookie;
        add_header Set-Cookie $auth_cookie;


        location  = /_auth/ {
           internal;
                proxy_pass http://gauth_pool/;
                proxy_pass_request_body off;
                proxy_buffering off;
                proxy_cache off;
                proxy_set_header Content-Length "";
                proxy_set_header Host mydomain.com;
        }

я выделил этот кусок конфига в отдельный файл и буду include там где будет нужно.

в /etc/nginx/nginx.conf в конце добавляем пул серверов apache хотя бы 2 для надежности:

upstream  gauth_pool  {
        server ga1.mydomain.com:8888 weight=1;
        server ga2.mydomain.com:8888 weight=5;
}

теперь везде где надо для Nginx добавляем:


server {
        listen 443 ssl spdy;
#       listen 80;

        server_name www.mydomain.com;

        satisfy  any;
        include   /etc/nginx/allow_nets.txt;
        deny  all;
        auth_request /_auth/;

        include location_auth.conf;

Проверяем 🙂

/etc/nginx/allow_nets.txt — список IP которым не надо авторизоваться. Думаю не надо всех мучать авторизацией.

Теперь самое интересное — тонкости:

Работает все это следующим образом.

Авторизовались. Пока работаете на сайте постоянно происходит проверка вашей авторизации по куки
set-cookie: google_authn=user:1390714695:FRxZCSDzox/a5KEGXXXXXXX5TYGIYZrRf=

Она постоянно обновляется, 1390714695 — время когда истекает срок действия куки. Она постоянно обновляется текущее время {GoogleAuthCookieLife 600} из конфига apache. Можно сказать это время бездействия на страничке. отошли на 10 минут — заново авторизуйтесь.

И второй момент. Введенный вами одноразовый пароль действует не вечно. Вообще срок ему 1 минута и все. Но с помощью параметра
GoogleAuthEntryWindow 3, можно раздвинуть «временное окно» действия паролей.
Смысл в том что google-authenticator-apache-module может генерировать помимо текущего пароля, пароли до и после в количестве GoogleAuthEntryWindow, это сделано для того что если часы на вашем мобильном и часы на сервер не совпадают — вы все равно смогли залогиниться.

Это же можно сделать чтоб ваш одноразовый пароль дольше проходил авторизацию, это будет позволять дольше сохранять авторизацию «пройденой»;

Ну и напоследок кусок лога из apache:

[Sun Jan 20 09:01:49 2022] [error] [client 1.2.3.4] **** COOKIE AUTH at  T=1390714549, referer: https://www.mydomain.com/
[Sun Jan 20 09:01:49 2022] [error] [client 1.2.3.4] Cookie auth is DECLINED, referer: https://www.mydomain.com/
[Sun Jan 20 09:01:49 2022] [error] [client 1.2.3.4] **** PW AUTH at  T=1390714549  user  "my_user", referer: https://www.mydomain.com/
[Sun Jan 20 09:01:49 2022] [error] [client 1.2.3.4] getUserSecret with username "my_user", referer: https://www.mydomain.com/
[Sun Jan 20 09:01:49 2022] [error] [client 1.2.3.4] OPENING FILENAME /etc/httpd/ga_auth/my_user, referer: https://www.mydomain.com/
[Sun Jan 20 09:01:49 2022] [error] [client 1.2.3.4] Comparing Authentication   @ T=46017151 Code=475002 "332994" vs.  "475002", referer: https://www.mydomain.com/
[Sun Jan 20 09:01:49 2022] [error] [client 1.2.3.4] Comparing Authentication   @ T=46017151 Code=87841 "332994" vs.  "087841", referer: https://www.mydomain.com/
[Sun Jan 20 09:01:49 2022] [error] [client 1.2.3.4] Comparing Authentication   @ T=46017151 Code=627132 "332994" vs.  "627132", referer: https://www.mydomain.com/
[Sun Jan 20 09:01:49 2022] [error] [client 1.2.3.4] Comparing Authentication   @ T=46017151 Code=332994 "332994" vs.  "332994", referer: https://www.mydomain.com/
[Sun Jan 20 09:01:49 2022] [error] [client 1.2.3.4] Created cookie expires 1390715149 hash is sEFQLm92bSI= Cookie: google_authn=my_user:1390715149:sEFQLm92bSI=, referer: https://www.mydomain.com/

Постепенно, а точнее раз в минуту строки типа
Comparing Authentication @ T=46017151 Code=87841 "332994" vs.
будут сокращаться, пока не останется строка только с вашим паролем, и через минуту — авторизация по новой.

Other builds

If you fancy a bleeding edge Nginx package (from the dev releases) for
Debian made to measure then you might be interested in my
debian Nginx
package. Instructions for using the repository and making the package
live happily inside a stable distribution installation are
provided.

Tl;dr

Protecting a web site with NGINX by using authentication server via a subrequest.

Using directive auth_request /auth

We are protecting /. For each request to /* except for regex pattern ^/(auth|login|logged-in|logout)$ and /css/skeleton.

A 201 response from /auth is a successful authentication and the /* contents will be served as normal. Any other reponse from /auth is a failed authentication and the client will be served a 401 (unauthorised) response. We’ll customise this 401 response later by serving a login interface.

From NGINX’s documentation:

Когда стоит использовать basic auth

По мне, ее стоит применять в двух случаях.

Первое, при разработке проекта, чтобы скрыть от посторонних глаз целый сайт или отдельный раздел.


Второе, в простой админке вроде упомянутого примера с лендингом.

Плюсы и минусы базовой аутентификации

Из плюсов: простота и нативность реализации. Делается парой команд и обеспечивается средствами браузера.

Похожее:  Личный кабинет Ликард для юридических лиц

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *