Elasticsearch security for free.
ARMOR is a free and open source plugin for Elasticsearch which provides security features.
Basically ARMOR consists of an authentication, authorization, SSL/TLS, XFF, HTTP session and audit log module and access control. All of them without the exception of access control are more or less self-explanatory. But access control, the heart of ARMOR, needs some more attention.
ARMOR has the concept of routing a request through a chain of filters which can modify or block the request/response. There are currently 3 types of filters:
You must verify the integrity of the downloaded files. We provide PGP signatures for every release file. This signature should be matched against the KEYS file. We also provide MD5 and SHA-1 checksums for every release file. After you download the file, you should calculate a checksum for your download, and make sure it is the same as ours. Here and here are some tips how to verify the pgp signatures.
It's recommended to setup the access control rules (ACL rules) before installing the plugin to simplify the installation process. If you install the plugin first you have to do extra effort cause then your're firstly locked-out of elasticsearch.
Why not install a ACL rules file which grants all access for a user with role admin?
curl -XPUT 'http://localhost:9200/armor/ac/ac' -d '{
"acl": [
{
"__Comment__": "By default no filters are executed and no filters a by-passed. In such a case an exception is thrown and access will be denied.",
"filters_bypass": [],
"filters_execute": []
},
{
"__Comment__": "For role *admin* all filters are bypassed (so none will be executed). This means unrestricted access.",
"roles": [
"admin"
],
"filters_bypass": ["*"],
"filters_execute": []
}
]
}'
Install it like any other Elasticsearch plugin:
(On Centos, you can find the bin/plugin
at /usr/share/elasticsearch
)
# ES 2.4.1
$ bin/plugin -i com.petalmd/armor/2.4.1
Prerequisites:
Build it yourself:
`git clone https://github.com/petaldevelopment/armor.git
cd armor
mvn package -DskipTests
Configured in elasticsearch's logging.yml. Nothing special. To enable debug just add
logger.com.petaldevelopment: DEBUG
Two kind of keys are used by ARMOR:
The security rules for each module are stored in an special index armor
and with a type and id of ac
.
See below (or look at chapter Pre-Installation) for more details.
See armor_config_template.yml. Just copy the content over to elasticsearch.yml and modify the settings so fit your needs. A very basic example you can find here
All the configuration up to know makes only sense if we can limit the usage of Elasticsearch for the authenticated user. There are four types of security filters (by now) which also can be used together.
You have to configure at least on filter.
If you use either transport layer SSL or DLS or FLS you have to install it on every node. Otherwise install it on every client node which is exposed to be the entry point into the cluster and on every node which exposes the HTTP REST API. Please note that the armor.config_index_name
must be the same for all nodes in within a cluster.
Auditlog is stored in Elasticsearch within the armor index (with type audit)
$ curl -XGET 'http://localhost:9200/armor/audit/_search?pretty=true'
Now lets define for which user on which index which filter have to be applied.
{
"acl": [
{
"__Comment__": "By default no filters are executed and no filters a by-passed. In such a case a exception is throws an access will be denied.",
"filters_bypass": [],
"filters_execute": []
},
{
"__Comment__": "For admin role all filters are bypassed (so none will be executed) for all indices. This means unrestricted access at all for this role.",
"roles": ["admin"],
"filters_bypass": ["*"],
"filters_execute": []
},
{
"__Comment__": "For every authenticated user who access the index 'public' for this access all non dls and all non fls filters are executed.",
"indices": ["public"],
"filters_bypass": [
"dlsfilter.*",
"dlsfilter.*"
],
"filters_execute": ["*"]
},
{
"__Comment__": "For marketing role all filters are bypassed (so none will be executed) for index 'marketing'. This means unrestricted access to this index for this role.",
"roles": ["marketing"],
"indices": ["marketing"],
"filters_bypass": ["*"],
"filters_execute": []
},
{
"__Comment__": "For finance role all filters are bypassed (so none will be executed) for index 'finance'. This means unrestricted access to this index for this role.",
"roles": ["finance"],
"indices": ["financ*"],
"filters_bypass": ["*"],
"filters_execute": []
},
{
"__Comment__": "For marketing role the filters 'flsfilter.filter_sensitive_finance' and 'actionrequestfilter.readonly' are executed (but no other filters) for index 'finance'",
"roles": ["marketing"],
"indices": ["financ*"],
"filters_bypass": [],
"filters_execute": [
"flsfilter.filter_sensitive_fina*",
"actionrequestfilter.readonly"
]
},
{
"__Comment__": "For roles 'ceo' 'marketing' 'finance' all filters are bypassed (so none will be executed) for alias 'planning'. This means unrestricted access to this alias for this roles.",
"roles": [
"ce*o",
"marke*ing",
"*nanc*"
],
"aliases": ["planning"],
"filters_bypass": ["*"],
"filters_execute": []
},
{
"__Comment__": "For finance role the filters 'dlsfilter.filter_sensite_from_ceodata' and 'actionrequestfilter.readonly' are executed (but no other filters) for index 'ceodata'",
"roles": ["finance"],
"indices": ["ceodat*"],
"filters_bypass": [],
"filters_execute": [
"dlsfilter.filter_sensitive_from_ceodata",
"actionrequestfilter.readonly"
]
},
{
"__Comment__": "For role 'ceo' all filters are bypassed (so none will be executed) for index 'ceodata'. This means unrestricted access to this index for this role.",
"roles": ["ce*o"],
"indices": ["ceodata"],
"filters_bypass": ["*"],
"filters_execute": []
}
]
}
For every rule that match all execute and bypass filters will be concatenated, and bypass is winning over execute. For example if an user which has the roles marketing and finance and want to access index marketing the final result looks like
filters_bypass=["*"],
filters_execute=["flsfilter.filter_sensitive_fina*","actionrequestfilter.readonly"]
which then will be resolved to filters_bypass= ["*"]
(execute NO filter at all).
Because bypass is winning.
If a user which has the marketing role and want to access index finance the final result looks like
filters_bypass: []
filters_execute: ["flsfilter.filter_sensitive_fina*", "actionrequestfilter.readonly"]
which then will be resolved to
filters_execute: ["flsfilter.filter_sensitive_fina*", "actionrequestfilter.readonly"]
(execute these two filters, no others).
For an admin accessing index public it looks like
filters_bypass: ["*", "dls.*", "fls.*"],
filters_execute: ["*"]
which then will be resolved to filters_bypass: ["*"]
(execute NO filter at all).
Because bypass is winning.
If filters resolve to
filters_bypass: []
filters_execute: []
then an security exception will be thrown.
For the sake of completeness a rule definition can look like:
{
// who is the requestor
"hosts":[
"10.*.1.*",
"host-*.company.org"
],
"users":["*"],
"roles":["*"],
// on what resources do the requestor operate
"indices":["public"],
"aliases":["..."],
// which filters have to be applied or can be bypassed for this
// requestor on this resource
"filters_bypass": ["*"],
"filters_execute": []
}
Everywhere a simple wildcard (*) can be used.
To make the rule apply all present attributes (users, roles, hosts, indices, aliases) must match. An attribute which is missing or is empty does always match. An attribute only containing the wildcard sign (*) does also match always.
If you access more than one index (e.g. search in multiple indices) only rules will match when they list all the indices (or "*”). So for a multi index search on the indices marketing and finance a rules have to look like:
{
"roles": ["..."],
"indices": [
"finance",
"marketing"
],
"filters_bypass": ["..."],
"filters_execute": ["..."]
}
You can circumvent this by using aliases.
See the documentation for Kibana 4.2
TODO
Contributions, questions, and comments are all welcomed and encouraged!
This project derives from Search-guard 1.6
Copyright 2015 PetalMD
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.