Nesnesitelná lehkost vyhledávání (ve vašich datech) — díl 1: zabezpečení Elasticsearch

Stanislav Prihoda 🔥
OpenWise Tech blog
Published in
12 min readApr 22, 2019

SearchGuard, Open Distro for Elasticsearch

Photo by Dave Redfern on Unsplash

Úvod

Objem dat, který se každým okamžikem celosvětově vygeneruje, nezadržitelně roste. Řada firem se předhání v odhadu přesnějšího (a ideálně co nejvyššího) čísla o kolik se vlastně za každou minutu/den/člověka/atd. jedná, nicméně faktická (ohromující) číslovka není vlastně zcela podstatná. Co však podstatné je, že důležitější než objem surových dat, jež dokážeme vytvořit, je množství využitelných informací o našem fungování, výkonnosti, prostředí, trhu a konkurenci (atd. doplň si sám), které z daných dat dokážeme získat a to skrze jejich efektivní zpracování a vyhledávání v nich. Technologií a platforem, které v této oblasti působí je nepřeberné množství a spolu s rostoucím objemem dat je jasné, že jejich důležitost těžko bude kdy klesat.

Elasticsearch

Jednou ze stálic v této oblasti je nástroj Elasticsearch postavený na technologii Apache Lucene, který umožňuje zaindexování kýžených datových zdrojů ve formě tzv. JSON dokumentů a následné efektivní vyhledávání v nich. To je při správném nastavení skutečně, skutečně rychlé (řády milisekund) a i to nad značně velkými objemy nestrukturovaných textových dat tzn. super poprvé! K popularitě tohoto nástroje navíc zásadně přispívá fakt, že je ve svém jádru open-source projektem a tudíž jeho klíčových vyhledávacích a analytických funkcí je možno jednoduše využívat zdarma (dle pravidel Apache License 2.0.) tzn. super podruhé! “Ve svém jádru” je však podstatné vymezení, neboť business model firmy Elastic je postaven právě na všech dalších důležitých doplňkových funkcích, které jsou poskytovány a licencovány komerčně na placené subscription bázi tzn. zde již je potřeba (při omezeném rozpočtu) být obezřetnější.

Safety first!

Jednou z takových zásadních doplňkových funkcí, která je se zpřístupňováním dat a vyhledáváním v nich ruku v ruce spjata, je zajištění jejich bezpečnosti a znemožnění jejich neautorizovaných změn. Elasticsearch cluster je totiž po svém základním zprovoznění zcela “otevřený” (stejně jako jeho kód :)) a kdokoli, kdo zná jeho adresu, může kromě vyhledávání v dokumentech tyto dokumenty jakkoliv měnit, doplňovat či mazat. U některých případů užití toto nemusí být zásadní problém, nicméně u kritických či citlivých dat, která jsou využívána k business analýzám, reportingu a rozhodování nebo jsou zpřístupněna koncovým uživatelům toto určitě není zcela kýžený stav. Elastic za tímto účelem poskytuje jednu z doplňkových komerčních funkcí Security v balíku tzv. Elastic Stack Features (také známé jako X-Pack). Předmětem tohoto článku však není komerční X-Pack samotný, nicméně právě další dostupné alternativy, které poskytnou účinnou formu zabezpečení s vynaložením přiměřených zdrojů.

Zaměření: role-based access control

Klíčovou funkcí, na kterou jsou ukázky zaměřeny je tzv. role-based access control tedy řízení oprávnění na základě přiřazené role danému přistupujícímu uživateli (po jeho alespoň základní autentifikaci) a to právě s restriktivním cílem znemožnit plošnou možnost úpravy indexů a dokumentů v nich. Jinými slovy navodit stav kdy jeden (technický) uživatel může v našem clusteru pouze číst (read-only access) a druhý může “cokoli” (admin access).

Poznámka: ukázky jsou zaměřeny na co nejjednodušší možnou ilustraci základního konceptu a nesnaží se být žádným způsobem návodem k plné produkční implementaci. U té je vždy nutné zvážení řady dalších faktorů např. parametrů zpracovávaných dat či charakteristik konkrétního prostředí.

Ukázky jsou zprovozněny v prostředí Docker s cílem jejich co nejjednodušší reprodukce. Veškerý kód publikován zde:

