Решил я защитить двухфакторной аутентификацией опубликованные ресурсы.
После поисков в сети нашел бесплатный аутсорсный продукт от Authelia.
Сие творение позволяет подключить парольную, OTP и 2FA к любому разделу на сайте или домену целиком. Подробная информация на сайте первоисточника.
Я настраивал на обратном прокси от NginX, т.к. он мне ближе. Authelia с Redis в контейнерах.
Я прописал в DNS 2 субдомена:
Далее всё на чистом Debian 11. Все команды от root.
Ставлю зависимости и NginX 1.18.0:
apt update && apt install mc vim htop wget curl build-essential autoconf libpcre++-dev automake pkg-config libtool \
libpcre++-dev libssl-dev apache2-dev libxml2-dev libcurl4-gnutls-dev zlib1g-dev libnginx-mod-http-perl libperl-dev -y && \
timedatectl set-timezone Europe/Moscow && timedatectl set-ntp on && \
mkdir ~/nginx && cd ~/nginx && wget https://nginx.org/download/nginx-1.18.0.tar.gz && \
tar -zxvf nginx-1.18.0.tar.gz && cd nginx-1.18.0
Для корректной работы NginX на этапе компиляции нужно добавить дополнительные модули.
Скачиваем и распаковываем:
wget https://github.com/openresty/set-misc-nginx-module/archive/refs/tags/v0.33.tar.gz && \
wget https://github.com/vision5/ngx_devel_kit/archive/refs/tags/v0.3.2.tar.gz && \
tar xvf v0.33.tar.gz && tar xvf v0.3.2.tar.gz && rm v0.3.2.tar.gz v0.33.tar.gz
Конфигурирование и установка:
./configure \
--prefix=/etc/nginx \
--sbin-path=/usr/bin \
--conf-path=/etc/nginx/nginx.conf \
--error-log-path=/var/log/nginx/error.log \
--http-log-path=/var/log/nginx/access.log \
--pid-path=/var/run/nginx.pid \
--lock-path=/var/lock/nginx.lock \
--http-client-body-temp-path=/var/cache/nginx/client_temp \
--http-proxy-temp-path=/var/cache/nginx/proxy_temp \
--http-fastcgi-temp-path=/var/cache/nginx/fastcgi_temp \
--http-uwsgi-temp-path=/var/cache/nginx/uwsgi_temp \
--http-scgi-temp-path=/var/cache/nginx/scgi_temp \
--modules-path=/usr/lib/nginx/modules \
--with-http_gzip_static_module \
--with-http_gunzip_module \
--with-http_realip_module \
--with-http_mp4_module \
--with-http_flv_module \
--with-http_dav_module \
--with-http_secure_link_module \
--with-http_ssl_module \
--with-http_addition_module \
--with-http_sub_module \
--with-http_stub_status_module \
--with-http_random_index_module \
--with-http_auth_request_module \
--with-http_slice_module \
--with-http_v2_module \
--with-pcre \
--with-http_perl_module \
--add-module=/root/nginx/nginx-1.18.0/ngx_devel_kit-0.3.2 \
--add-module=/root/nginx/nginx-1.18.0/set-misc-nginx-module-0.33
make && make install
Добавляем сервис NginX:
tee /lib/systemd/system/nginx.service<<EOF
[Unit]
Description=The NGINX HTTP and reverse proxy server
After=syslog.target network.target remote-fs.target nss-lookup.target
[Service]
Type=forking
PIDFile=/var/run/nginx.pid
ExecStartPre=/usr/bin/nginx -t
ExecStart=/usr/bin/nginx
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s QUIT $MAINPID
PrivateTmp=true
[Install]
WantedBy=multi-user.target
EOF
Разрешаем и запускаем:
systemctl unmask nginx.service && systemctl daemon-reload && mkdir -p /var/cache/nginx/{client,proxy,fastcgi,uwsgi,scgi}_temp && mkdir -p /etc/nginx/{conf,keys,sites-available,sites-enabled,snippets,proxy-confs} && rm -rf /etc/nginx/*.default && systemctl restart nginx && systemctl enable nginx && systemctl status nginx
Подразумевается, что у вас есь настроенная DNS-записи auth.example.ru и connect.example.ru
Ваши приложения и службы проксируются либо к вашему корневому домену, либо к некоторым поддоменам.
У вас есть настроенный SSL-сертификат. Я настраиваю с Wildcard сертификатом.
Ставим зависимости и DOCKER:
apt update && apt install -y ca-certificates curl gnupg lsb-release && \
curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg && \
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian \
$(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null && \
apt-get update && apt-get install -y docker-ce docker-ce-cli containerd.io docker-compose git && systemctl status docker
Создаем папки и YAML:
mkdir -p ~/authelia/authelia && cd ~/authelia && nano docker-compose.yml
version: '3.3'
networks:
net:
driver: bridge
services:
authelia:
image: authelia/authelia
container_name: authelia
volumes:
- ./authelia:/config
networks:
- net
ports:
- 9091:9091
restart: unless-stopped
environment:
- PUID=1000
- PGID=1000
- TZ=Europe/Moscow
redis:
image: redis:alpine
container_name: redis_authelia
volumes:
- ./redis:/data
networks:
- net
expose:
- 6379
restart: unless-stopped
environment:
- TZ=Europe/Moscow
- PUID=1000
- PGID=1000
Создаем файл конфигурации и поясню пару параметров:
policy:
Существует четыре варианта политики:
deny - доступ запрещен.
one_factor - вход в систему с именем пользователя и паролем.
two_factor - вход в систему, используя имя пользователя, пароль и 2FA.
bypass - вход в систему не требуется.
В данном примере домен auth.example.ru доступен без аутентификации, а домен connect.example.ru защищается 2FA.
cd authelia/ && nano configuration.yml
theme: dark
server:
host: 0.0.0.0
port: 9091
log:
level: info
jwt_secret: fRfFAHOgLC5qs0nzls6frZsfTEY3grDgq9gIfrZdM4T5T7kFJZis2b7wTmysSlR
## The display name the browser should show the user for when using Webauthn to login/register.
webauthn:
display_name: MyCompany
authentication_backend:
file:
path: /config/users_database.yml
access_control:
default_policy: deny
rules:
- domain:
- "auth.example.ru"
policy: bypass
- domain:
- "connect.example.ru"
policy: two_factor
session:
name: authelia_session
secret: fRfFAHOgLC5qs0nzls6frZsfTEY3grDgq9gIfrZdM4T5T7kFJZis2b7wTmysSlR
expiration: 12h # 12 hours
inactivity: 45m # 45 minutes
remember_me_duration: 1M # 1 month
domain: example.ru
redis:
host: redis_authelia
port: 6379
regulation:
max_retries: 3
find_time: 5m
ban_time: 15m
storage:
encryption_key: fRfFAHOgLC5qs0nzls6frZsfTEY3grDgq9gIfrZdM4T5T7kFJZis2b7wTmysSlR
local:
path: /config/db.sqlite3
notifier:
# filesystem:
# filename: /config/notification.txt
smtp:
username: Адрес электронной почты защищен от спам-ботов. Для просмотра адреса в браузере должен быть включен Javascript.
password: FdeNxyhfGRrz
host: smtp.yandex.ru
port: 465
sender: Адрес электронной почты защищен от спам-ботов. Для просмотра адреса в браузере должен быть включен Javascript.
Генерируем сложный пароль:
head /dev/urandom | tr -dc A-Za-z0-9 | head -c64
и меняем в 3-х местах, а именно:
jwt_secret:
secret:
encryption_key:
Чтобы получить хэшированный пароль, который нам будет необходим для пользователя meadmin с паролем QWERTY выполняем следующую команду:
docker run authelia/authelia:latest authelia hash-password QWERTY
Копируем полученную строку
$argon2id$v=19$m=65536,t=3,p=4$SpdFLfWerL9dA$GtJV3pEv0MvCp/N/WTo9c
и вставляем в файл:
nano users_database.yml
users:
meadmin:
displayname: "Administrator"
# Generate with docker run authelia/authelia:latest authelia hash-password QWERTY
password: "$argon2id$v=19$m=65536,t=3,p=4$SpdFLfWerL9dA$GtJV3pEv0MvCp/N/WTo9c"
email: Адрес электронной почты защищен от спам-ботов. Для просмотра адреса в браузере должен быть включен Javascript.
groups:
- admins
Запускаем composer:
docker-compose up -d
Если всё сделали правильно, то докеры готовы. Если же какой-то контейнер рестартится, то смотрим логи контейнера и выясняем где допущена ошибка:
docker logs authelia
После успешного запуска контейнеров должна быть доступна авторизация:
webserver-ip:9091
Проверьте с именем пользователя и паролем, которые настраивали.
Создаём папки и настраиваем сайт авторизации:
mkdir -p /etc/nginx/sites-available/ /etc/nginx/sites-enabled/ /etc/nginx/snippets/ && \
nano /etc/nginx/sites-available/auth.example.ru
server {
server_name auth.example.ru;
listen 80;
return 301 https://$server_name$request_uri;
}
server {
server_name auth.example.ru;
listen 443 ssl http2;
location / {
set $upstream_authelia http://127.0.0.1:9091;
proxy_pass $upstream_authelia;
client_body_buffer_size 128k;
#Timeout if the real server is dead
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503;
# Advanced Proxy Config
send_timeout 5m;
proxy_read_timeout 360;
proxy_send_timeout 360;
proxy_connect_timeout 360;
# Basic Proxy Config
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;
proxy_set_header X-Forwarded-Host $http_host;
proxy_set_header X-Forwarded-Uri $request_uri;
proxy_set_header X-Forwarded-Ssl on;
proxy_redirect http:// $scheme://;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_cache_bypass $cookie_session;
proxy_no_cache $cookie_session;
proxy_buffers 64 256k;
# If behind reverse proxy, forwards the correct IP
set_real_ip_from 10.0.0.0/8;
set_real_ip_from 172.0.0.0/8;
set_real_ip_from 192.168.0.0/16;
set_real_ip_from fc00::/7;
real_ip_header X-Forwarded-For;
real_ip_recursive on;
}
}
Линкуем:
ln -s /etc/nginx/sites-available/auth.example.ru /etc/nginx/sites-enabled/auth.example.ru
Создаем сниппет для Афелии и авторизации:
nano /etc/nginx/snippets/authelia.conf
# Virtual endpoint created by nginx to forward auth requests.
location /authelia {
internal;
set $upstream_authelia http://127.0.0.1:9091/api/verify;
proxy_pass_request_body off;
proxy_pass $upstream_authelia;
proxy_set_header Content-Length "";
# Timeout if the real server is dead
proxy_next_upstream error timeout invalid_header http_500 http_502 http_503;
# [REQUIRED] Needed by Authelia to check authorizations of the resource.
# Provide either X-Original-URL and X-Forwarded-Proto or
# X-Forwarded-Proto, X-Forwarded-Host and X-Forwarded-Uri or both.
# Those headers will be used by Authelia to deduce the target url of the user.
# Basic Proxy Config
client_body_buffer_size 128k;
proxy_set_header Host $host;
proxy_set_header X-Original-URL $scheme://$http_host$request_uri;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $http_host;
proxy_set_header X-Forwarded-Uri $request_uri;
proxy_set_header X-Forwarded-Ssl on;
proxy_redirect http:// $scheme://;
proxy_http_version 1.1;
proxy_set_header Connection "";
proxy_cache_bypass $cookie_session;
proxy_no_cache $cookie_session;
proxy_buffers 4 32k;
# Advanced Proxy Config
send_timeout 5m;
proxy_read_timeout 240;
proxy_send_timeout 240;
proxy_connect_timeout 240;
}
nano /etc/nginx/snippets/auth.conf
auth_request /authelia;
auth_request_set $target_url $scheme://$http_host$request_uri;
auth_request_set $user $upstream_http_remote_user;
auth_request_set $groups $upstream_http_remote_groups;
auth_request_set $name $upstream_http_remote_name;
auth_request_set $email $upstream_http_remote_email;
proxy_set_header Remote-User $user;
proxy_set_header Remote-Groups $groups;
proxy_set_header Remote-Name $name;
proxy_set_header Remote-Email $email;
error_page 401 =302 https://auth.example.ru/?rd=$target_url;
Немного поясню конфигурацию Nginx.
user www-data;
worker_processes auto;
pid /run/nginx.pid;
events {
worker_connections 1024;
}
http {
sendfile on;
tcp_nopush on;
types_hash_max_size 2048;
include /etc/nginx/mime.types;
include /etc/nginx/snippets/ssl.conf;
default_type application/octet-stream;
gzip on;
include /etc/nginx/sites-enabled/*;
server {
server_name *.example.ru;
listen 80;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name connect.example.ru;
ssl_session_cache builtin:1000 shared:SSL:10m;
include snippets/authelia.conf; # Authelia auth endpoint
include 1c/*.conf;
location / {
root html;
index index.html index.htm;
error_page 404 /404.html;
error_page 500 502 503 504 /50x.html;
}
location = /50x.html {
root html;
}
}
}
Нужно включить фрагмент
include snippets/authelia.conf;
в основной блок server, а также фрагмент
include snippets/auth.conf;
в каждый защищаемый location
В приложенной конфигурации NginX я добавил строку
include 1c/*.conf;
и вынес в отдельные файлы отдельные файлы, каждый location.
Для примера я проксирую доступ к серверу 10.10.10.3 с установленный IIS, на котором опубликована база Гилёва.
cat 1c/gilev.conf
location /gilev/ {
proxy_pass http://10.10.10.3/gilev/;
include snippets/auth.conf;
}
Готовая конфигурация NginX.