Go to content Go to menu Go to search

Ограничение доступа к сайту по 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!


при публикации материалов с данного сайта обратная ссылка на сайт обязательна.
valynkin.ru © no rights reserved