Showing posts with label nginx. Show all posts
Showing posts with label nginx. Show all posts

Thursday, May 20, 2021

Secure TCP to Upstream

Overview 
-------- 

 

- TCP connection to upstream servers (group of proxied/backend servers) can be 

  secured using SSL 

- requirements: 

    a. Nginx PLUS R6 and later or NGINX Open Source compiled with 

       `--with-stream` and `with-stream_ssl_module` 

    b. upstream group of servers / proxied TCP servers 

    c. SSL certificate and a private key 

- setup is similar in securing HTTPS to upstream but `stream` context is used instead 

 

Complete Example 

---------------- 

 

stream { 

 

    upstream backend { 

        server backend1.example.com:12345; 

        server backend2.example.com:12345; 

        server backend3.example.com:12345; 

   } 

 

    server { 

        listen     12345; 

        proxy_pass backend; 

        proxy_ssl  on; 

 

        proxy_ssl_certificate         /etc/ssl/certs/backend.crt; 

        proxy_ssl_certificate_key     /etc/ssl/certs/backend.key; 

        proxy_ssl_protocols           TLSv1 TLSv1.1 TLSv1.2; 

        proxy_ssl_ciphers             HIGH:!aNULL:!MD5; 

        proxy_ssl_trusted_certificate /etc/ssl/certs/trusted_ca_cert.crt; 

 

        proxy_ssl_verify        on; 

        proxy_ssl_verify_depth  2; 

        proxy_ssl_session_reuse on; 

    } 

} 

 

 

Sunday, April 4, 2021

Setup NGINX Proxy

Once in a while there are applications that needs to run in unprivileged port
(ports above 1024). What can you do to protect its identity from attacks? Aha!
Use HTTPS.. But how? We can setup another host in front of it (proxy server) to
accept incoming requests via encrypted channel (HTTPS, port 443/tcp) and
redirect that to the backend server (or proxied host) via an uncrypted channel.
In this post, we will use Nginx to have that setup.

1. First, let's say we have VM01 that runs an application on port 8081.







2. Now, let's spin up another host, VM02 (Centos 7.3 w/ SELinux in enforcing
mode), and install Nginx. First, be sure that the nginx repo is enabled.

[root@vm02 ~]# cat /etc/yum.repos.d/nginx.repo
[nginx]
name=nginx repo
baseurl=http://nginx.org/packages/centos/7/x86_64/
gpgcheck=0
enabled=1
[root@vm02 ~]#

3. Install nginx package.

[root@vm02 ~]# yum install -y nginx

4. Start and enable nginx at boot

[root@vm02 ~]# systemctl start nginx
[root@vm02 ~]# systemctl enable nginx
Created symlink from /etc/systemd/system/multi-user.target.wants/nginx.service to /usr/lib/systemd/system/nginx.service.
[root@vm02 ~]#

5. Create selfsigned certificates. In this part, you may use `genkey` or
`openssl`. I always wanted the openssl way because its faster. BTW, don't
memorize the command below. Just be familiar with it because you can always see
it inside `/etc/pki/tls/certs/make-dummy-cert`

