shaneoh
shaneoh

Reputation: 494

Nginx HTTP basic authentication with exceptions for particular IP addresses

I'm looking to set up basic authentication for a web app I have running.

The app is using nginx 1.12.2 as well as Apache 2.2.15 (although this is a test instance and the production instance uses 1.12.2 and 2.4.6). It's all running on a CentOS 7 server.

I've been using a tutorial here to do this. I've managed to get the authentication working and I'm getting a pop up asking for username and password when I navigate to the site in a browser. However, I can't get the IP whitelist working - credentials are requested wherever I connect from.

The goal is that anyone on our network or connected via our VPN won't have to enter these credentials. Seems like it should be pretty straightforward, but I can't get it to work.

Essentially we need anyone in the range 192.168.1.1-192.168.1.255 to be able to access this, as well as the VPN addresses which are in the range 10.8.0.x.

Before attempting the IP address controls I had to play around with where in the nginx conf file I placed the authentication information to get it working and found it had to be in the section I have added it in. But, the IP controls are not working as stated. I can't see what I'm missing here.

Below are the contents of /etc/nginx/sites-available/myapp.conf

upstream myapplication-3.3.2 {
        server 127.0.0.1:18805;
}

server {
  listen 80;
  server_name mydomain.com;
  location '/.well-known/acme-challenge' {
    default_type "text/plain";
    root  /srv/letsencrypt;
  }
  location / {
    return 301 https://$server_name$request_uri;
  }
}

server {
        listen 18804;
        location / {
                return 301 https://$host$request_uri;
        }
}


server {
        listen 80;
        location / {
                return 301 https://$host$request_uri;
        }
}

server {
        listen 443 ssl;
        server_name mydomain.com;

        access_log /var/log/nginx/myapplication3.access.log;
        error_log /var/log/nginx/myapplication3-errors.log;

        ssl on;
        ssl_certificate_key /home/user1/.acme.sh/mydomain.com/mydomain.com.key;
        ssl_certificate /home/user1/.acme.sh/mydomain.com/fullchain.cer;
        ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:ECDHE-RSA-AES128-GCM-SHA256:AES256+EECDH:DHE-RSA-AES128-GCM-SHA256:AES256+EDH:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4";

        ssl_prefer_server_ciphers on;
        ssl_session_cache shared:SSL:10m;
        ssl_stapling on;
        ssl_stapling_verify on;
        add_header Strict-Transport-Security max-age=15768000;

        satisfy any;
        allow 127.0.0.1;
        allow 192.168.1.1/24;
        allow 10.8.0.0/24;
        deny all;

        auth_basic      "Authentication required";
        auth_basic_user_file /etc/httpd/.htpasswd;

        client_max_body_size 0;

        location / {
                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_pass http://myapplication-3.3.2;
        }
}

server {
        listen 80 default_server;
        listen [::]:80 default_server;
        server_name _;
        return 301 https://$host$request_uri;
}

EDIT

Based on the suggestions so I have established that the issue is something to do with how I am writing the IP addresses themselves. I'm able to get an exception working using 0.0.0.0/0 which is a good start, and also if I use my actual public IP address. But I can't seem to add an exception using my private/internal IP address range. I've tried a few ways including:

192.168.1.0/24 "off";
192.168.1.1/24 "off"
192.168.1.0/32 "off"
192.168.1.0/32 "off"

But I'm still being prompted for authentication when accessing the page despite my IP address being 192.168.1.22.

EDIT added to address question.

When I have 192.168.1.0/24 "off", this is what I see in the log when trying to access the page.

78.432.xx.xxx - - [23/Jan/2018:14:01:19 +0000] "GET /favicon.ico HTTP/1.1" 401 195 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:58.0) Gecko/20100101 Firefox/58.0"

Which I presume means that I'm being asked for credentials because nginx considers the public IP address to be mine. I think there must be some way to tell it to looks for both public and private/internal addresses though.

Because of this I also tried connecting using the internal IP address instead of the domain name and yes, I could connect with no credentials.

Upvotes: 6

Views: 12804

Answers (1)

Shawn C.
Shawn C.

Reputation: 6841

What you are looking for is the geo directive. This should with testing turn on and off authentication based on ip address. Just remove the allow and deny ip ranges.

geo $authentication {
    default "Authentication required";
    127.0.0.1 "off";
    192.168.1.1/24 "off";
    10.8.0.0/24 "off";
    ...
}

server {
    ...
    location / {
        ...
        auth_basic $authentication;
        auth_basic_user_file /etc/nginx/.htpasswd;
        ...
    }
}

Upvotes: 18

Related Questions