Демон ldap auth это что
Перейти к содержимому

Демон ldap auth это что

  • автор:

Nginx + LDAP авторизация

И очень часто надо сделать авторизацию к какому-то сервису авторизацию через LDAP на Nginx. Сам Nginx не имеет встроенного модуля авторизации в LDAP, в отличие от Apache или Tomcat.

Итак, давайте сделаем basic авторизацию пользователей в Nginx через LDAP.

Сервер авторизации

Метод, который предлагают сами разработчики Nginx заключается в следующем: необходимо поднять промежуточный сервер, который будет проверять введеные данные в LDAP и возвращать результат в Nginx. В случае ответа HTTP/200 — пользователь авторизован. В любом другом случае — даные не верны.

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

Клонируем репу к себе на сервер:

$ git clone https://github.com/nginxinc/nginx-ldap-auth.git /opt/nginx-ldap-auth 

и запускаем этот сервер (дополнительной настройки он не требует):

$ /opt/nginx-ldap-auth/nginx-ldap-auth-daemon-ctl.sh start 

Остальная настройка будет производиться из конфига Nginx. Для этого нам надо добавить в Nginx что-то типа такого:

 location = /auth-proxy  internal; proxy_pass_request_body off; proxy_set_header Content-Length ""; proxy_pass http://127.0.0.1:8888; proxy_set_header X-Ldap-URL "ldap://127.0.0.1:389"; proxy_set_header X-Ldap-Template "(uid=%(username)s)"; proxy_set_header X-Ldap-BaseDN "dc=example,dc=com"; > location /private-storage  auth_request /auth-proxy; proxy_pass http://application-backend; > 

По умолчанию, будет произведена попытка simple bind с анонимным пользователем. Если же у вас не поддерживается этот метод, то вам необходимо раскомментировать строки и указать DN и пароль пользователя, который может искать по дереву LDAP. Это самая простая конфигурация и она может быть расширена другими модулями авторизации.

Похожие записи:

  • Создаем htpasswd для nginx (без Apache)
  • How To: Проксирование в приватный AWS S3 через Nginx

Nginx + LDAP Auth ( Наладка аутентификации пользователей сайта под управлением Nginx через внешний LDAP-сервис. )

OS: «Linux Debian 8/9/10», «Linux Ubuntu 16/18 LTS».
Application: Nginx, Python, LDAP.

Задача: обеспечить аутентификацию пользователей сайта через внешний LDAP-сервис, средствами web-сервера «Nginx».

С точки зрения эксплуатационщика на предприятии удобно проводить аутентификацию пользователей внутренних сервисов через некий централизованный каталог с учётными данными. Чаще всего для этого применяется сервис «Microsoft Active Directory», но технически почти всегда в этой роли можно использовать иные реализации LDAP, вроде «OpenLDAP» или «389-DS».

В сложносочинённых сайтах задачи аутентификации и авторизации обычно возлагаются на специально для этого предназначенные компоненты внутри информационной системы, для реализации которых во всех распространённых языках программирования имеются библиотеки функций взаимодействия с LDAP. С мелкими сайтами, возможно даже полностью статическими, сложнее — у них нет подкапотных механизмов, посредством которых можно было бы проверять право доступа пользователя к запрашиваемым данным. В таком случае на роль привратника остаётся один кандидат — web-браузер. И вот на этом этапе выясняется, что любимый нами «Nginx» не имеет модуля аутентификации через LDAP.

Как вариант решения поставленной задачи, можно воспользоваться системных модулем «auth_pam», указав «Nginx» проводить аутентификацию через PAM несущей операционной системы («Linux» или xBSD), в которой настроена связка с LDAP. Лет пять назад разрабатывалась реализация в виде модуля «nginx-auth-ldap», но он устарел сейчас разработчики «Nginx» официально предлагают использовать другой подход, с промежуточным сервисом «nginx-ldap-auth-daemon».

Предлагаемая схема взаимодействий проста и прозрачна. Когда пользователь обращается к защищённому разделу сайта, web-сервер «Nginx» запрашивает посредством протокола «HTTP Basic authentication» логин и пароль. Полученные аутентификационные данные встроенным модулем «http_auth_request» сразу отправляются по протоколу проксирования фоновому web-сервису «LDAP Auth Daemon», который в свою очередь обращается к указанному в его настройках LDAP-серверу за подтверждением существования пользователя с предъявленными логином и паролем. Положительный или отрицательный ответ доставляется обратно по цепочке web-серверу «Nginx», который допускает или нет пользователя до запрашиваемого контента. Этот процесс красиво расписан в официальной документации.

Перейдём же к практике.

Установка «Nginx LDAP Auth Daemon».

Простенькое приложение-посредник написано на «Python», который почти всегда уже установлен:

# aptitude install python2.7-minimal python-ldap git

Загружаем дистрибутив «Nginx LDAP Auth Daemon»:

# cd /usr/src
# git clone https://github.com/nginxinc/nginx-ldap-auth

Копируем единственный нужный исполняемый файл в наиболее подходящее ему место в файловой системе:

# cp ./nginx-ldap-auth/nginx-ldap-auth-daemon.py /usr/local/bin/

Заготавливаем место для журналов событий (аутентификация дело ответственное):

# mkdir -p -m 740 /var/log/nginx-ldap-auth
# chown -R www-data /var/log/nginx-ldap-auth

Пробуем запустить приложение:

# cd /usr/local/bin
# LOG=/var/log/nginx-ldap-auth/daemon.log ./nginx-ldap-auth-daemon.py start

