Securing Elasticsearch using Nginx as a Proxy

Elasticsearch doesn’t come with any type of security out of the box. It’s so open and accessible, anyone can destroy all of your data with a single call. Yes, there is protection against the DELETE call, but it is possible. Recently Elastic released the Shield plugin to allow for encrypted communication, access control and a slew of other security features, but it costs money. Before Shield you had to wrap Elasticsearch in a proxy like Nginx to enable some sort of access control and encryption. This is still a viable option if you don’t want to buy a Shield license, or if you feel Shield is overkill.

This post will look at configuring Nginx as a proxy for securing Elasticsearch.



Setup

You’ll need to ensure that you have Nginx installed, as well as Apache Utils to create the HTTP password file:

sudo apt-get install nginx apache2-utils

You also need to create a password file for the HTTP authentication. The following command will prompt you for a password for the user you specified:

sudo htpasswd -c /etc/nginx/conf.d/search.htpasswd exampleuser

The created file should only be accessible by the user that is running Nginx.

To enable SSL you need a certificate and a key. For this example we’ll assume you have both, otherwise look at this post on how to create self signed certs.

The first config is just the proxy with HTTP Basic Authentication and will serve as the base config. We’ll add SSL in the second config.

Base Config

server { listen *:80 ; server_name search.eagerelk.com; access_log /var/log/nginx/search.access.log; location / { auth_basic "EagerELK Search"; auth_basic_user_file /etc/nginx/conf.d/eagerelk.htpasswd; # Send everything to the Elasticsearch endpoint try_files @elasticsearch; } # Endpoint to pass Elasticsearch queries to location @elasticsearch { proxy_pass http://127.0.0.1:9200; proxy_read_timeout 90; } }

As you can see it’s a relatively simple setup. The simplicity comes from putting the whole Elasticsearch setup behind Nginx and just proxying the requests through.

Elasticsearch over SSL

Data is only as secure as the line it travels across, so let’s add SSL encryption to this setup:

# Redirect all insecure requests to the secure port server { listen *:80 ; server_name search.eagerelk.com; return 301 https://$server_name$request_uri; } # Serve SSL encrypted data server { listen *:443 default_server ssl; server_name search.eagerelk.com; access_log /var/log/nginx/search.access.log; # Specify the certificate and key ssl_certificate /etc/nginx/ssl/search.eagerelk.com.crt; ssl_certificate_key /etc/nginx/ssl/search.eagerelk.com.rsa; location / { auth_basic "EagerELK Search"; auth_basic_user_file /etc/nginx/conf.d/eagerelk.htpasswd; # Send everything to the Elasticsearch endpoint try_files @elasticsearch; } # Endpoint to pass Elasticsearch queries to location @elasticsearch { proxy_pass http://127.0.0.1:9200; proxy_read_timeout 90; } }

Access Control

If you want to open up certain Elasticsearch actions, you can just add more location clauses or tweak the location / clause to allow those requests. Since we defined the @elasticsearch endpoint, it’s easy to add different locations that will proxy through to it with or without authentication. Nginx matches on the most specific location first, which allows you to exert fine-grained control over what is allowed and what’s not:

Read only access

server { # ... # Allow read only public access location / { try_files @elasticsearch; limit_except GET { auth_basic "EagerELK Search"; auth_basic_user_file /etc/nginx/conf.d/eagerelk.htpasswd; try_files @elasticsearch; } } # ... }

Index specific control

Make the public index public, and the private index private:

server { # ... # Add access control to the private index location /private { auth_basic "EagerELK Search"; auth_basic_user_file /etc/nginx/conf.d/eagerelk.htpasswd; try_files @elasticsearch; } # Make the public index public location /public { try_files @elasticsearch; } # ... }

Keep your data safe

Allow anything but DELETE calls:

server { # ... # Allow everything but DELETE calls location / { try_files @elasticsearch; limit_except DELETE { deny all; } } # ... }

Since Nginx doesn’t take up a lot of resources, it’s convenient and simple enough to install it on the same server as Elasticsearch if you’re running a single machine cluster or a cluster with only one client node. If you have a cluster with multiple clients, you can install it on a master node and have it load balance between the nodes, or just install and configure it on each of the client nodes.

This should provide you with at least a base configuration to secure your Elasticsearch cluster. Happy searching!

More interesting tips: http://www.elasticsearch.org/blog/playing-http-tricks-nginx/