You Know, for Security: Shield Goes GA
Today we are pleased to announce Shield 1.0 GA — the first release of our security plugin for Elasticsearch. While we announced the coming of Shield back in November, today is when the security functionality for Elasticsearch completes the transition that started with a general wish, moved to concrete ideas and execution plan, and is now a reality.
While it has always been possible to secure Elasticsearch clusters by deploying them within well-secured environments, we continuously received requests from customers and users to have a more integrated solution.
We started exploring what such a product would look like, spending a lot of time making sure we truly understood the security needs of our customers and users. The result is Shield — a commercial Elasticsearch plugin that enables securing Elasticsearch clusters. And we are pleased to include it as part of all our Development, Gold, and Platinum subscriptions at no additional cost.
This first release is focused on infrastructure and foundational functionality. We went to great lengths preparing Elasticsearch itself for security, not just on its extensibility side, but also carefully rethinking how the data flows in it. We’ve built a foundation that not only delivers immediate tangible value when it comes to securing Elasticsearch clusters, but also enables us to extend its functionality incrementally and rapidly over time.
Shield 1.0 focuses on the following five aspects:
- Encrypted Communication & Node Authentication
- IP Filtering
- Audit Trail
Security at large is all about identity (e.g., Who called this API?, What service connected to our system?, etc.). At any given time in the lifetime of a service, one could associate a subject (a.k.a User) with any of the currently running sub-/processes. Having this association mandates that the users will be identified just before any of the sub-/processes start running. The process of identifying the users is called Authentication and it is triggered for every API call in Elasticsearch.
There are many different authentication methods, each requires the user to provide different types of credentials by which they’ll be identified (a.k.a. Authentication Token). In Shield 1.0 we kept it simple and require the authentication token to be in the form of a username/password pair. (That said, Shield’s authentication infrastructure is built to easily extend this and support other authentication tokens in the future.)
Receiving the user credentials is not enough, next we need to verify and authenticate them. In Shield, this is the responsibility of realms. A realm can be seen as an authentication provider/service that can either resolve and verify the relevant user, or reject the authentication token due to incorrect credentials or simply because the user is unknown. Shield’s authentication mechanism enables you to configure multiple realms and chain them together where one realm can serve as a fallback to another. In Shield 1.0 we support three realm types:
- esusers – An internal file-based realm managed by Elasticsearch that enables the definition of users in files (much like htpasswd files in Apache Server). This realm has no external dependencies and is enabled by default when Shield is installed. This realm can be used in smaller deployments and for multitenant Elasticsearch clusters, where each application that shares the cluster is a tenant. It can also serve as an “emergency” fallback realm in situations where all users forgot their passwords (everybody locked themselves out of the system).
- LDAP – A realm that authenticates users against an external LDAP server. This realm targets enterprises that already have all their users stored and managed in the organization’s LDAP server(s).
- Active Directory – A specific type of LDAP realm that has a simplified configuration for Active Directory.
The realm can be configured in the elasticsearch.yml configuration file in the following manner:
shield.authc realms: esuser: type: esusers order: 0 ldap: type: ldap order: 1 url: ldaps://url/to/ldap1/server ldap_fallback: type: ldap order: 2 url: ldaps://url/to/ldap2/server
As mentioned above, the realms are consulted one at a time in a chain. The per-realm order setting determines the order in which they will be consulted.
NOTE: Shield comes with a command-line tool to manage the users stored in the esusers files.
Authorization is the process of granting or denying a user access to a protected resource. Modern systems use the role-based access control (a.k.a RBAC) model to determine user permissions. In this model, each user is associated with a set of roles, where each role defines a set of permissions. This enables sophisticated configuration where permissions can be shared across functional groups. For example, we may define the following roles:
- employee – All employees have access to cross department company data (e.g., contacts and directory information)
- sales – All the sales personnel have access to sales data (e.g., pipeline, leads, and accounts)
- finance – All the finance personnel have access to financial data (e.g., budgets, expenses, and purchases)
Having that, Ann from the finance department may have both employee and finance roles, granting her access to company directory and all financial data.
Since the authorization process requires the user to be associated with the incoming request, it’s only natural for this process to execute directly after the authentication phase.
Shield defines two types of protected resources — cluster and indices — which cover and protect all API calls in Elasticsearch. Furthermore, it enables defining the available roles and their associated permissions on both. Once defined, roles may be assigned to users or mapped to LDAP/AD groups. The roles are defined in a dedicated roles.yml configuration file. Here is an example of such configuration:
admin: cluster: all indices: '*' : all monitor: cluster: monitor indices: '*': monitor employee: indices: 'company_directory' : read sales: indices: 'opportunities' : read, write 'accounts' : read, write finance: indices: 'expenses' : read, write 'purchases' : read, write
In the example above, we defined five roles:
- admin – A role for administrators enabling them full access to all cluster-level operations as well as full access to all index-level operations on all indices (* indicates a wildcard matching all indices)
- monitor – A role for system/cluster monitoring purposes. Users of this role are able to have read access to all cluster and index level info APIs, but cannot update any of the settings or read/write data to any of the indices.
- employee – A role that provides read access to all data within the company_directory index. Note that this role doesn’t grant cluster-level access or even write privileges on the data (typically in a company, only a selected group of people will be able to update the company directory, while all employees will just be able to read it)
- sales – A role that provides both read and write privileges over the opportunities and accounts indices
- finance – A role that provides both read and write privileges over the expenses and purchases indices
The definitions above use all, read, and write as “named” privileges, as we often like to refer to them. These are predefined, high-level privileges that group multiple low-level Elasticsearch actions under a single name (e.g., the write privilege groups
index, delete, delete_by_query, bulk and
update operations). While for most cases these high-level named privileges will suffice, we also enable finer-grained access control by explicitly specifying the actions granted for a specific role, as shown in the example below:
hr: indices: 'company_directory' : indices:data/write/index, indices:data/write/update
The authentication realms we’ve discussed above are responsible for resolving the roles associated with each user. With the internal esusers realm, the roles can be assigned to users (and modified) using the provided esusers command-line tool. With LDAP and Active Directory, we enable mapping LDAP/AD groups to Shield roles.
Having both authentication and authorization in place, we can now grant or deny user requests depending on their nature (action/operation types) and the user’s privileges.
While authorization protects the data in Elasticsearch from a functional perspective (granting access to an operation to only permitted users), sending the data unencrypted from the client to the Elasticsearch cluster and between the nodes in the cluster, is dangerous. Third parties “listening” or sniffing the wire can potentially view and modify the data on the fly, or emulate other users and thus compromise the cluster as a whole.
Shield 1.0 enables securing all communication channels in Elasticsearch. Whether these are the channels between the nodes within the cluster, or those that are opened to the clients. This is done with the introduction of SSL/TLS communication.
When SSL is enabled Shield will replace the transport services of Elasticsearch with ones that “talk” SSL/TLS. This can be done separately on the internal node-to-node communication channels and on the HTTP transport that is opened to serve the REST APIs.
SSL/TLS in Shield is based on the standard Java™ support and is based on keystores and truststores. Configuring SSL/TLS involves importing certificates into the keystore of every node. It is possible to use Certificate Authority (CA) signed certificates and their authorization/validation will be done on the trusted CAs. This requires all trust stores to know about all trusted CAs. When new nodes are added to the cluster, all that is required is to sign their certificates with one of the trusted CAs, without the need to update all the keystores/truststores on all other nodes in the cluster.
You can read more about about securing the communication channels and how one can configure SSL/TLS in the Shield in the documentation.
It is also possible (and highly recommended) to configure the SSL transports to perform node authentication, making sure that only the permitted nodes can connect to the cluster. This can be done by setting
true. When set, during the SSL handshake between the node, the connected node will request a client certificate from the connecting node and verify it. If verification fails, the SSL handshake fails and the connection is denied.
SSL Client Authentication
Requiring node authentication on the transport level poses an interesting question. How will Elasticsearch behave when using a Transport Client to connect to the cluster? Since the Transport Client uses the same channels as the other nodes in the cluster, a node cannot typically differentiate between another node trying to connect to it and a client when the connection is established.
One could claim, that the simplest solution here is to simply issue certificates to the Transport Clients as well. While that will solve the authentication challenge, it also introduces another one: (potentially malicious) Transport Clients will be able to emulate nodes in the cluster. And we don’t want that, do we?!
Luckily, there’s a clear path to an elegant solution here: transport profiles. Introduced in Elasticsearch 1.4, transport profiles enables you to define multiple network channels for the transport layer (each binding to different host/port). Shield extends this support by enabling the configuration of different SSL settings per profile. It also enables you to clearly distinguish between a client profile type to a node type. With this in place, one can set up two profiles — one dedicated for the clients (one that doesn’t require SSL client authentication) and another one dedicated for nodes (one that requires SSL client authentication). With this settings, there’s no need to issue certificates for the clients, and Shield will also ensure that requests coming through the client profile will be limited to those that clients are allowed to execute (i.e., public API requests).
While this doesn’t directly fall under the “authentication” category, it is related. Shield ships with its own IP filtering mechanism that enables setting a list of “allowed” and “denied” IPs, from which requests can be made. These filtering rules can be configured on multiple levels – globally on the transport channels, on the transport profile level, and globally on the HTTP channels. The following snippet shows an example of such settings (within the elasticsearch.yml configuration file):
shield: transport.filter: allow: - '127.0.0.1' - '2001:0db8:1234:0000:0000:8a2e:0370:73 deny: - '10.0.0.0/8' - '2001:0db8:1234::/48' - '*.google.com' http.filter: allow: [ '10.0.0.0/8' ] deny: [ '127.0.0.1' ] transport.profiles: client: shield.filter.deny: [ '_all' ]
As you can see above, the IP rules support both IPv4 and IPv6, CIDR masks, hostnames, and wildcards. Also note that while this functionality can typically be added by configuring the IP tables of the hosting OS, keeping it in Shield significantly simplifies these settings and removes yet another moving part in the overall deployment. (See more about IP filtering in the documentation.)
Being an essential part of any secured system, audit trails enable tracking of important events occurring in Elasticsearch. Persisting these events provides evidence for important activities in the Elasticsearch cluster and primarily serves as a diagnostic tool when investigating potentially suspicious/malicious events.
In Shield 1.0.0, audit trails are persisted in audit/access logs that are separate from the standard Elasticsearch logs. They have a well-defined and consistent structure that makes it easy to both read and parse, and emit several types of events. It is also possible to configure the level of the information that is emitted for each event by simply configuring the logging level. Here is a list of the events that may be logged:
- anonymous_access_denied – Logged when requests arrive without a user authentication token attached
- authentication_failed – Logged when shield could not authenticate the user associated with the request
- access_denied – Logged when an authenticated user attempts to execute a forbidden action
- access_granted – Logged when an authenticated user executes an allowed action
- tampered_request – Logged when Shield detects that the arriving request was tampered with
- connection_granted – Logged when a node or a transport client successfully passes the IP filtering rules
- connection_denied – Logged when a node or a transport client connection request is denied due to restricting IP filtering rules.
To learn more about audit trails in Shield, check out the documentation.
So… What’s next?
As mentioned in the introduction, this is just the beginning. There are many features we’d like to add to Shield, and now that we have the solid infrastructure built, the next version of Shield will focus on adding these features. Some of these features include (and not limited to):
- API driven configuration and management
- More extensive/flexible LDAP/Active Directory support
- Additional realm types (kerberos, anonymous, certificates, and more…)
- Session-based authentication
Shield is the second commercial product offered by our company (after Marvel), yet it’s available for everyone to download and evaluate on development environments. You install it just like you install any other plugin in Elasticsearch (see here for detailed instructions). Once installed, you’ll automatically be issued a 30-day trial license with which you can test it. If you need more time, you’re invited to contact us at firstname.lastname@example.org and enquire for an extended trial license.
As with every product we have, your feedback is highly appreciated. If you have any questions regarding Shield’s commercial offering, its functionality, future roadmap, or any other security related topic, please reach out to us.