По умолчанию «Nginx LDAP Auth Daemon» прослушивает запросы только на «локальной сетевой петле», на обычно свободном порту, что меня полностью устраивает и освобождает от необходимости что-то настраивать:

# netstat -apn | grep -i python
tcp . 127.0.0.1:8888 0.0.0.0:* LISTEN . /python

Оставим пока приложение запущенным и перейдём к настройке web-сервера.

Настройка аутентификации через LDAP в «Nginx».

Принимая за данность, что web-сервер «Nginx» уже корректно настроен, дополним настройки конкретного сайта блоком параметров проксирования запросов аутентификации к «Nginx LDAP Auth Daemon»:

# vi /etc/nginx/sites-available/site.example.net.conf

# Перечисляем требования, которым должны удовлетворять пользователи сайта
satisfy all;
#
# (пользователи из локальных сетей)
allow 10.0.0.0/8;
allow 172.16.0.0/12;
allow 192.168.0.0/16;
deny all;
#
# (прошедшие аутентификацию)
auth_request /auth-proxy;

# Блок параметров запроса к «Nginx LDAP Auth Daemon»
location = /auth-proxy {
internal;
proxy_pass_request_body off;
proxy_set_header Content-Length «»;
proxy_pass http://127.0.0.1:8888;
proxy_set_header X-Ldap-URL «ldaps://ldap.example.net:636»;
proxy_set_header X-Ldap-Template «(&(uid=%(username)s)(objectclass=person)(memberOf=cn=web-service-users,ou=groups,dc=example,dc=net))»;
proxy_set_header X-Ldap-BaseDN «ou=People,dc=example,dc=net»;
proxy_set_header X-Ldap-BindDN «uid=nginx-web-service,ou=Accounts,ou=Services,dc=example,dc=net»;
proxy_set_header X-Ldap-BindPass «***»;
}

Конструкция «%(username)s» в примере выше используется для получения из набора внутренних переменных «Nginx» имени пользователя (логина), введённого в форму «HTTP Basic authentication».

Проверяем синтаксическую корректность конфигурации «Nginx» и применяем её:

# nginx -t && nginx -s reload

Сразу после запуска можно пробовать обращаться к закрытой части сайта и проверять, работает ли связка «Nginx», «Nginx LDAP Auth Daemon» и LDAP в соответствии с ожиданиями. Если что-то пошло не так, смотрим предусмотрительно заготовленный журнал событий.

Подключение к LDAP с «самоподписанным» SSL-сертификатом.

Почти наверняка LDAP-сервер, работающий только в локальной сети, для шифрования соединений будет предлагать «self-signed» SSL-сертификат. Типовое python-приложение доверяет сертификатам, размещённым в соответствующем хранилище несущей операционной системы, так что самым простым способом наладить связь будет добавление публичной части самодельного сертификата LDAP-сервиса в перечень «доверенных»:

# cp ./ss-rootCA.crt /usr/local/share/ca-certificates/
# update-ca-certificates

Последующая проверка (с несущего «Nginx LDAP Auth Daemon» сервера) не должна демонстрировать предупреждений о проблемах распознавания подписи SSL-сертификата целевого сервера:

$ echo QUIT | openssl s_client -connect ldap.exfmple.net:636 -CApath /etc/ssl/certs

О кешировании запросов аутентификации.

Аутентификация через «auth_request» в «Nginx» работает так, что на каждый запрос любого ресурса (даже мелкой картинки в составе страницы) генерируется внутреннее событие требования аутентификации, по которому отправляется запрос в промежуточную подсистему «ldap‑auth», которая в свою очередь обращается за подтверждением подлинности пользователя в LDAP. Таким образом на каждый запрос web-страницы создаётся от десятка до нескольких сотен подзапросов, в которых совершенно нет необходимости. Для снижения затрат ресурсов на такую непродуктивную деятельность в «Nginx» применяется кеширование.

Вначале на уровне глобальной конфигурации «Nginx» указываем желаемое месторасположение директории для файлов данных кешируемых запросов и максимальное время хранения таковых, а после в конфигурации сайта, для доступа к которому требуется аутентификация через LDAP, добавляем указание кешировать успешно завершённые запросы к подсистеме «ldap-auth» на срок до десяти минут:

# vi /etc/nginx/sites-available/site.example.net.conf