[root@vm02 ~]# /usr/bin/openssl req -newkey rsa:2048 -keyout vm02.key -nodes -x509 -days 365 -out vm02.crt
Generating a 2048 bit RSA private key
.........+++
..........................................................................................+++
writing new private key to 'vm02.key'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:US
State or Province Name (full name) []:California
Locality Name (eg, city) [Default City]:Los Angeles
Organization Name (eg, company) [Default Company Ltd]:dummy
Organizational Unit Name (eg, section) []:dummy
Common Name (eg, your name or your server's hostname) []:vm02
Email Address []:dummy@nxdomain.com
[root@vm02 ~]#

6. Move the certificates to the correct paths and run `restorecon` to make sure
SELinux contexts are correct.

[root@vm02 ~]# mv *crt /etc/pki/tls/certs
[root@vm02 ~]# mv *key /etc/pki/tls/private/                                                                                                                                                                [root@vm02 ~]# restorecon -Rv /etc/pki/tls/
restorecon reset /etc/pki/tls/certs/vm02.crt context unconfined_u:object_r:admin_home_t:s0->unconfined_u:object_r:cert_t:s0
restorecon reset /etc/pki/tls/private/vm02.key context unconfined_u:object_r:admin_home_t:s0->unconfined_u:object_r:cert_t:s0
[root@vm02 ~]#

7. Update nginx configuration to use SSL, point to the correct certificates
(ssl_certificate_*), and activate reverse proxy (proxy_pass). We will just use
the default config and use the minimal directives needed for simplicity.

[root@vm02 ~]# cat /etc/nginx/conf.d/default.conf
server {
    listen       443;
    server_name  vm02;
    ssl on;
    ssl_certificate /etc/pki/tls/certs/vm02.crt;
    ssl_certificate_key /etc/pki/tls/private/vm02.key;

    error_page   500 502 503 504  /50x.html;
    location = /50x.html {
        root   /usr/share/nginx/html;
    }

    location / {
        proxy_pass   http://vm01:8081;
    }
}
[root@vm02 ~]#

8. Open up port 443/tcp on the firewall to allow incoming connections. You may
use firewall-cmd's "--add-service" or "--add-port". Let's use "--add-service"
since there is already an existing service defined for HTTPS.

[root@vm02 ~]# firewall-cmd --add-service=https --permanent
success
[root@vm02 ~]# firewall-cmd --reload
success
[root@vm02 ~]#

9. Activate this SELinux boolean to allow HTTP to forward requests to our
upstream server (VM01).

[root@vm02 ~]# setsebool -P httpd_can_network_connect on
[root@vm02 ~]#

10. Now, our proxy server is ready. Let's try connecting. It must display the
data from the upstream like in #1.







So that are the basics steps in hiding your application via a proxy server.
This is very important if your application accepts user details like username
and passwords. You never want your credentials to be sent in cleartext!

Hope you learned something from this post :)

Saturday, June 30, 2018

Proxy Limiting


Introduction
------------

- Nginx and Nginx Plus can limit the ff:
    a. number of connections per key value (e.g per IP address)
    b. request rate per key value (limits requests per second or minute)
    c. download speed

Limiting Number of Connections
------------------------------

setup
http {
    limit_conn_zone $server_name zone=servers:10m;
    # $server_name -> key
    # zone         -> used by worker processes to share counters for key values
    # servers      -> zone name
    # 10m          -> zone size
 [...]

  # limits connection on this location
  location /download/ {
      limit_conn addr 1;
  }
} 

Limiting Request Rate
---------------------

setup
http {
  [...]
    # limits to 1 request per second (r/m for request per minute)
    limit_req_zone $binary_remote_addr zone=one:10m rate=1r/s;
 [...]

  location /download/ {
      # This will limit requests to this location by 1r/s. If requests
      # exeeds rate limit, those are put into queue. `burst` parameter
      # is the max requests that awaits processing. If requests exceeds
      # `burst` value, Nginx will respond a 503 error.
      limit_req zone=one burst=5;

      # You can use this instead to prevent delay set by `burst`
      # limit_req zone=one burst=5 nodelay;
  }
}

Limiting bandwidth
------------------

limits dowload speed to 50k/s
but multiple connections are
still allowed
  location ~ \.bin {
    root /data;
    limit_rate 50k;
  }
limits download speed and at
the same time limits 1 connection
per IP address
http {
  [...]
  limit_conn_zone $binary_remote_addr zone=addr:10m;
  [...]
}

server {
  [...]
  location ~ \.bin {
    root /data;
    limit_conn addr 1;
    limit_rate 50k;
  }
  [...]
}
limits bandwidth after certain size
has been downloaded (e.g: useful
when client needs to download a
file header)
location {
  [...]
  limit_rate_after 500k;
  limit_rate 20k;
  [...]
}

Friday, June 29, 2018

HTTP Authentication (Nginx)


Introduction
------------

- available on both Nginx opensource and Nginx PLUS
- requires password file creation file creation tool (e.g apache-2 utils)
- can enforce restriction based on:
    a. IP address
    b. geographical location

Setting up authentication
-------------------------

1. Install apache2-utils
     # yum install httpd-tools

2. Create a password file containing the 1st user
     # htpasswd -c /etc/nginx/.htpasswd_users user1

3. Add another user if needed
     # htpasswd /etc/nginx/.htpasswd_users user2

4. Make sure selinux (if selinux is enabled) and permission is correct on the
   password file
     # chown nginx /etc/nginx/.htpasswd_users
     # restorecon -Rv /etc/nginx

5. Add the following directives on the location you wish to protect
  location ~ \.(pdf|PDF) {
    root /payroll;
    auth_basic "restricted area";
    auth_basic_user_file /etc/nginx/.htpasswd_users;
  }

