Thank you for reading this post, don't forget to subscribe!
Модуль SPNEGO для NGINX — это программный компонент для возможности прохождения аутентификации (Single Sign-On или SSO) через сервер LDAP.
1. Имя сервера
В процессе настройки аутентификации через LDAP нам необходимо будет задать в качестве принципала имя нашего сервера:
hostnamectl set-hostname nginx.domain.local
* предполагается, что в нашем случае имя сервера будет nginx.domain.local (домен domain.local).
2. Настройка времени
Для работы с LDAP нам необходимо, чтобы время на последнем совпадало с временем на нашем веб-сервере. Самый правильный способ этого добиться — настроить синхронизацию.
Для начала настраиваем временную зону:
timedatectl set-timezone Europe/Moscow
* в данном примере мы задаем зону по московскому времени. Список все доступных зон можно посмотреть командой timedatectl list-timezones.
Устанавливаем утилиту для синхронизации времени, настраиваем ее, разрешаем запуск демона и стартуем его. Набор команд будет зависеть от дистрибутива Linux.
а) если на системе Ubuntu / Debian:
apt-get install chrony
vi /etc/chrony/chrony.conf
1 2 3 4 5 6 |
... pool domain.local # pool … # pool … # pool … ... |
* в данном примере мы указали в качестве сервера синхронизации любой контроллер домена. Остальные настройки pool необходимо закомментировать.
systemctl enable chrony
systemctl restart chrony
б) если на системе CentOS / Red Hat:
yum install chrony
vi /etc/chrony.conf
1 2 3 4 5 6 |
... server domain.local # server … # server … # server … ... |
* в данном примере мы указали в качестве сервера синхронизации любой контроллер домена. Остальные настройки pool необходимо закомментировать.
systemctl enable chronyd --now
3. Настройка безопасности
Для корректной работы нашего веб-сервера необходимо открыть порты http и https. Действия будут отличаться в зависимости от используемого брандмауэра.
а) Iptables (как правило, на Ubuntu/Debian или ранних версиях CentOS):
iptables -I INPUT -p tcp --match multiport --dports 80,443 -j ACCEPT
Для сохранения правил устанавливаем iptables-persistent и запускаем утилиту:
apt-get install iptables-persistent
netfilter-persistent save
б) Firewalld (как правило, на поздних версиях CentOS):
firewall-cmd --permanent --add-service=http{,s}
firewall-cmd --reload
Также на системах с активированным SELinux (как правило, )
setenforce 0
sed -i 's/^SELINUX=.*/SELINUX=disabled/g' /etc/selinux/config
Сборка и установка NGINX с модулем SPNEGO
Встроенных средств NGINX недостаточно для реализации нашей задачи, поэтому необходимо использовать бесплатный модуль SPNEGO. Мы можем выполнить это двумя методами:
- Собрать NGINX с добавлением модуля.
- Собрать динамический модуль SPNEGO и подключить его к уже работающему NGINX.
У каждого способа есть свои плюсы и минусы, но мы рассмотрим оба варианта, а выбор оставляем за читателем.
Сборка NGINX с модулем SPNEGO
Выполняем сборку в несколько этапов. Разберем их по очереди:
1. Установка зависимостей
Для сборки нам нужны пакеты, от которых зависит процесс конфигурирования. В зависимости от операционной системы, команды будут отличаться.
а) для Ubuntu/Debian:
apt-get update
apt-get install wget git build-essential libpcre++-dev zlib1g-dev libkrb5-dev libssl-dev libxslt-dev libgd-dev
б) для CentOS:
yum install epel-release
yum install wget git pcre-devel openssl-devel libxml2-devel libxslt-devel gd-devel perl-ExtUtils-Embed gperftools-devel
2. Загрузка исходников
Загрузим исходник для nginx и модуля SPNEGO.
Переходим на страницу загрузки nginx и копируем ссылку на нужную версию веб-сервера:
* в данном примере мы будем загружать nginx версии 1.20.0.
С помощью скопированной ссылки, загружаем исходник веб-сервера:
wget https://nginx.org/download/nginx-1.20.0.tar.gz
После распаковываем его:
tar zxvf nginx-*.tar.gz
Переходим в распакованную папку:
cd nginx-*/
Клонируем репозиторий для модуля SPNEGO:
git clone https://github.com/stnoonan/spnego-http-auth-nginx-module.git
Мы готовы к сборке.
3. Сборка и установка пакета
Для разных систем мы выполним разные команды конфигурирования пакета.
а) на Ubuntu/Debian:
1 |
./configure --prefix=/usr/share/nginx --sbin-path=/usr/sbin/nginx --conf-path=/etc/nginx/nginx.conf --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log --lock-path=/var/lock/nginx.lock --pid-path=/run/nginx.pid --modules-path=/usr/lib/nginx/modules --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --with-debug --with-compat --with-pcre-jit --with-http_ssl_module --with-http_stub_status_module --with-http_realip_module --with-http_auth_request_module --with-http_v2_module --with-http_dav_module --with-http_slice_module --with-threads --with-http_addition_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_image_filter_module=dynamic --with-http_sub_module --with-http_xslt_module=dynamic --with-stream=dynamic --with-stream_ssl_module --with-mail=dynamic --with-mail_ssl_module --add-module=spnego-http-auth-nginx-module |
б) на Centos:
1 |
./configure --prefix=/usr/share/nginx --sbin-path=/usr/sbin/nginx --modules-path=/usr/lib64/nginx/modules --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --http-client-body-temp-path=/var/lib/nginx/client_body --http-proxy-temp-path=/var/lib/nginx/proxy --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --http-scgi-temp-path=/var/lib/nginx/scgi --pid-path=/run/nginx.pid --lock-path=/run/lock/subsys/nginx --user=nginx --group=nginx --with-file-aio --with-http_ssl_module --with-http_v2_module --with-http_realip_module --with-stream_ssl_preread_module --with-http_addition_module --with-http_xslt_module=dynamic --with-http_image_filter_module=dynamic --with-http_sub_module --with-http_dav_module --with-http_flv_module --with-http_mp4_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_random_index_module --with-http_secure_link_module --with-http_degradation_module --with-http_slice_module --with-http_stub_status_module --with-http_perl_module=dynamic --with-http_auth_request_module --with-mail=dynamic --with-mail_ssl_module --with-pcre --with-pcre-jit --with-stream=dynamic --with-stream_ssl_module --with-google_perftools_module --with-debug --add-module=spnego-http-auth-nginx-module |
Собираем пакет:
make
Выполняем установку:
make install
4. Завершение настройки системы
Чтобы nginx мог корректно запуститься, выполним несколько предварительных действий.
Создадим пользователя nginx:
useradd --no-create-home nginx
Создадим каталог /var/lib/nginx:
mkdir -p /var/lib/nginx
Проверим, что nginx проходит проверку конфигурационного файла:
nginx -t
Мы должны увидеть:
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
5. Создаем юнит в systemd и стартуем сервис
Для запуска nginx в качестве сервиса, создаем файл:
vi /lib/systemd/system/nginx.service
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
[Unit] Description=A high performance web server and a reverse proxy server Documentation=man:nginx(8) After=network.target [Service] Type=forking PIDFile=/run/nginx.pid ExecStartPre=/usr/sbin/nginx -t -q -g 'daemon on; master_process on;' ExecStart=/usr/sbin/nginx -g 'daemon on; master_process on;' ExecReload=/usr/sbin/nginx -g 'daemon on; master_process on;' -s reload ExecStop=-/sbin/start-stop-daemon --quiet --stop --retry QUIT/5 --pidfile /run/nginx.pid TimeoutStopSec=5 KillMode=mixed Restart=on-failure [Install] WantedBy=multi-user.target |
Перечитываем конфигурационные файлы в systemd:
systemctl daemon-reload
Разрешаем автозапуск сервиса и стартуем его:
systemctl enable nginx
systemctl start nginx
Сборка и подключение динамического модуля
Данный способ немного отличается по действиям и конфигурированию, но суть процесса та же. Рассмотрим его по шагам.
1. Установка NGINX
Предполагается, что nginx установлен в системе. Иначе, установку можно выполнить из репозитория в зависимости от дистрибутива Linux.
а) Для Ubuntu/Debian:
apt-get update
apt-get install nginx
б) Для CentOS:
yum install epel-release
yum install nginx
Запускаем NGINX и разрешаем автостарт сервиса:
systemctl start nginx
systemctl enable nginx
2. Установка зависимостей
Для сборки нам нужны пакеты, от которых зависит процесс конфигурирования. В зависимости от операционной системы, команды будут отличаться.
а) для Ubuntu/Debian:
apt-get install wget git build-essential libpcre++-dev zlib1g-dev libkrb5-dev libssl-dev libxslt-dev libgd-dev
б) для CentOS:
yum install wget git pcre-devel openssl-devel libxml2-devel libxslt-devel gd-devel perl-ExtUtils-Embed gperftools-devel redhat-rpm-config
3. Загрузка исходников
Загрузим исходник для nginx и модуля SPNEGO.
Для начала, смотрим версию установленного NGINX:
nginx -v
Переходим на страницу загрузки nginx и копируем ссылку на установленную версию в нашей системе:
* в данном примере мы будем загружать nginx версии 1.16.1.
С помощью скопированной ссылки, загружаем исходник веб-сервера:
wget https://nginx.org/download/nginx-1.16.1.tar.gz
После распаковываем его:
tar zxvf nginx-*.tar.gz
Переходим в распакованную папку:
cd nginx-*/
Клонируем репозиторий для модуля SPNEGO:
git clone https://github.com/stnoonan/spnego-http-auth-nginx-module.git
Мы готовы к сборке.
4. Сборка и установка модуля
Смотрим, с какими опциями собран установленный NGINX:
nginx -V
В ответ мы получим список опций — нам нужно все, что идет после configure arguments, например:
1 |
--with-cc-opt='-g -O2 -fdebug-prefix-map=/build/nginx-5J5hor/nginx-1.18.0=. -fstack-protector-strong -Wformat -Werror=format-security -fPIC -Wdate-time -D_FORTIFY_SOURCE=2' --with-ld-opt='-Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fPIC' --prefix=/usr/share/nginx --conf-path=/etc/nginx/nginx.conf --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log --lock-path=/var/lock/nginx.lock --pid-path=/run/nginx.pid --modules-path=/usr/lib/nginx/modules --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --with-debug --with-compat --with-pcre-jit --with-http_ssl_module --with-http_stub_status_module --with-http_realip_module --with-http_auth_request_module --with-http_v2_module --with-http_dav_module --with-http_slice_module --with-threads --with-http_addition_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_image_filter_module=dynamic --with-http_sub_module --with-http_xslt_module=dynamic --with-stream=dynamic --with-stream_ssl_module --with-mail=dynamic --with-mail_ssl_module |
Нам нужно ввести команду с синтаксисом:
./configure <список опций nginx -V> --add-dynamic-module=<путь до модуля>
В моем случае, это:
1 |
./configure --with-cc-opt='-g -O2 -fdebug-prefix-map=/build/nginx-5J5hor/nginx-1.18.0=. -fstack-protector-strong -Wformat -Werror=format-security -fPIC -Wdate-time -D_FORTIFY_SOURCE=2' --with-ld-opt='-Wl,-Bsymbolic-functions -Wl,-z,relro -Wl,-z,now -fPIC' --prefix=/usr/share/nginx --conf-path=/etc/nginx/nginx.conf --http-log-path=/var/log/nginx/access.log --error-log-path=/var/log/nginx/error.log --lock-path=/var/lock/nginx.lock --pid-path=/run/nginx.pid --modules-path=/usr/lib/nginx/modules --http-client-body-temp-path=/var/lib/nginx/body --http-fastcgi-temp-path=/var/lib/nginx/fastcgi --http-proxy-temp-path=/var/lib/nginx/proxy --http-scgi-temp-path=/var/lib/nginx/scgi --http-uwsgi-temp-path=/var/lib/nginx/uwsgi --with-debug --with-compat --with-pcre-jit --with-http_ssl_module --with-http_stub_status_module --with-http_realip_module --with-http_auth_request_module --with-http_v2_module --with-http_dav_module --with-http_slice_module --with-threads --with-http_addition_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_image_filter_module=dynamic --with-http_sub_module --with-http_xslt_module=dynamic --with-stream=dynamic --with-stream_ssl_module --with-mail=dynamic --with-mail_ssl_module --add-dynamic-module=spnego-http-auth-nginx-module |
Собираем модуль:
make modules
Готово. В каталоге objs появится файл ngx_http_auth_spnego_module.so. Нам нужно его скопировать в каталог с библиотеками. В зависимости от системы и опций сборки, этот каталог может находиться по разному пути.
а) Для Ubuntu/Debian (как правило):
cp objs/ngx_http_auth_spnego_module.so /usr/lib/nginx/modules/
б) Для CentOS (как правило):
cp objs/ngx_http_auth_spnego_module.so /usr/lib64/nginx/modules/
* более точный путь можно посмотреть командой nginx -V — среди полученных опций найти --modules-path.
5. Подключение модуля в NGINX
Наш модуль в нужном каталоге, но чтобы веб-сервер его мог использовать, необходимо внести изменения в конфигурационный файл. Пути немного отличаются для разных дистрибутивов Linux.
а) Ubuntu/Debian:
vi /etc/nginx/modules-enabled/spnego-http-auth-nginx-module.conf
load_module "/usr/lib/nginx/modules/ngx_http_auth_spnego_module.so";
б) CentOS:
vi /usr/share/nginx/modules/spnego-http-auth-nginx-module.conf
load_module "/usr/lib64/nginx/modules/ngx_http_auth_spnego_module.so";
* напомню, что точный путь до файла ngx_http_auth_spnego_module.so может быть другим.
Проверяем, корректность настройки nginx:
nginx -t
Мы должны увидеть:
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
Можно перезапускать NGINX:
systemctl restart nginx
Создание учетной записи в AD и файла keytab
Для подключения к контроллеру домена нам необходимо подтверждать подлинность. Это выполняется с помощью учетной записи в LDAP и файла keytab.
Создание учетной записи
Открываем консоль управления пользователями и добавляем нового со стандартными правами. От этой учетной записи будут выполняться запросы к AD DS.
В своем примере мы создаем пользователя spnego.
Учетная запись должна быть размещена по пути, в котором присутствуют названия только на латинице. Подразделения и контейнеры не должны быть на русском. В противном случае, при выполнении команды ниже мы получим ошибку «Password set failed! 0x00000020».
Создание keytab-файла
В двух словах, данный файл позволяет пройти идентификацию в Kerberos без запроса пароля. Он содержит пары имен субъектов Kerberos и зашифрованные ключи, полученные из пароля Kerberos.
Мы создадим данный файл на контроллере домена и скопируем на сервер NGINX. Для этого на контроллере домена и от имени администратора запускаем Powershell или обычную командную строку. Вводим:
1 |
ktpass /princ HTTP/nginx.domain.local@DOMAIN.LOCAL /mapuser spnego@DOMAIN.LOCAL /crypto ALL /ptype KRB5_NT_PRINCIPAL /out C:\spnego.keytab /pass * |
* где:
- nginx.domain.local — полное имя нашего nginx-сервера;
- DOMAIN.LOCAL — наш домен;
- spnego@DOMAIN.LOCAL — учетная запись в AD для выполнения запросов (создана на шаге выше);
- pass * — пароль, который будет задан пользователю (должен соответствовать требованию AD). Система запросит его ввод дважды.
* регистр важен.
В нашем примере, после выполнения команды на контроллере домена в корне диска С появится файл spnego.keytab. Его копируем на Linux-сервер, например, при помощи WinSCP.
Настройка Linux для интеграции с AD
Для интеграции Linux с нашим LDAP (в данном примере, на основе Active Directory) установим необходимые пакеты и настроим Kerberos.
Установка пакетов
Необходимые пакеты ставим из репозиториев.
а) на Ubuntu/Debian:
apt-get install heimdal-clients
б) на Centos:
yum install krb5-workstation
Проверка файла
Переходим в каталог с файлом keytab и выполняем команду:
kinit -kt spnego.keytab HTTP/nginx.domain.local@DOMAIN.LOCAL
* напомним, что spnego.keytab — имя нашего файла; HTTP/nginx.domain.local@DOMAIN.LOCAL — принципал, для которого сгенерирован файл.
Команда нам ничего не должна вернуть. Это значит, что она выполнена корректно.
Теперь выполним:
klist
Мы должны увидеть что-то на подобие:
1 2 3 4 5 |
Credentials cache: FILE:/tmp/krb5cc_0 Principal: HTTP/nginx.domain.local@DOMAIN.LOCAL Issued Expires Principal Apr 28 15:04:47 2021 Apr 29 01:04:47 2021 krbtgt/DOMAIN.LOCAL@DOMAIN.LOCAL |
В данном ответе мы видим, что нам выдан билет для принципала HTTP/nginx.domain.local@DOMAIN.LOCAL. Идем дальше.
Настройка kerberos
Открываем на редактирование файл:
vi /etc/krb5.conf
Приводим его к виду (остальные строки не трогаем):
1 2 3 4 5 6 7 8 9 10 11 12 |
[libdefaults] ... default_realm = DOMAIN.LOCAL .. [realms] DOMAIN.LOCAL = { kdc = 192.168.0.15 kdc = 192.168.0.16 kdc = 192.168.0.17 admin_server = domain.local } |
* DOMAIN.LOCAL — наш домен; kdc — перечень контроллеров домена; admin_server — первичный контроллер (в данном примере будет использоваться случайный).
Настройка аутентификации на NGINX
Переходим к настройке самого веб-сервера. Для начала, перенесем наш файл keytab в каталог NGINX:
mv spnego.keytab /etc/nginx/
Открываем файл nginx с настройками для виртуального домена или главный конфигурационный файл.
а) пример для Ubuntu/Debian:
vi /etc/nginx/sites-enabled/default
б) пример для CentOS:
vi /etc/nginx/nginx.conf
В секции server добавляем:
1 2 3 4 5 6 7 8 |
server { ... auth_gss on; auth_gss_realm DOMAIN.LOCAL; auth_gss_keytab /etc/nginx/spnego.keytab; auth_gss_service_name HTTP/nginx.domain.local; ... } |
Перезапускаем NGINX:
systemctl restart nginx
Готово. Пробуем зайти на наш сайт.
1. В качестве альтернативного модуля для осуществления basic-аутентификации через ldap может использоваться nginx-ldap-auth. Он также должен быть загружен и добавлен при сборке.
2. В инструкции используется пример сборки пакета на целевом сервере. Это не совсем правильно, так как оставляет после себя много мусора. Сборку лучше осуществлять на другом компьютере или в контейнере Docker.