Ограничение доступа к сайту по IP в nginx с автоматическим добавлением IP в белый список
Постановка задачи
Имеем Nginx, на котором нужно ограничить доступ по IP для админки сайта.
При этом нужно обеспечить автоматическое добавление IP адресов в белый список.
Как будем решать:
Напишем cgi-скрипт, который при обращении к нему будет добавлять IP клиента в белый список.
Сам же этот cgi-скрипт будет закрыт basic авторизацией (логин-пароль, без ограничения по IP)
Таким образом, при первом доступе к сайту нужно будет сходить на урл, на котором выложен cgi-скрипт и авторизоваться, после чего остальные страницы станут доступны без пароля с ограничением по IP
Реализация
Скрипт /etc/nginx/allow_list.pl
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 | #!/usr/bin/perl # # This script listen FCGI port 9999 # External link: https://example.com/pmadmin # When somebody opens this url the script will add IP of the connected client to the whitelist in /etc/nginx/conf/allow_list.txt # # Runned by /etc/init.d/allow_list start # # created by Valynkin P.S. 25.10.2018 # use strict; use warnings; use FCGI; use Sys::Syslog; use subs qw/err/; use subs qw/say/; use File::Basename; # ====== Preferences and constants ====== # my $REDIRECT_URL='/wp-admin'; my $FILE='/etc/nginx/conf/allow_list.txt'; my $NGINX = '/usr/bin/nginx'; my $LOG_FACILITY='local3'; my $debug = 0; # debug levels: 0, 1 # ========= End of preferences ========== # # ========= Global variables ============ # my $OUT; # ========= End of gobal variables ====== # # ========= Main program ================ # #my $perror = ',$perror' if $debug; my $basename = File::Basename::basename($0); openlog("$basename", "nofatal,pid,perror", $LOG_FACILITY); say "$basename started"; my $socket = FCGI::OpenSocket(":9000", 5); my $request = FCGI::Request(\*STDIN, \*STDOUT, \*STDERR, \%ENV, $socket); while($request->Accept() >= 0) { my @ip_list = &read_file($FILE); say "Got connection from $ENV{'REMOTE_ADDR'}"; my $ip = $ENV{'REMOTE_ADDR'}; if ( not($ip ~~ @ip_list) ) { &write_file($FILE,$ip); say "New IP $ip added to $FILE"; &reload_nginx; sleep 5; } else { say "IP $ip already in $FILE"; } print "Status: 302 Found\n", "Location: $REDIRECT_URL\n\n"; }; closelog; exit; # ========= End of Main program ========= # # ========= Subroutines ================= # sub read_file { my $file=shift; my @arr; open IN, "<$file" ; while (<IN>) { chomp; my $ip = $1 if ( $_ =~ /^allow\s(\d+\.\d+\.\d+\.\d+)\;/); push @arr,$ip; } close IN; return @arr; } sub write_file { my $file = shift; my $ip = shift; open OUT, ">>$file" ; print OUT "\n# ", scalar localtime(),"\n"; print OUT "allow $ip;\n"; close OUT; } sub reload_nginx { say "Reloading nginx"; $OUT = `$NGINX -t`; err "Nginx configuration test failed: $OUT" if $?; $OUT = `$NGINX -s reload`; err "Nginx reload test failed: $OUT" if $?; } sub say { my $msg = shift; syslog('info', "$msg"); } sub err { my $msg = shift; syslog('err', 'ERROR: '."$msg"); closelog; die; } # ========= End of Subroutines ========== # |
Добавляем в конфиг Nginx:
# защищаемая по IP часть сайта (в данном случае wordpress админка) location ~ ^/(wp-admin|wp-login\.php) { include propertyminder_allow_list.txt; deny all; proxy_pass http://172.17.254.206;
}
# наш скрипт, закрытый праролем location /pmadmin/ { # To add user and set pasword: # echo -n 'user:' >> /etc/nginx/conf/.htpasswd # openssl passwd -apr1 >> /etc/nginx/conf/.htpasswd auth_basic "Restricted Content"; auth_basic_user_file /etc/nginx/conf/.htpasswd; include fastcgi_params; fastcgi_pass localhost:9000; }
Скрипт для запуска /etc/init.d/allow_list:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | #!/bin/bash # # chkconfig: 2345 12 88 # # processname: allow_list # Short-Description: allow_list # Source function library. . /etc/init.d/functions NAME='allow_list' PROG='/etc/nginx/conf/propertyminder_allow_list.pl' PID='/var/run/allow_list.pid' start() { echo -n "Starting : $PROG" daemonize -p $PID $PROG touch /var/lock/subsys/allow_list return } stop() { echo -n "Shutting down : $PROG" cat $PID | xargs kill rm -f /var/lock/subsys/allow_list return } case "$1" in start) start ;; stop) stop ;; restart) stop start ;; *) echo "Usage: {start|stop|restart}" exit 1 ;; esac exit $? |
Enjoy!