My l3g3nd

There is no spoon

Nginx With Microsoft AD Authentication and FastCGI Load Balancing

| Comments

Nginx is an open source fast performing web server and is known for its high performance, stability, rich feature set, simple configuration, and low resource consumption”. Nginx has two versions one of which is open source while other (Nginx Plus) is available with paid support. I have used the open version for all my testing. Instead of writing multiple posts I have combined all that I have learned in this long post.

Nginx – Microsoft AD Authentication

I started tinkering with Nginx to integrate Microsoft AD authentication for the web pages. I was trying to get this working with Lighttpd web server for some quiet some time but to no luck. And just after couple of days of research I was able to setup the authentication working. Below is my sample config

1
2
3
4
5
6
7
8
9
10
11
12
13
auth_ldap_cache_enabled on;
  auth_ldap_cache_expiration_time 10000;
  auth_ldap_cache_size 1000;
 
  ldap_server LDAP1 {
      url "ldap://<ip-address>:3268/DC=<domain-name>,DC=com?sAMAccountName?sub?";
      binddn "<Bind Account>";
      binddn_passwd "<Bind Password>";
      connect_timeout 5s;
      bind_timeout 5s;
      request_timeout 5s;
      satisfy any;
  }

The trick to get AD authentication working is to use a third party open source module for nginx called nginx-auth-ldap. Nginx open doesn’t support adding modules on the fly like Apache/lighttpd so we need to compile the package manually. Here is the step by step guide to get it working with on Ubuntu 14.04:

  1. sudo apt-get install dpkg-dev
  2. sudo apt-get install libldap2-dev
  3. sudo add-apt-repository ppa:nginx/stable
  4. Edit sudo nano /etc/apt/sources.list.d/nginx-stable-trusty.list add dpkg-src:
    1. deb http://ppa.launchpad.net/nginx/stable/ubuntu trusty main
    2. deb-src http://ppa.launchpad.net/nginx/stable/ubuntu trusty main
  5. sudo apt-get update
  6. sudo apt-get source nginx
  7. sudo apt-get build-dep nginx
  8. Edit nginx-0.8.54/debian/rules and under section ‘full_configure_flags := \’ add following line:
    1. —add-module=$(MODULESDIR)/nginx-auth-ldap (Do NOT forget the trailing “\” in previous line else ldap module won’t compile)
  9. Inside modules directory “sudo git clone https://github.com/kvspb/nginx-auth-ldap.git
  10. cd /etc/nginx/nginx-1.8.0
  11. sudo dpkg-buildpackage -uc -us (or -b flag)
  12. Install generated packages inside /etc/nginx
    1. sudo dpkg —install nginx-common_1.8.0-1+trusty1_all.deb
    2. sudo dpkg —install nginx-full_1.8.0-1+trusty1_amd64.deb
  13. Edit main config file accordingly (Change password for the BIND DN account)
  14. Edit /etc/nginx/fastcgi_params and add following:
    1. “fastcgi_param REMOTE_USER $remote_user”;
  15. sudo nginx -V to check if nginx-auth-ldap is loaded

Verify that everything went well and nginx-auth-ldap module is loaded by executing nginx -V on terminal:

Unless --add-module=/etc/nginx/nginx-1.8.0/debian/modules/nginx-auth-ldap line shows in the above image, authentication will not work and there is some problem in adding the module and setting it up. I referred to Server Fault while figuring out any issues.

Round Robin Load Balancing for FastCGI Processes

Nginx is excellent in load balancing as well. Nginx supports load balancing via round-robin, least-connected and ip-hash. I am not going in details of each as this post is not about features of Nginx but what functionality/features I used in my instance. More about load balancing can be read here.

If you have bunch of apps either running on same box or another box running on different ports it is very easy to setup round robin load balancing for them as well. Load balancing servers are defined in block directive:

1
2
3
4
5
upstream  APP1 {
      server   127.0.0.1:4100;
      server   127.0.0.1:4101;
      server   127.0.0.1:4102;
  }

Above code block is self explanatory but just for the heck of it APP1 is running on localhost and is written in such a way that it can support upto 3 ports. We want our web server to load balance via round-robin fashion on three separate ports. This is called in location directive as fastcgi_pass APP2;