proxy_cache_path /var/lib/nginx/cache/ keys_zone=auth_cache:10m;
.
server {
.

location = /auth-proxy {
internal;
proxy_cache auth_cache;
proxy_cache_valid 200 10m;
.

# nginx -t && nginx -s reload

Настройка автозапуска «Nginx LDAP Auth Daemon» посредством «Systemd».

Ранее мы запустили приложение-прослойку вручную. Автоматизируем эту процедуру, описав подсистему аутентификации как постоянно работающий простой сервис:

# vi /etc/systemd/system/nginx-ldap-auth-daemon.service

[Unit]
Description=LDAP authentication helper for Nginx
After=network.target network-online.target

Указываем «Systemd» перечитать и принять новую конфигурацию, а также явно активируем и запускаем новый сервис:

# systemctl daemon-reload
# systemctl enable nginx-ldap-auth-daemon.service
# systemctl start nginx-ldap-auth-daemon

Журналы событий нам в помощь, если что-то работает не так, как задумывалось:

# systemctl status nginx-ldap-auth-daemon
# journalctl -xe

Наладка ротации журналов событий.

Выше упоминалось, что реализация аутентификации в «Nginx» склонна генерировать массу запросов, которые записываются в журнал событий. Если забыть об этом, то через полгода в файловой системе вырастет огромный ненужный файл. Заранее натравим на него подсистему усечения и оборота журналов:

# vi /etc/logrotate.d/nginx-ldap-auth-daemon

/var/log/nginx-ldap-auth/*.log {
monthly
rotate 12
compress
delaycompress
missingok
notifempty
copytruncate
su www-data www-data
}

Проверяем корректность конфигурации, не воздействуя при этом на файлы журналов:

# logrotate -d /etc/logrotate.d/nginx-ldap-auth-daemon

[ уже посетило: 8996 / +5 ] [ интересно! / нет ]

Поблагодарить автора ( сделайте свой денежный вклад в хорошее настроение )

Заметки и комментарии к публикации:

Оставьте свой комментарий ( выразите мнение относительно публикации, поделитесь дополнительными сведениями или укажите на ошибку )

Nginx: basic auth через Samba AD

В данной статье описаны принцип работы и настройка basic auth в Nginx через Samba Active Directory.

Применение и принцип работы

Необходимость такого решения возникла в результате закрытия всех внутренних ресурсов от посторонних глаз. Но на каждый проект заводить отдельные .htpasswd файлы или делать один общий, а потом где-то хранить логин и пароль не очень хотелось – со временем проектов станет много и администрировать учётки станет не очень удобно. Тут-то на помощь и пришёл вариант использования Nginx с имеющейся Samba в качестве контроллера домена.

Модуль ngx_http_auth_request_module (1.5.4+) предоставляет возможность авторизации клиента, основанной на результате подзапроса. Если подзапрос возвращает код ответа 2xx, доступ разрешается. Если 401 или 403 — доступ запрещается с соответствующим кодом ошибки. Любой другой код ответа, возвращаемый подзапросом, считается ошибкой.

То есть работа модуля основана на подзапросах к какому-либо стороннему сервису, который обращается к Active Directory, и возвращается к Nginx с ответом. Таковым сервисом является демон, написанный на Python, и называется ldap‑auth daemon. Поддерживает работу Python 2 и 3 версии.

На сайте Nginx изображена схема работы при использовании модуля авторизации и коннектора на Python:

The NGINX Plus reference implementation for LDAP authentication includes the ldap-auth daemon and a sample backend daemon

Необходимые зависимости

  • Модуль ngx_http_auth_request_module, согласно документации, не включен в сборку по умолчанию, но в пакетах из репозитория Nginx данный модуль присутствует. Для проверки необходимо вывести список всех модулей Nginx:
nginx -V 2>&1 | tr ' ' '\n' | grep with-http_auth_request_module
  • Для работы демона ldap‑auth daemon необходима библиотека python-ldap – установить её можно через пакетный менеджер python – pip. Но для этого потребуется установить на сервер следующие зависимости:
    • компилятор языка C
    • непосредственно python3
    • openldap-devel
    yum install python3 gcc python3-devel openldap-devel 

    Создание пользователя Active Directory

    Для возможности обращения в AD с помощью ldap‑auth daemon необходима сервисная учётная запись с правами на чтение дерева.

    • Для создания в Microsoft AD или Samba можно воспользоваться оснасткой dsa.msc. Или же через консоль сервера в случае с Samba:
    samba-tool user add nginx
    • Также необходимо отключить срок действия учетной записи:
    samba-tool user setexpiry nginx --noexpiry

    Проверка связанности с AD

    • Рекомендуется проверить напрямую через утилиту ldapsearch, есть ли возможность подключиться к AD с помощью созданной УЗ. Команда ниже выведет объекты дерева:
    ldapsearch -v -D "nginx@domain.local" -w "PASSWORD" -b "DC=domain,DC=local" -H "ldap://10.10.4.30" | head -n 40 

    Если ошибок не возникло, можно переходить к установке демона.

    Установка nginx-ldap-auth bare metal

    • Демон потребляет мало ресурсов, поэтому его допустимо установить на тот же сервер, где запущен Nginx:
    curl -o /usr/bin/nginx-ldap-auth-daemon.py https://raw.githubusercontent.com/nginxinc/nginx-ldap-auth/master/nginx-ldap-auth-daemon.py chmod +x /usr/bin/nginx-ldap-auth-daemon.py
    • Выполнить пробный запуск, задав адрес и порт:
    /usr/bin/python3 /usr/bin/nginx-ldap-auth-daemon.py --host 127.0.0.1 --port 8080 
    • Обратиться к демону через curl. В логах должно появиться что-то подобное:
    curl localhost:8080 Start listening on 127.0.0.1:8080. 127.0.0.1 - - [02/Apr/2021 17:14:08] using username/password from authorization header 127.0.0.1 - - [02/Apr/2021 17:14:08] "GET / HTTP/1.1" 401 -
    • Убедившись, что запуск выполняется корректно, для удобного последующего запуска логично будет создать systemd-юнит:
    cat > /etc/systemd/system/nginx-ldap-auth.service 

    Стоит обратить внимание – в конфиге юнита указан отдельный пользователь nginx-ldap-auth, от имени которого будет запускаться демон. Необходимо создать данного пользователя:

    adduser nginx-ldap-auth --no-create-home --shell=/bin/false 
    • Выполнить запуск демона через systemd:
    systemctl daemon-reload && systemctl start nginx-ldap-auth && systemctl enable nginx-ldap-auth 
    • Проверить логи:
    journalctl -u nginx-ldap-auth.service -f

    Запуск в Docker

    На гитхабе представлен Dockerfile для сборки Docker-образа nginx-ldap-auth. Я немного его изменил, добавив:

    • non-root пользователя для запуска приложения в контейнере
    • временную зону Europe/Moscow
    • 3 версию питона по умолчанию в entrypoint
    • аргументы CMD
    ARG PYTHON_VERSION=3.9 FROM python:$-alpine RUN \ addgroup -S nginx-ldap-auth && \ adduser -S nginx-ldap-auth -G nginx-ldap-auth && \ cp -r /usr/share/zoneinfo/Europe/Moscow /etc/localtime && echo Europe/Moscow > /etc/timezone && \ apk --no-cache add openldap-dev && \ apk --no-cache add --virtual build-dependencies build-base && \ pip3 install python-ldap && \ apk del build-dependencies COPY nginx-ldap-auth-daemon.py /usr/src/app/ WORKDIR /usr/src/app/ EXPOSE 8888 USER nginx-ldap-auth ENTRYPOINT ["python3", "/usr/src/app/nginx-ldap-auth-daemon.py"] CMD ["--host", "0.0.0.0", "--port", "8888"]

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

    docker build -t nginx-ldap-auth . docker run --name nginx-ldap-auth -p 8888:8888 -d nginx-ldap-auth

    А при необходимости запуска на порту, отличном от дефолтного 8888, можно изменить аргументы CMD при старте:

    docker run --name nginx-ldap-auth -p 8888:8887 -d nginx-ldap-auth --host 0.0.0.0 --port 8887

    Используемые заголовки

    Демон nginx-ldap-auth успешно запущен, но перед дальнейшей настройкой непосредственно самого Nginx, необходимо убедиться, что запросы корректно приходят в Active Directory от nginx-ldap-auth. Для этого понадобится curl и специальные HTTP-заголовки, в которых будет передаваться вся необходимая информация для подключения к LDAP.

    Параметры LDAP HTTP Header Описание
    basedn X-Ldap-BaseDN База поиска. В большинстве случаев соответствует суффиксу каталога. Если необходимо просто авторизовать пользователя, то не нужно указывать дополнительные группы, в которые этот пользователь входит (для этого используется template). Например, dc=domain,dc=local или cn=Users,dc=domain,dc=local
    binddn X-Ldap-BindDN Для выполнения операции поиска в каталоге используется BIND DN, в данном параметре указывается непосредственно уникальное имя пользователя каталога. Например, cn=root,dc=domain,dc=local
    bindpasswd X-Ldap-BindPass Пароль пользователя
    cookiename X-CookieName Авторизация на основе файлов кук, необязательный параметр. При использовании basic auth игнорируется.
    realm X-Ldap-Realm Имя realm, необязательный параметр, используется по умолчанию значение Restricted.
    template X-Ldap-Template Шаблон, по которому будет происходить выборка. Можно настраивать различные конфигурации. Например, для OpenLDAP подойдет такой шаблон: (cn=%(username)s), а для AD – (SAMAccountName=%(username)s) – это базовый шаблон, который просто выполняет поиск пользователя по каталогу.
    url X-Ldap-URL Адрес подключения к LDAP-серверу. Например, ldap://10.10.4.30:389 или ldaps://10.10.4.30:636

    Проверка работы

    Определившись с заголовками, можно выполнить проверку через curl, передав минимальные параметры: адрес AD, наименование домена, логин\пароль и простой шаблон:

    curl --location --request GET 'http://localhost:8080' \ --header 'X-Ldap-URL: ldap://10.10.4.30' \ --header 'X-Ldap-BaseDN: DC=domain,DC=local' \ --header 'X-Ldap-BindDN: nginx@domain.local' \ --header 'X-Ldap-BindPass: STRONG_PASS' \ --header 'X-Ldap-Template: (SAMAccountName=%(username)s)' -vv -u nginx:STRONG_PASS 
    • В ответ должен поступить 200 код, т.е. подключение успешно устанавливается от имени созданного пользователя:
    * About to connect() to localhost port 8080 (#0) * Trying 127.0.0.1. * Connected to localhost (127.0.0.1) port 8080 (#0) * Server auth using Basic with user 'nginx' > GET / HTTP/1.1 > Authorization: Basic efVnsdfuZ2DpQaEFhDFsdxM0tMZVRmdWfg0 > User-Agent: curl/7.29.0 > Host: localhost:8080 > Accept: */* > X-Ldap-URL: ldap://10.10.4.30 > X-Ldap-BaseDN: DC=domain,DC=local > X-Ldap-BindDN: nginx@domain.local > X-Ldap-BindPass: STRONG_PASS > X-Ldap-Template: (SAMAccountName=%(username)s) > * HTTP 1.0, assume close after body < HTTP/1.0 200 OK < Server: BaseHTTP/0.6 Python/3.6.8 < Date: Mon, 05 Apr 2021 10:01:42 GMT < * Closing connection 0

    В случае ошибки вида Error while binding as search user: Strong(er) authentication required‘, ‘ctrls’: [], ‘info’: ‘BindSimple: Transport encryption required.’> необходимо добавить в конфиг smb.conf строку “ldap server require strong auth = no”, но делать так для production не рекомендуется.

    Конфигурация Nginx

    Наконец, можно выполнять настройку веб-сервера. Для удобства будет создана директория, в которой необходимо расположить конфиг для авторизации через AD – так его будет удобно подключать в необходимый контекст. Ну, или разместить по своему усмотрению:

    mkdir -p /etc/nginx/conf.d/nginx-ldap-auth cat > /etc/nginx/conf.d/nginx-ldap-auth/nginx-ldap-auth.conf EOF

    В файле nginx-ldap-auth.conf описан location, в котором настроено:

    • наименование location – в данном случае /auth
    • кеширование 200 кода (через пробел можно добавить и другие коды) ответа в течение 10 минут
    • проксирование запросов на локальный адрес, где слушает nginx-ldap-auth
    • передача HTTP-заголовков для LDAP

    Если раскомментировать директиву “proxy_cache auth_cache”, то необходимо в nginx.conf в контексте http указать директиву proxy_cache_path cache/ keys_zone=auth_cache:10m; – она задаёт путь и другие параметры кэша. Данные кэша хранятся в файлах.

    Поскольку тело запроса отбрасывается для подзапросов аутентификации, необходимо отключить директиву “proxy_pass_request_body”, а также установить для заголовка Content-Length пустую строку

    • И в завершение осталось подключить в нужном контексте “server” location для авторизации через Active Directory – выделено жирным:
     server < server_name example.com location / < auth_request /auth; proxy_pass http://10.16.0.14:81; proxy_set_header Host $host; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Real-IP $remote_addr; autoindex on; > include /etc/nginx/conf.d/nginx-ldap-auth/nginx-ldap-auth.conf; > >

    В вышеописанном конфигурационном файле к обычному “location /” добавляется “auth_request /auth;” и после подключается ранее сформированный файл nginx-ldap-auth.conf. Далее остаётся проверить синтаксис и выполнить релоад Nginx:

    nginx -t && nginx -s reload 

    Исключение для basic auth

    Удобным может тот случай, когда для доверенных адресов какую-либо авторизацию на веб-сервере можно вообще убрать – на помощь приходит директива “satisfy any”:

    location / < satisfy any; allow 10.10.1.0/24; auth_request /auth; proxy_pass http://10.16.0.14:81;

    Если пользователь пришёл с адреса из подсети 10.10.1.0/24, то satisfy разрешает доступ, если все ( all ) или хотя бы один ( any ) из модулей ngx_http_access_module, ngx_http_auth_basic_module, ngx_http_auth_request_module или ngx_http_auth_jwt_module разрешают доступ и в таком случае пароль вводить не понадобится.

    Удобно сделать white-лист и подключать его через include:

    location / < satisfy any; include /etc/nginx/conf.d/whitelist_ip.conf; auth_request /auth; proxy_pass http://10.16.0.14:81; >

    Заключение

    По сути вся настройка сводится к тому, что команда Nginx предоставила готовое решение и описала общие принципы настройки, что очень удобно. К тому же, для большего удобства предоставлены Dockerfile для сборки образов и запуска nginx-ldap-auth в контейнере.

    Из минусов мне видится два и причём весьма существенных:

    • если пропадёт сетевая связанность до сервера с AD или сам сервер падёт смертью храбрых, то клиент на Nginx не сможет авторизоваться и в ответ получит 500 код. Для серьезных решений это может быть критичным моментом и стоит это учитывать. Но в теории Nginx сейчас крайне функционален и наверняка можно обыграть этот нюанс с использованием модуля njs или хитрых конструкций из директив.
    • аутентификация в AD происходит по протоколу LDAP, а это по сути большая дыра. В идеале использовать хотя бы NTLM или Kerberos.

    Также есть форк, в котором есть возможность использования нескольких LDAP-серверов, что в теории должно нивелировать описанный выше минус. Но на практике не проверял.

    Используемые источники

    • https://www.nginx.com/blog/nginx-plus-authenticate-users/
    • http://nginx.org/en/docs/http/ngx_http_auth_request_module.html
    • https://docs.nginx.com/nginx/admin-guide/security-controls/configuring-subrequest-authentication/
    • https://winitpro.ru/index.php/2021/03/22/nginx-active-directory-ldap-autentifikaciya/
    • https://github.com/kvspb/nginx-auth-ldap
    • https://github.com/nginxinc/nginx-ldap-auth

    Настройка аутентификации в Nginx через Active Directory (LDAP)

    date

    22.03.2021

    user

    Ivan

    directory

    Active Directory, DevOps, Docker, Linux, Ubuntu

    comments

    комментариев 12

    В данной статье мы рассмотрим, как настроить basic аутентификацию в Nginx через LDAP каталог. В качестве сервера LDAP будем использовать Windows Active Directory. Так как у Nginx нет официального встроенного модуля авторизации через LDAP (в отличии от Apache или Tomcat), разработчики предлагают использовать сторонний сервис nginx-ldap-auth, который будет обращаться к LDAP и выступать своего рода прокси между Nginx и сервером каталога LDAP ldap сервером. Для начала давайте запустим сервис и посмотрим, как он работает.

    Настройка и запуск сервиса аутентификации nginx-ldap-auth

    Для запуска сервиса nginx-ldap-auth будем использовать docker. Для начала нужно клонировать репозиторий с сервисом с github:

    # sudo git clone https://github.com/nginxinc/nginx-ldap-auth

    Если у вас не установлен утилиты git, можно просто скачать архив с исходниками и распаковать его в директорию nginx-ldap-auth.

    В директории уже имеется готовый Dockerfile. Для сборки контейнера нужно выполнить:

    # sudo docker build -t nginx-ldap-auth-daemon .

    Вывод при сборке будет таким:

    Sending build context to Docker daemon 208.9kB Step 1/7 : ARG PYTHON_VERSION=2 Step 2/7 : FROM python:$-alpine ---> 8579e446340f Step 3/7 : COPY nginx-ldap-auth-daemon.py /usr/src/app/ ---> Using cache ---> a0b2c58fd4af Step 4/7 : WORKDIR /usr/src/app/ ---> Using cache ---> 2d93d045af89 Step 5/7 : RUN apk --no-cache add openldap-dev && apk --no-cache add --virtual build-dependencies build-base && pip install python-ldap && apk del build -dependencies ---> Using cache ---> fd942ca28c6e Step 6/7 : EXPOSE 8888 ---> Using cache ---> 0d5b7bab2edf Step 7/7 : CMD ["python", "/usr/src/app/nginx-ldap-auth-daemon.py", "--host", "0.0.0.0", "--port", "8888"] ---> Using cache ---> 3eb60dda0847 Successfully built 3eb60dda0847 Successfully tagged nginx-ldap-auth-daemon:latest

    установка контейнера nginx-ldap-auth

    Docker image готов, можно запустить контейнер. Для этого выполните команду:

    # sudo docker run -p 8888:8888 --name ldap-auth nginx-ldap-auth-daemon

    Вывод данной команды будет таким:

    Start listening on 0.0.0.0:8888…

    Эта команда запустит контейнер из образа nginx-ldap-auth-daemon, c названием контейнера ldap-auth и пробросит порт 8888 из контейнера на host машину. Проброс портов нужен, чтобы проверить работу и выполнить отладку аутентификации в Active Directory. В дальнейшем, можно исключить этот параметр. Также для отладки мы не добавили ключ -d, который запустил бы контейнер и отвязал бы его от консоли, но тогда не было видно лога работы, который полезен при отладке.

    Давайте теперь разберем, как работает сервис nginx-ldap-auth. Данный демон является небольшим web сервисом, к которому можно отправить HTTP запрос методом get с определенными заголовками, он в свою очередь обратится в Active Directory и проверит авторизационные данные. Если они верны, он ответит HTTP кодом 200 ОК, если нет, то вернет 401 код (не авторизован).

    Для проверки нужен настроенный сервер Active Directory либо OpenLDAP. В данной статье будет рассмотрен контроллер домена на Windows Server 2008 R2, но в README репозитория демона заявлена поддержка и других LDAP серверов.

    • Имя домена: corp.to.high
    • IP контроллера домена: 192.168.0.16

    Создадим пользователя с правами гость. Назовем его ldap_reader. Данный пользователь нужен, чтобы от его имени демон обращался в AD и проверял переданную при авторизации связку логин и пароль.

    Данные пользователя следующие

    пользователь для доступа к домену

    гость домена

    Запретите пользователю менять пароль и установите неограниченный срок действия пароля (Never Expires), так как это сервисная УЗ.

    Для тестирования можно скачать утилиту для поиска в дереве LDAP, например ldapsearch.

    # sudo apt install ldap-utils

    Для проверки доступности контроллера домена и правильной настройки пользователя можно выполнить команду:

    # ldapsearch -v -D "[email protected]" -w "r05-2020" -b "DC=corp,DC=to,DC=high" -H "ldap://192.168.0.16" "(sAMAccountName=ldap_reader)"

    • -D binddn учетная запись, для доступа к домену,
    • -w bindpassword пароль учетной записи,
    • -b searchbase – контейнер (OU) AD, в котором нужно искать пользователя (можно сузить область поиска для получения ответа более быстро),
    • -H адрес ldap сервера;
    • Затем указывается LDAP фильтр, по которому нужно выполнить поиск.

    Вывод для нашего домена будет такой:

    ldap_initialize( ldap://192.168.0.16:389/??base ) filter: (sAMAccountName=ldap_reader) requesting: All userApplication attributes # extended LDIF # # LDAPv3 # base with scope subtree # filter: (sAMAccountName=ldap_reader) # requesting: ALL # # ldap_reader, Users, corp.to.high dn: CN=ldap_reader,CN=Users,DC=corp,DC=to,DC=high objectClass: top objectClass: person objectClass: organizationalPerson objectClass: user cn: ldap_reader givenName: ldap_reader distinguishedName: CN=ldap_reader,CN=Users,DC=corp,DC=to,DC=high instanceType: 4 whenCreated: 20210308212600.0Z whenChanged: 20210308212700.0Z displayName: ldap_reader ………. # search reference ref: ldap://ForestDnsZones.corp.to.high/DC=ForestDnsZones,DC=corp,DC=to,DC=high # search reference ref: ldap://DomainDnsZones.corp.to.high/DC=DomainDnsZones,DC=corp,DC=to,DC=high # search reference ref: ldap://corp.to.high/CN=Configuration,DC=corp,DC=to,DC=high # search result search: 2 result: 0 Success # numResponses: 5 # numEntries: 1 # numReferences: 3

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

    # curl --location --request GET 'http://localhost:8888' \
    --header 'X-Ldap-URL: ldap://192.168.0.16' \
    --header 'X-Ldap-BaseDN: CN=Users,DC=corp,DC=to,DC=high' \
    --header 'X-Ldap-BindDN: [email protected]' \
    --header 'X-Ldap-BindPass: r05-2020' \
    --header 'X-Ldap-Template: (sAMAccountName=%(username)s)' -vv -u ldap_reader:r05-2020

    Вывод будет таким:

    curl с header X-Ldap-BindDN, проверка аутентфикации в Active Directory

    Note: Unnecessary use of -X or --request, GET is already inferred. * Rebuilt URL to: http://localhost:8888/ * Trying 127.0.0.1. * TCP_NODELAY set * Connected to localhost (127.0.0.1) port 8888 (#0) * Server auth using Basic with user 'ldap_reader' > GET / HTTP/1.1 > Host: localhost:8888 > Authorization: Basic bGRhcF9yZWFkZXI6cjA1LTIwMjA= > User-Agent: curl/7.58.0 > Accept: */* > X-Ldap-URL: ldap://192.168.0.16 > X-Ldap-BaseDN: CN=Users,DC=corp,DC=to,DC=high > X-Ldap-BindDN: [email protected] > X-Ldap-BindPass: r05-2020 > X-Ldap-Template: (sAMAccountName=%(username)s) > * HTTP 1.0, assume close after body < HTTP/1.0 200 OK < Server: BaseHTTP/0.3 Python/2.7.18 < Date: Sun, 14 Mar 2021 19:07:48 GMT < * Closing connection 0

    Заголовки, используемые в запросе:

    • X-Ldap-URL — адрес ldap сервера, такой же, как при тестировании с помощью утилиты ldapsearch;
    • X-Ldap-BaseDN — начальный DN для поиска;
    • X-Ldap-BindDN — учетная запись с правами на чтение дерева домена.
    • X-Ldap-BindPass – пароль пользователя для доступа к AD;
    • X-Ldap-Template — в данном заголовке передается LDAP фильтр, по которому будет происходить поиск. В заголовке можно комбинировать разные фильтры. Подробнее можно посмотреть в документации к демону nginx-ldap-auth.
    • Опцией -u : нужно передать креденшелы пользователя, которые нужно проверить в домене

    Если передать неверные учетные данные, будет возвращена ошибка 401 ( не авторизован). Попробуем передать неверный пароль, вывод будет такой:

    * Rebuilt URL to: http://localhost:8888/ * Trying 127.0.0.1. * TCP_NODELAY set * Connected to localhost (127.0.0.1) port 8888 (#0) * Server auth using Basic with user 'ldap_reader' > GET / HTTP/1.1 > Host: localhost:8888 > Authorization: Basic bGRhcF9yZWFkZXI6cjA1LTIwMjAx > User-Agent: curl/7.58.0 > Accept: */* > X-Ldap-URL: ldap://192.168.0.16 > X-Ldap-BaseDN: CN=Users,DC=corp,DC=to,DC=high > X-Ldap-BindDN: [email protected] > X-Ldap-BindPass: r05-2020 > X-Ldap-Template: (sAMAccountName=%(username)s) > * HTTP 1.0, assume close after body < HTTP/1.0 401 Unauthorized < Server: BaseHTTP/0.3 Python/2.7.18 < Date: Sun, 14 Mar 2021 19:16:40 GMT * Authentication problem. Ignoring this. < WWW-Authenticate: Basic realm="Restricted" < Cache-Control: no-cache < * Closing connection 0

    Также в логах демона можно увидеть вывод:

    авторизация в ad http

    172.17.0.1 - - [14/Mar/2021 19:17:45] using username/password from authorization header 172.17.0.1 - ldap_reader [14/Mar/2021 19:17:45] searching on server "ldap://192.168.0.16" with base dn "CN=Users,DC=corp,DC=to,DC=high" with filter "(sAMAccountName=ldap_reader)" 172.17.0.1 - ldap_reader [14/Mar/2021 19:17:45] attempting to bind using dn "CN=ldap_reader,CN=Users,DC=corp,DC=to,DC=high" 172.17.0.1 - ldap_reader [14/Mar/2021 19:17:45] Error while binding as an existing user "CN=ldap_reader,CN=Users,DC=corp,DC=to,DC=high": , server="ldap://192.168.0.16", login="ldap_reader" 172.17.0.1 - ldap_reader [14/Mar/2021 19:17:46] "GET / HTTP/1.1" 401 -

    Настройка контейнера Nginx для авторизации в Active Directory (LDAP)

    Мы проверили работу демона аутентфикации nginx-ldap-auth, теперь можно перейти к настройке Nginx. В данной статье, покажу, как настроить авторизацию для docker registry с учетной записью Active Directory. Nginx будем запускать в docker контейнере. Создадйте Dockerfile:

    FROM nginx COPY nginx-ldap-auth.conf /etc/nginx/conf.d/nginx-ldap-auth.conf

    В директории с Dockerfile создадйте файл конфигурации nginx-ldap-auth.conf.
    Содержание файла:

    proxy_cache_path cache/ keys_zone=auth_cache:10m; upstream backend < server registry:5000; >server < listen 8081; # Protected application location / < auth_request /auth-proxy; proxy_pass http://backend/; >location = /auth-proxy < internal; proxy_cache auth_cache; proxy_cache_valid 200 10m; # The following directive adds the cookie to the cache key proxy_cache_key "$http_authorization$cookie_nginxauth"; proxy_pass_request_body off; proxy_set_header Content-Length ""; proxy_pass http://ldap-auth:8888; # URL and port for connecting to the LDAP server proxy_set_header X-Ldap-URL "ldap://192.168.0.16"; # Base DN proxy_set_header X-Ldap-BaseDN "cn=Users,dc=corp,dc=to, dc=high"; # Bind DN proxy_set_header X-Ldap-BindDN "ldap_rea[email protected]"; # Bind password proxy_set_header X-Ldap-BindPass "r05-2020"; proxy_set_header X-Ldap-Template "(sAMAccountName=%(username)s)"; > >

    В данном конфиге указывается location, с опцией auth_request, которая позволяет отправить HTTP запрос для проверки авторизации. Мы указали внутренний адрес /auth-proxy, на который будет переадресован запрос авторизации. В данном location указаны опций, которые настраивают параметры кэширования и заголовки, которые будут отправлены в nginx-ldap-auth.

    • proxy_pass_request_body — запрещает передачу полей заголовка исходного запроса на проксируемый сервер;
    • proxy_set_header — устанавливает заголовок Content-Length;
    • proxy_cache_valid 200 10m — кешировать ответ с кодом 200 на 10 минут (чтобы не отправлять запрос к серверу авторизации при каждом обращении);
    • proxy_cache_path — путь и другие параметры кэша;
    • proxy_cache_key — ключ кэширования;
    • proxy_pass – указывает на контейнера демона авторизации nginx-ldap-auth. Остальные опции аналогичны тем, что использовались при проверке демона. Файл конфига и dockerfile можно взять в github репозитории.

    После создания конфига, нужно собрать контейнер:

    # sudo docker build . -t nginx-ldap

    Запустите контейнер с nginx с выводом в консоль:

    # sudo docker run -p:8081:8081 --link ldap-auth --link registry --name nginx-ldap nginx-ldap

    • Запускаем nginx-ldap образ с именем —name nginx-ldap;
    • —link — опция позволяет связать в одну сеть контейнеры, так как мы к ним обращаемся по именам в конфиге nginx. Без этих опций из контейнера nginx не будет резолвиться имя registry и ldap-auth;
    • -p:8081:8081 — прокидываем порт наружу.

    Вывод команды будет такой:

    /docker-entrypoint.sh: /docker-entrypoint.d/ is not empty, will attempt to perform configuration /docker-entrypoint.sh: Looking for shell scripts in /docker-entrypoint.d/ /docker-entrypoint.sh: Launching /docker-entrypoint.d/10-listen-on-ipv6-by-default.sh 10-listen-on-ipv6-by-default.sh: info: Getting the checksum of /etc/nginx/conf.d/default.conf 10-listen-on-ipv6-by-default.sh: info: Enabled listen on IPv6 in /etc/nginx/conf.d/default.conf /docker-entrypoint.sh: Launching /docker-entrypoint.d/20-envsubst-on-templates.sh /docker-entrypoint.sh: Configuration complete; ready for start up

    запуск nginx в контейнере с авторизацией в active directory

    Тестируем аутентификацию пользователя доменного пользователя AD в Nginx

    Теперь откройте браузер и перейдите по адресу: http://localhost:8081/v2/_catalog. После успешной авторизации nginx должен переадрессовать на приватный репозиторий docker, описанный в статье про Docker Registry Нам будет предложено окно базовой авторизации следующего вида.

    запрос пароля

    В логах веб сервера должна появится строку обращения к /v2/_catalog. Т.к. текущий пользователь не авторизирован, сервер вернул код ответа 401 код и предлагает авторизоваться. После успешной авторизации должен вернуться код ответа 200.

    успешная аутентфикация HTTP/1.1 200

    172.17.0.1 - - [21/Mar/2021:19:19:09 +0000] "GET /v2/_catalog HTTP/1.1" 401 179 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:82.0) Gecko/20100101 Firefox/82.0" "-" 172.17.0.1 - ldap_reader [21/Mar/2021:19:19:20 +0000] "GET /v2/_catalog HTTP/1.1" 200 20 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:82.0) Gecko/20100101 Firefox/82.0" "-"

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

    После успешной авторизации должна открыться страница со списком образов в Docker репозитории.

    после аутентфикаии получен доступ к сервису за nginx

    У меня в репозитории в данный момент один образ, созданного в статье про создание простого микросервиса в docker.

    В логах сервиса, который обращается к серверу ldap можно увидеть следующее:

    172.17.0.4 - - [21/Mar/2021 19:18:18] using username/password from authorization header 172.17.0.4 - ldap_reader [21/Mar/2021 19:18:18] searching on server "ldap://192.168.0.16" with base dn "cn=Users,dc=corp,dc=to, dc=high" with filter "(sAMAccountName=ldap_reader)" 172.17.0.4 - ldap_reader [21/Mar/2021 19:18:18] attempting to bind using dn "CN=ldap_reader,CN=Users,DC=corp,DC=to,DC=high" 172.17.0.4 - ldap_reader [21/Mar/2021 19:18:18] Auth OK for user "ldap_reader" 172.17.0.4 - ldap_reader [21/Mar/2021 19:18:18] "GET /auth-proxy HTTP/1.0" 200

    По логу видно, что выполнено подключение к LDAP серверу, выполнена авторизация и проверены учетные данные пользователя.

    После проверки, можно остановить контейнеры, и запустить заново в фоновом режиме:

    # sudo docker rm ldap-auth
    # sudo docker rm nginx-ldap

    Теперь можно запуститьконтейнеру nginx и nginx-ldap-auth в фоновом режиме. Также мы убрали в контейнере авторизации проброс портов наружу, это больше не нужно.

    # sudo docker run -d --name ldap-auth nginx-ldap-auth-daemon
    # sudo docker run -p:8081:8081 -d --link ldap-auth --link registry --name nginx-ldap nginx-ldap

    В данной статье мы рассмотрели общий принцип настройки авторизации с учетными данными LDAP в nginx. В качестве конечного backend может выступать не обязательно docker registry, таким образом можно настроить аутентификацию в Active Directory в в любом вашем приложении, опубликованном через nginx.

    Предыдущая статьяПредыдущая статья Следующая статья Следующая статья

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

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