Alternativa 1: SearchGuard

search-guard.com

První zajímavou možností je využití SearchGuard pluginu do Elasticsearch od společnosti floragunn GmbH. Tento plugin nabízí již v základní verzi tzv. Community Edition řadu potřebných bezpečnostních funkcí např. TLS encryption (pro REST i transport layer), HTTP Basic Authentication, Role-based access control a další (např. využití i pro zabezpečení uživatelského nástroje Kibana, ale o tom až příště). Navíc je daná verze licencována obdobně jako jádro Elasticsearch software samotného tedy pod Apache License 2.0. Plugin SearchGuard je pro naše účely zvolen jako reprezentant Elasticsearch pluginů třetích-stran, protože i z hlediska referencí se jedná o ověřenou záležitost. Existují však samozřejmě i další např. plugin ReadonlyREST.

Inicializace Elasticsearch clusteru a instalace SearchGuard plugin

V Docker platformě je spuštění obou nástrojů velmi jednoduché — u Elasticsearch stačí vybrat kýženou verzi v publikovaných Docker images. Zároveň je nabídnuta možnost (z hlediska jistoty využití pouze skutečně open-source funkcí) zvolit “čisté” oss (=open-source) verze, které neobsahují doplňkové funkcionality. Dle zvolené verze Elasticsearch je třeba následně vhodně vybrat verzi SearchGuard pluginu, která má být nainstalována. Za tímto účelem je vypublikována mapovací tabulka mezi verzemi Elasticsearch a pluginu SearchGuard. V našem případě zvolíme Elasticsearch 6.6.2 a SearchGuard verzi 24.2.

Dockerfile tedy vypadá následovně:

Náš dockerfile je na instrukce poměrně jednoduchý. Jako base image je využit elasticsearch-oss image v kýžené verzi (poznámka: ten je postaven na base image CentOS verze 7, což je defacto pouze “převlečený” Red Hat Enterprise Linux, tzn. velmi rozšířené distribuce). Dále jsou pod root uživatelem nastavena oprávnění k relevantním elastic souborům a adresářům (pro uživatele elasticsearch), pod kterým se ve výsledku container spouští. Dále je nainstalován SearchGuard plugin, který je získáván z Central Maven Repository. Nakonec je nakopírována naše verze skriptu install_demo_configuration.sh do relevantního adresáře a je spuštěn. Tento skript nastavuje po daný cluster kompletní demo konfiguraci a je dobré se na něj blíže podívat, protože poměrně dobře obecně ilustruje minimálně nutné kroky/oblasti, které je nutno řešit z hlediska nastavení zabezpečení daným pluginem (nejen v rámci demo konfigurace).

Ve shrnutí tento bash script:

  • Řeší certifikáty: přidává demo TLS certifikáty v PEM formátu do config složky Elasticsearch. Poznámka: toto je primární věc, kterou lze brát jako opravdu pouze “proof-of-concept” a v potencielní produkční verzi je třeba pracovat s vlastní sadou certifikátů.
  • Řeší searchguard konfiguraci v elasticsearch.yml: přidává potřebnou bezpečnostní konfiguraci (zejména z pohledu TLS) do hlavního configu Elasticsearch — elasticsearch.yml. Tu projdeme později.
  • Může přidat auto-initialize nastavení do elasticsearch.yml, které automaticky inicializuje Search Guard konfigurační index (pokud neexistuje). Poznámka: v našem případě tuto možnost nevyužíváme, nicméně lze umožnit přidáním -i parametru při spouštění daného install skriptu. Výsledkem je konfigurační parametr searchguard.allow_default_init_sgindex: true v elasticsearch.yml.
  • Vygeneruje sgadmin_demo.sh script, který je možno použít k aplikování daného nastavení (či jeho změn) skrze příkazovou řádku. Na tento script se podíváme za chvíli.

Pro spuštění už stačí pouze vybuildovat image z daného Dockerfile

docker build . -t stanislavprihoda/elastic-sg-security

… a spustit container na základě vytvořeného image

docker run -p 9200:9200 stanislavprihoda/elastic-sg-security:latest

Konfigurace clusteru a SearchGuard plugin