Another part in the config is the location directive where you can specify what load balancing server to call when a particular string is present in the requested URI. In my case its .abc.

The other thing to note about FastCGI is that pages that are loaded are not necessarily physically present on the disk. However, they are generated on the fly and displayed on the browser. User is browsing to the page http://<server.com>/APP1/blah.html and that blah.html is requesting .abc page in the backend which is displayed on user browser. I know its complicated to someone new but whoever understands the FastCGI will know what I am talking about. The location code block looks like as follows:

1
2
3
4
location ~ ^/APP1/.+\.bgi$ {
      include /etc/nginx/fastcgi_params;
      fastcgi_pass APP1;
  }

Enable SSL Support

Execute following commands to generate required files

  1. sudo mkdir /etc/nginx/ssl
  2. sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/nginx/ssl/nginx.key -out /etc/nginx/ssl/nginx.crt

Configure server directive in the /etc/nginx.conf file as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
server {
                  listen       80;
          server_name  blog.l3g3ndary.org;
                  listen 443 ssl;

                  ssl_certificate /etc/nginx/ssl/nginx.crt;
                  ssl_certificate_key /etc/nginx/ssl/nginx.key;

                  root /var/www/;
                  index index.html index.htm;

                  auth_ldap "Enter AD credentials";
                  # LDAP block 'LDAP1' defined earlier
                  auth_ldap_servers LDAP1
      }

In the end the my final config files look like as follows:

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
user www-data;
worker_processes 4;
pid /run/nginx.pid;

events {
  worker_connections 768;
  # multi_accept on;
}

http {

  ##
  # Basic Settings
  ##

  sendfile on;
  tcp_nopush on;
  tcp_nodelay on;
  keepalive_timeout 65;
  types_hash_max_size 2048;
  # server_tokens off;

  # server_names_hash_bucket_size 64;
  # server_name_in_redirect off;

  include /etc/nginx/mime.types;
  default_type application/octet-stream;

  ##
  # Logging Settings
  ##
  access_log /var/log/nginx/access.log;
  error_log /var/log/nginx/error.log;

  ##
  # Gzip Settings
  ##
  gzip on;
  gzip_disable "msie6";


  auth_ldap_cache_enabled on;
  auth_ldap_cache_expiration_time 10000;
  auth_ldap_cache_size 1000;
 
  ldap_server LDAP1 {
      url "ldap://<AD server>:3268/DC=<domain name>,DC=com?sAMAccountName?sub?";
      binddn "<account name>";
      binddn_passwd "<password>";
      connect_timeout 5s;
      bind_timeout 5s;
      request_timeout 5s;
      satisfy any;
      }

# load balancing
  upstream  APP1{
      server   127.0.0.1:4100;
      server   127.0.0.1:4101;
      server   127.0.0.1:4102;
  }     

  upstream  APP2{
      server   127.0.0.1:5120;
      server   127.0.0.1:5121;
      server   127.0.0.1:5122;
  }

  server {
      listen       80;
      server_name  _;
      listen 443 ssl;

      ssl_certificate /etc/nginx/ssl/nginx.crt;
      ssl_certificate_key /etc/nginx/ssl/nginx.key;   

      root /var/www/;
      index index.html index.htm;
      
      auth_ldap "Enter AD credentials";
                # LDAP block 'LDAP1' defined earlier
                auth_ldap_servers LDAP1

      location / {
      }
  
      location ~ ^/APP1/.+\.bgi$ {
          include /etc/nginx/fastcgi_params;   
          fastcgi_pass APP1;
      }
      
      location ~ ^/APP2/.+\.bgi$ {
          include /etc/nginx/fastcgi_params;
          fastcgi_pass APP2;
      }

  }
}

This is one of the longest posts I have written and I am sure missed some points that I should have included because of the assumptions made. Feel free to let me know and I will update the blog as necessary.

References

  1. http://serverfault.com/questions/227480/installing-optional-nginx-modules-with-apt-get
  2. https://github.com/kvspb/nginx-auth-ldap
  3. https://www.digitalocean.com/community/tutorials/how-to-create-an-ssl-certificate-on-nginx-for-ubuntu-14-04

Comments