Securitzar accés a Elasticsearch des d'una pàgina web

Darrera actualització: 01-03-2017

A qui va dirigit

Aquest how-to va dirigit a tots aquells proveïdors d’aplicacions que utilitzin Elasticsearch (ES) i vulguin securitzar la connexió amb l’ES des de navegadors web.

Introducció

En cas que l’accés a un ES es realitzi directament des del navegador de l’usuari, cal que el client disposi de les credencials d’accés a aquest ES, amb les vulnerabilitats de seguretat que això pot implicar.

Per evitar-ho es proposa aprovisionar un proxy intermig que sigui qui disposi d’aquestes credencials i així evitar-ne la potencial sostracció.

En aquest HowTo expliquem com configurar un Apache 2.2 / 2.4 per a que faci aquesta funció de proxy cap a l’ES.

Elasticsearch

Per aquest howto hem instal·lat mitjançant Docker un ES

Hem modificat el fitxer “elasticsearch.yml” per a configurar el CORS:

http.host: 0.0.0.0

http.cors.enabled : true
 
http.cors.allow-origin : "*"
http.cors.allow-methods : OPTIONS, HEAD, GET, POST, PUT, DELETE
http.cors.allow-headers : X-Requested-With,X-Auth-Token,Content-Type, Content-Length

Una vegada desplegat al accedir a http://localhost:9200 el navegador ens ha de mostrar:

{
	name: "OOHe2gg",
	cluster_name: "docker-cluster",
	cluster_uuid: "pzOqu-XkRvGMKM08gcCUVw",
	version: {
	number: "5.2.2",
	build_hash: "f9d9b74",
	build_date: "2017-02-24T17:26:45.835Z",
	build_snapshot: false,
	lucene_version: "6.4.1"
},
	tagline: "You Know, for Search"
}

Exemple aplicació Angular

Hem utilitzat la següent aplicació AngularJS per l’accés a l’ES.

Una vegada seguits els passos pel seu desplegament, accedim amb el navegador al fitxer index.html i ens trobem amb el següent error:

Aquest error és degut al fet que tenim l’ES securitzat i no hem especificat les credencials al index.html. Com que precisament és això el que volem evitar, aprovisionem un Apache amb les credencials d’accés a l’ES.

Configuració Apache

Per aquest Howto hem desplegat un Apache amb Docker amb els següents canvis al fitxer httpd.conf:

Hem afegit els següents mòduls:

LoadModule headers_module modules/mod_headers.so
LoadModule proxy_http_module modules/mod_proxy_http.so

I realitzat la següent configuració per la funcionalitat de proxy cap a l’ES:

Apache 2.4

<Location "/">
	RequestHeader set Authorization "Basic ZWxhc3RpYzpjaGFuZ2VtZQ=="
	Require ip 192.168.99.1
	ProxyPass        "http://127.0.0.1:9200/"
	ProxyPassReverse "http://127.0.0.1:9200/"
</Location>

on

  • http://127.0.0.1:9200/ és la URL d’accés a l’ES
  • 192.168.99.1 és la IP/Host de l’aplicació. En cas d’especificar un domini enlloc d’una IP s’haurà de fer de la següent manera “Require host

Apache 2.2

<Location "/">
	RequestHeader set Authorization "Basic ZWxhc3RpYzpjaGFuZ2VtZQ=="
	
	Order deny,allow
	Deny from all
	Allow from 192.168.99.1
	
	ProxyPass        "http://127.0.0.1:9200/"
	ProxyPassReverse "http://127.0.0.1:9200/"
</Location>

Les credencials d’accés del nostre ES són (usuari=elastic, password=changeme).

Aquestes credencials s’han d’especificar codificades en BASE64 en la sentència RequestHeader en format “user:password”:

elastic:changeme ---> ZWxhc3RpYzpjaGFuZ2VtZQ==

En aquest exemple hem afegit per seguretat (whitelist) la sentència Require ip. Aquesta sentència permet indicar les IPs per les que el proxy accepta sol·licituds.

Modifiquem el index.html per a canviar la url d’accés per a que apunti al proxy:

 host: 'http://192.168.99.100:9200' (ES) -->  host: 'http://192.168.99.100' (proxy),

Ara al accedir a l’index.html el navegador ens mostrarà correctament l’estat de l’ES:

Elasticsearch per HTTPS i balancejat

En cas que el nostre Elasticsearch només es pugui accedir per HTTPS (Per exemple un Elasticsearch desplegat a Compose) i tingui més d’un node s’ha de modificar la configuració al Apache de la següent manera:

Primer de tot afegir el mòdul ssl:

LoadModule ssl_module modules/mod_ssl.so
LoadModule proxy_balancer_module modules/mod_proxy_balancer.so

Apache 2.2

<VirtualHost *:80>

	SSLProxyEngine On
	
	<Proxy balancer://mycluster>
		BalancerMember https://${ELASTIC_HOSTNAME1}:${ELASTIC_PORT1}/
		BalancerMember https://${ELASTIC_HOSTNAME2}:${ELASTIC_PORT2}/
		# Set counting algorithm to more evenly distribute work: 
		ProxySet lbmethod=byrequests
	</Proxy>
	
	<Location "/">
		RequestHeader set Authorization "Basic ${ELASTIC_CREDENTIALS}"
		
		Order deny,allow
		Deny from all
		Allow from 192.168.99.1
		
		ProxyPass balancer://mycluster/
		ProxyPassReverse balancer://mycluster/
	</Location>
</VirtualHost>

Apache 2.4

<VirtualHost *:80>

	SSLProxyEngine On
	
	<Proxy balancer://mycluster>
		BalancerMember https://${ELASTIC_HOSTNAME1}:${ELASTIC_PORT1}/
		BalancerMember https://${ELASTIC_HOSTNAME2}:${ELASTIC_PORT2}/
		# Set counting algorithm to more evenly distribute work: 
		ProxySet lbmethod=byrequests
	</Proxy>
	
	<Location "/">
		RequestHeader set Authorization "Basic ${ELASTIC_CREDENTIALS}"
		
		Require ip 192.168.99.1
		
		ProxyPass balancer://mycluster/
		ProxyPassReverse balancer://mycluster/
	</Location>
</VirtualHost>

On $ELASTIC_CREDENTIALS són les credentials en Base64 (De la mateixa manera que a l’exemple HTTP), i $ELASTIC_HOSTNAME1:${ELASTIC_PORT1} , $ELASTIC_HOSTNAME2:${ELASTIC_PORT2} són les dos url de connexió amb Elasticsearch.