Abychom si prohlédli konfiguraci našeho clusteru, tak se stačí jednoduše připojit k výše spuštěnému containeru (přes dohledání jeho id ve výpisu běžících containers příp. můžeme v rámci docker run nastavit i — name parametr) a spustit bash shell:

docker psdocker exec -it 432a8ea6ba89 /bin/bash

Klíčovým konfiguračním filem z hlediska Elasticsearch je elasticsearch.yml. Ten jak je výše zmíněno je v průběhu demo instalace SearchGuard pluginu doplněn o nutná hlavní bezpečnostní nastavení, která si blíže představíme.

cat config/elasticsearch.yml

Po dokončené instalaci vypadá elasticsearch.yml následovně

cluster.name: “docker-cluster”
network.host: 0.0.0.0
######## Start Search Guard Demo Configuration ########
# WARNING: revise all the lines below before you go into production
searchguard.ssl.transport.pemcert_filepath: esnode.pem
searchguard.ssl.transport.pemkey_filepath: esnode-key.pem
searchguard.ssl.transport.pemtrustedcas_filepath: root-ca.pem
searchguard.ssl.transport.enforce_hostname_verification: false
searchguard.ssl.http.enabled: true
searchguard.ssl.http.pemcert_filepath: esnode.pem
searchguard.ssl.http.pemkey_filepath: esnode-key.pem
searchguard.ssl.http.pemtrustedcas_filepath: root-ca.pem
searchguard.allow_unsafe_democertificates: true
searchguard.authcz.admin_dn:
— CN=kirk,OU=client,O=client,L=test, C=de
searchguard.audit.type: internal_elasticsearch
searchguard.enable_snapshot_restore_privilege: true
searchguard.check_snapshot_restore_write_privileges: true
searchguard.restapi.roles_enabled: [“sg_all_access”]
cluster.routing.allocation.disk.threshold_enabled: false
discovery.zen.minimum_master_nodes: 1
node.max_local_storage_nodes: 3
searchguard.enterprise_modules_enabled: false######## End Search Guard Demo Configuration ########

Ve výpisu vidíme dvě zásadní věci. Nastavení TLS na transport layer — tzn. pro mezi-nodovou komunikaci, která je provozována po tcp (bez http overheadu), a spuštění TLS i pro http komunikaci searchguard.ssl.http.enabled: true, které lze narozdíl od transport i vypnout. Z dalších nastavení je nutno také explicitně potvrdit užití demo certifikátů searchguard.allow_unsafe_democertificates: true, jakožto určitá bezpečností pojistka. Oproti defaultní verzi daného scriptu je do naší ukázkové verze přidáno ještě zadání jednoho nastavení a to searchguard.enterprise_modules_enabled: false, které zajišťuje, že jsou skutečně používány pouze nekomerční funkce z Community Edition SearchGuard pluginu.

Detailní bezpečností konfigurace SearchGuard plugin jsou umístěny v sadě .yml files v příslušné složce daného pluginu ~/plugins/search-guard-6/sgconfig.

V našem kontextu jde především o:

  • sg_config.yml: hlavní config file nastavující autentizační a autorizační moduly/backendy, definující především jak sg přijmá a verfikuje credentials a permissions. V případě, že bychom uživatele chtěli autentifikovat např. oproti LDAP/AD (komerční funkcionalita), tak bychom nastavovali v tomto configu. V našem případě využijeme interní databáze uživatelů.
  • sg_internal_users.yml: interní databáze uživatelů, hashed passwords a emitovaných backend rolí. Funguje jako “backend” pro autentifikaci.
  • sg_action_groups.yml: formalizované sady oprávnění do skupin typu READ/MANAGE/DELETE apod.
  • sg_roles.yml: definice konkrétních searchguard rolí a jim přiřazených specifických oprávnění.
  • sg_roles_mapping.yml: mapování backend rolí a userů k searchguard rolím.

Nejzajímavější pro naší demo aplikaci jsou informace obsažené sg_internal_users.yml.

cat /usr/share/elasticsearch/plugins/search-guard-6/sgconfig/sg_internal_users.yml

… který vypadá následovně (výňatek):