6. Restart nginx
     # systemctl restart nginx

7. Try downloading a file from that location
     # wget http://server.home.net/01-01-1970.pdf --user=user1 --password=pass123

Common configurations
---------------------

limiting access to the whole website
server {
    ...
    # Restrict access to all location below
    auth_basic  "My personal files";
    auth_basic_user_file /etc/nginx/.htpasswd_users;

    location ~ \.(mp3|mp4) {
      root /music;
    }

    location ~ \.(jpg|png) {
      root /pictures;
    }
}
bypassing `server` level authentication
server {
    ...
    # Restrict access to all location below except for 1 location
    auth_basic  "My personal files";
    auth_basic_user_file /etc/nginx/.htpasswd_users;

    location ~ \.(mp3|mp4) {  # this will require credentials
      root /music;
    }

    location ~ \.(jpg|png) {  # this will require credentials
      root /pictures;
    }

    location /public {
      root /downloads;
      auth_basic off;  # this wouldn't require credentials
    }
}
Restricting by either source IP or
credentials
location ~ \.txt {
  satisfy any;         # this will honor source IP or credentials
  allow 192.168.1.11;  # Nginx will allow from this source IP only
  deny all;            # others are deny

  root /files/public;

  auth_basic "my personal files";
  auth_basic_user_file /etc/nginx/.htpasswd_users;
}
Restricting by both source IP and
credentials
location ~ \.txt {
  satisfy all;         # source IP and credentials must be correct
  allow 192.168.1.11;  # Nginx will allow from this source IP only
  deny all;            # others are deny

  root /files/public;

  auth_basic "my personal files";
  auth_basic_user_file /etc/nginx/.htpasswd_users;
}

Thursday, June 28, 2018

Securing Proxy HTTP/TCP Traffic


Secure HTTP
-----------

- traffic between nginx proxy server and upstream server can also be encrypted

CLIENT -- SSL --> PROXY SERVER (nginx) -- SSL --> UPSTREAM SERVER (Apache, Nginx, etc..)

1. Get SSL certificate for proxy server
self-signed or signed by CA
2. Configure proxy server
location /upstream {
    proxy_pass https://backend.example.com;
    proxy_ssl_certificate     /etc/nginx/client.pem;
    proxy_ssl_certificate_key /etc/nginx/client.key

    # must be in PEM format
    proxy_ssl_trusted_certificate /etc/nginx/trusted_ca_cert.crt;

    # checks validity of certificates
    proxy_ssl_verify       on;
    proxy_ssl_verify_depth 2;

    # reuses previous sessions w/c reduces number of handshakes
    proxy_ssl_session_reuse on;

    proxy_ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    proxy_ssl_ciphers   HIGH:!aNULL:!MD5;
}
3. Configure upstream server
server {
    listen              443 ssl;
    server_name         backend1.example.com;

    # I don't know if these certificates are from the proxy
    # server or from the upstream server
    ssl_certificate     /etc/ssl/certs/server.crt;
    ssl_certificate_key /etc/ssl/certs/server.key;

    # Confused also with this one!
    ssl_client_certificate /etc/ssl/certs/ca.crt;
    ssl_verify_client      off;

    location /yourapp {
        ...
    }
}

Secure TCP

----------

- TCP connection to upstream servers (group of proxied/backend servers) can be
  secured using SSL
- requirements:
    a. Nginx PLUS R6 and later or NGINX Open Source compiled with
       `--with-stream` and `with-stream_ssl_module`
    b. upstream group of servers / proxied TCP servers
    c. SSL certificate and a private key
- setup is similar in securing HTTPS to upstream but `stream` context is used instead

stream {

    upstream backend {
        server backend1.example.com:12345;
        server backend2.example.com:12345;
        server backend3.example.com:12345;
   }

    server {
        listen     12345;
        proxy_pass backend;
        proxy_ssl  on;

        proxy_ssl_certificate         /etc/ssl/certs/backend.crt;
        proxy_ssl_certificate_key     /etc/ssl/certs/backend.key;
        proxy_ssl_protocols           TLSv1 TLSv1.1 TLSv1.2;
        proxy_ssl_ciphers             HIGH:!aNULL:!MD5;
        proxy_ssl_trusted_certificate /etc/ssl/certs/trusted_ca_cert.crt;

        proxy_ssl_verify        on;
        proxy_ssl_verify_depth  2;
        proxy_ssl_session_reuse on;
    }
}