# This is the internal user database
# The hash value is a bcrypt hash and can be generated with plugin/tools/hash.sh
#password is: admin
admin:
readonly: true
hash: $2a$12$VcCDgh2NDk07JGN0rjGbM.Ad41qVR/YFJcgHp0UGns5JDymv..TOG
roles:
— admin
attributes:
#no dots allowed in attribute names
attribute1: value1
attribute2: value2
attribute3: value3
#password is: readall
readall:
hash: $2a$12$ae4ycwzwvLtZxwZ82RmiEunBbIPiAmGZduBAjKN0TXdwQFtCwARz2
#password is: readall
roles:
— readall

Ve výňatku konfigurace vidíme dva uživatele admin a readall a jim přiřazené role (tyto dva uživatele později použijeme při testu). Poznámka: pro snadnější použití demo verze jsou uvedeny v komentáři i hesla — není třeba zdůrazňovat, že v případě jakéhokoliv reálnějšího použití se toto v configu nesmí objevit! Nicméně (špatný vtip): nezapomeňte, že i největší sociální síť světa se dá provozovat s volně přístupnými hesly v plaintext.

Spuštění zabezpečení clusteru skrze SearchGuard

K iniciaci zabezpečení pomocí nainstalovaného a nakonfigurovaného SearchGuard pluginu (pokud není nakonfigurována auto-inicializace nebo došlo k nějakým změnám v nastavení searchguard) stačí spustit již dříve zmiňovaný sgadmin_demo.sh script z home adresáře elasticsearch.

./sgadmin_demo.sh

Na health-check endpointu searchguard https://localhost:9200/_searchguard/health lze následně jednoduše potvrdit, že cluster skutečně běží a SearchGuard plugin je aktivní.

Pokud ještě letmo koukneme na daný sgadmin_demo.sh, tak zjistíme že neobsahuje nic zásadně sofistikovaného.

cat sgadmin_demo.sh

… defacto především s demo admin certifikátem (kirk.pem) spouští další script a to sgadmin.sh.

#!/bin/bash
“/usr/share/elasticsearch/plugins/search-guard-6/tools/sgadmin.sh” -cd “/usr/share/elasticsearch/plugins/search-guard-6/sgconfig” -icl -key “/usr/share/elasticsearch/config/kirk-key.pem” -cert “/usr/share/elasticsearch/config/kirk.pem” -cacert “/usr/share/elasticsearch/config/root-ca.pem” -nhnv

Zmíněný sgadmin.sh script je podstatně zásadnější, neboť se jedná o primární script, kterým se veškerá SearchGuard konfigurace (včetně userů, rolí, permissions atd.) indexuje do dříve vytvořeného SearchGuard indexu v Elasticsearch clusteru, ze kterého je pak načítána/využívána v exekučním prostředí. To umožňuje hot config reloading a eliminuje nutnost umísťovat konfigurační files na kterýkoli z nodů v provozovaném clusteru. Z toho vyplývá i potřeba spustit sgadmin.sh minimálně jednou (a následně s každou případnou změnou), abychom mohli využívat kýžených/nastavený autentizačních a autorizačních metod.

Výpis daného skriptu potvrzuje plnění sg indexů z dříve představených konfiguračních files.

Search Guard Admin v6
Will connect to localhost:9300 … done
Elasticsearch Version: 6.6.2
Search Guard Version: 6.6.2–24.2
Connected as CN=kirk,OU=client,O=client,L=test,C=de
Contacting elasticsearch cluster ‘elasticsearch’ and wait for YELLOW clusterstate …
Clustername: docker-cluster
Clusterstate: GREEN
Number of nodes: 1
Number of data nodes: 1
searchguard index does not exists, attempt to create it … done (0-all replicas)
Populate config from /usr/share/elasticsearch/plugins/search-guard-6/sgconfig/
Will update ‘sg/config’ with /usr/share/elasticsearch/plugins/search-guard-6/sgconfig/sg_config.yml
SUCC: Configuration for ‘config’ created or updated
Will update ‘sg/roles’ with /usr/share/elasticsearch/plugins/search-guard-6/sgconfig/sg_roles.yml
SUCC: Configuration for ‘roles’ created or updated
Will update ‘sg/rolesmapping’ with /usr/share/elasticsearch/plugins/search-guard-6/sgconfig/sg_roles_mapping.yml
SUCC: Configuration for ‘rolesmapping’ created or updated
Will update ‘sg/internalusers’ with /usr/share/elasticsearch/plugins/search-guard-6/sgconfig/sg_internal_users.yml
SUCC: Configuration for ‘internalusers’ created or updated
Will update ‘sg/actiongroups’ with /usr/share/elasticsearch/plugins/search-guard-6/sgconfig/sg_action_groups.yml
SUCC: Configuration for ‘actiongroups’ created or updated
Done with success

TEST TIME (indexace dokumentů)

Nyní přichází nejzajímavější část a to zkouška provolání našeho clusteru se zapnutým zabezpečením.

Yaaay!

Cluster v testu provoláme celkem třikrát — poprvé zcela bez autentifikačních headers (tak jak je v základu možno s Elasticsearch pracovat, pokud nemáme zapnutou žádnou formu zabezpečení), podruhé se pokusíme zaindexovat dokument s uživatelem, který je oprávněn (na základě své role) pouze data číst, a potřetí s uživatelem, který má plná práva. Protože máme aktivované i TLS pro REST layer, tak (v rámci omezené demo konfigurace) označíme odkud má curl brát vygenerováný veřejný CA certifikát.

Request (bez autentifikačních headers):

curl -XPUT --cacert certificates/root-ca.pem \
https://localhost:9200/testsecurity/_doc/1 \
-H ‘Content-Type: application/json’ \
-H ‘cache-control: no-cache’ \
-d ‘{
“user” : “stanislav”,
“post_date” : “2019–03–24”,
“message” : “Nesnesitelná lehkost vyhledávání (ve vašich datech) — díl 1: bezpečnost”
}’

Response:

Unauthorized

Request (s autentifikací readall uživatele) — credentials encoded v Base64:

curl -XPUT --cacert certificates/root-ca.pem \
‘https://localhost:9200/testsecurity/_doc/1?pretty=' \
-H ‘Authorization: Basic cmVhZGFsbDpyZWFkYWxs’ \
-H ‘Content-Type: application/json’ \
-H ‘cache-control: no-cache’ \
-d ‘{
“user” : “stanislav”,
“post_date” : “2019–03–24”,
“message” : “Nesnesitelná lehkost vyhledávání (ve vašich datech) — díl 1: bezpečnost”
}’

Response:

{
“error” : {
“root_cause” : [
{
“type” : “security_exception”,
“reason” : “no permissions for [indices:data/write/index] and User [name=readall, roles=[readall], requestedTenant=null]”
}
],
“type” : “security_exception”,
“reason” : “no permissions for [indices:data/write/index] and User [name=readall, roles=[readall], requestedTenant=null]”
},
“status” : 403
}

Request (s autentifikací admin uživatele):

curl -XPUT --cacert certificates/root-ca.pem \
https://localhost:9200/testsecurity/_doc/1?pretty \
-H ‘Authorization: Basic YWRtaW46YWRtaW4=’ \
-H ‘Content-Type: application/json’ \
-H ‘cache-control: no-cache’ \
-d ‘{
“user” : “stanislav”,
“post_date” : “2019–03–24”,
“message” : “Nesnesitelná lehkost vyhledávání (ve vašich datech) — díl 1: bezpečnost”
}’

Response:

{
“_index” : “testsecurity”,
“_type” : “_doc”,
“_id” : “1”,
“_version” : 1,
“result” : “created”,
“_shards” : {
“total” : 2,
“successful” : 1,
“failed” : 0
},
“_seq_no” : 1,
“_primary_term” : 1
}

V poslední odpovědi vidíme úspěšně zaindexovaný dokumentu v našem testovacím indexu testsecurity.

Deaktivace plugin

Plugin se dá jednoduše deaktivovat jedním parametrem v elasticsearch.yml (upravit můžeme například ve vim editoru) a kompletním restartem clusteru (kvůli transport layer TLS který bude tímto také vypnut).

searchguard.disabled: true

V našem případě můžeme restartovat daný container.

docker restart 432a8ea6ba89

Pokud následně zkusíme zaindexovat dokument bez jakékoli autentifikace, tak vše projde bez jakýchkoliv problémů.

curl -X PUT http://localhost:9200/testsecurity/_doc/1 \
-H ‘Content-Type: application/json’ \
-H ‘cache-control: no-cache’ \
-d ‘{
“user” : “stanislav”,
“post_date” : “2019–03–24”,
“message” : “Nesnesitelná lehkost vyhledávání (ve vašich datech) — díl 1: bezpečnost”
}’

Alternativa 2: Open Distro for Elasticsearch

AWS Open Source Blog

Druhá alternativa, kterou si dnes představíme, je poměrně velmi čerstvá záležitost z března letošního roku z dílny divize AWS relativně známé :) společnosti Amazon a to Open Distro for Elasticsearch. Jak už název naznačuje, tak koncepčně jde o zcela odlišnou záležitost než “pouze” security plugin do Elastic řešení, jedná se totiž o celou novou distribuci samotného Elasticsearch (spolu se sadou doplňových funkcí). Toto je možné díky právě zmíněné otevřenosti kódu Elasticsearch a vázaných software knihoven a jedná se o určitý “step-up” k již delší dobu nabízené AWS Elasticsearch službě. Reakce na tento krok (který se Amazon vysvětloval v několika zprávách a blog posts) na sebe pochopitelně nenechala dlouho čekat. Z hlediska principů open-source komunity a rozvoje software samotného budeme doufat, že Amazon alespoň dostojí svému tvrzení, že: This is not a fork; we will continue to send our contributions and patches upstream to advance these projects.

Distribuce je doplněna o řadu funkcí například Alerting, SQL queries, Performance Analyzer a v neposlední řadě Security. Právě díky přítomnosti bezpečnostních funkcí dává smysl se touto alternativou v tomto článku zabývat. Spoiler alert: pokud jste pozorně četli první část článku, tak vám spousta aspektů daného řešení (rozuměj téměř všechny snad kromě instalace) začnou být velmi velmi povědomé.

Využijeme opět docker prostředí a image, který Amazon vypublikoval.

Spuštění image:

docker run -p 9200:9200 -p 9600:9600 -e “discovery.type=single-node” amazon/opendistro-for-elasticsearch:0.7.0

Opět se rovnou připojíme k danému containeru:

docker exec -it f61520fefc92 /bin/bash

A pokud pak vylistujeme příslušný elasticsearch adresář:

[root@f61520fefc92 elasticsearch]# ls

tak uvidíme jeden povědomý script file…

LICENSE.txt NOTICE.txt README.textile bin config data lib logs modules plugins securityadmin_demo.sh

Script securityadmin_demo.sh již dobře známe z představení pluginu SearchGuard. Zkusíme se tedy podívat do adresáře plugins.

opendistro_alerting opendistro_performance_analyzer opendistro_security opendistro_sql

Zde vidíme dříve zmíněné moduly, které byly doplněny do Open Distro for Elasticsearch a jsou pojmenovány prefixem opendistro_. Když se však podíváme do adresáře security plugin a jeho konfigurace

[root@f61520fefc92 plugins]# ls opendistro_security/securityconfig/

… tak vidíme známou sadu config files (akorát bez sg_ prefixu)

action_groups.yml config.yml elasticsearch.yml.example internal_users.yml roles.yml roles_mapping.yml

Zmínku, že bylo v Open Distro for Elasticsearch využito kódové báze SearchGuard je možné nalézt pouze v licenčním NOTICE dokumentu, kde je uveden copyright pro výrobce daného plugin Copyright 2015–2017 floragunn GmbH. Vývojářská firma floragunn potvrdila využítí a jeho legitimitu v krátkém vyjádření na svém community fóru.

Závěr pro nás? Veškerá diskutovaná nastavení SearchGuard jsou plně ekvivalentní i pro nastavení Open Distro for Elasticsearch.

Závěr

Jak bylo ilustrováno, tak SearchGuard je efektivním a ozkoušeným standardem v oblasti zabezpečení Elasticsearch clusterů, což částečně “dokazuje” i využití jeho kódu Amazonem v Open Distro for Elasticsearch. Tento plugin nabízí poměrně široké možnosti nastavení a zabezpečení a to i ve volně dostupné Community Edition. Osobně by v tuto chvíli bylo doporučení (z hlediska funkcionalit základního zabezpečení představených výše) zatím používat spíše distribuce přímo od Elastic a floragunn vzhledem k přímému přístupu k aktualizacím a široké aktivní komunitě. Uvidíme až časem jaká bude kontribuce Amazonu v dané oblasti.

--

--