Using JS Auth with found cluster

2015-05-19
3 min read
Featured Image

Using Found by elastic cluster helps a lot to have a ready to use and managed elasticsearch cluster.

I started my own cluster yesterday to power brownbaglunch.fr website (work in progress) and it was ready to use after some clicks!

It’s a kind of magic!

But I ran into an issue when you secure it and use the elasticsearch javascript client.

Creating your cluster

Found Console

Found Console

Adding ACL

By default, your cluster is opened but you can fix that by opening “Access Control” menu. Found proposes a default configuration which generates two users and restrict some access.

# Deny everyone by default, as authentication is required.
# Deny is the default also if no "default" is specified,
# so it's only necessary to specify it if you want the
# default to be "allow".
default: deny

auth:
  users:
    searchonly: searchonlypassword
    readwrite: readwritepassword

rules:
  - paths:
      # Match all search requests.
      - '/_search|/([^_/]+/_search)|/[^_/]+/[^_/]+/_search'
    conditions:
      - basic_auth:
          users: [searchonly]
    action: allow

  # Also, allow any GET-request.
  - paths: ['.*']
    conditions:
      - basic_auth:
          users:
            - searchonly
      - method:
          verbs: [GET]
    action: allow

  # Allow everything for the readwrite-user
  - paths: ['.*']
    conditions:
      - basic_auth:
          users:
            - readwrite
# Uncomment the following if you want to require SSL.
#      - ssl:
#          require: true
    action: allow

Create your javascript application

<!DOCTYPE html>
<html>
  <head>
    <script src="https://cdn.rawgit.com/elastic/bower-elasticsearch-js/12ec0b8ee6d776e077b160e6dd6fc2e1b5818a86/elasticsearch.min.js"></script>
  </head>
  <body>
    <script>
      var login = "readwrite";
      var password = "readwritepassword";
      var hostname = "youclusteraddress.foundcluster.com";
      
      var client = new elasticsearch.Client({
        hosts: [
          {
            host: hostname,
            auth: login + ':' + password
          } 
        ]
      });
      
      client.cluster.health().then(done, done);
      
      function done(resp) {
        console.log(resp);
      }
    </script>
  </body>
</html>

If you run it, you will get something like:

elasticsearch.min.js:18 OPTIONS http://youclusteraddress.foundcluster.com:9200/_cluster/health 401 (Unauthorized)26.d.request @ elasticsearch.min.js:18c @ elasticsearch.min.js:1842.j.applyArgs @ elasticsearch.min.js:18k @ elasticsearch.min.js:11(anonymous function) @ elasticsearch.min.js:11
bblfr_elasticsearch.dev/:1 XMLHttpRequest cannot load http://youclusteraddress.foundcluster.com:9200/_cluster/health. Invalid HTTP status code 401
elasticsearch.min.js:18 ERROR: 2015-05-19T14:47:01Z
  Error: Request error, retrying -- Request failed to complete.
      at d.29.d.error (http://bblfr_elasticsearch.dev/lib/elasticsearch.min.js:18:15537)
      at d (http://bblfr_elasticsearch.dev/lib/elasticsearch.min.js:18:22917)
      at XMLHttpRequest.26.d.request.d.onreadystatechange (http://bblfr_elasticsearch.dev/lib/elasticsearch.min.js:18:9781)

Modify ACL

The javascript client needs to discuss with found using OPTIONS verb. So you basically need to add:

  - paths:
      - '.*'
    conditions:
      - method:
          verbs: [OPTIONS]
    action: allow

Running the same code will now work as expected!

{
  cluster_name: "youclusteraddress", 
  status: "green", 
  timed_out: false, 
  number_of_nodes: 1, 
  number_of_data_nodes: 1
  // ...
}

Using ACL for aliases

Note that for the project, I created one index named bbl_1 and one alias on top of it bbl. So I opened read access to anonymous users on this alias and add a secured one when it comes to write operations. OPTIONS in that case is applied only to the bbl alias. I came up with this config:

default: deny

auth:
  users:
    readwrite: readwritepassword

rules:
  - paths:
      - '/bbl/.*'
    conditions:
      - method:
          verbs: [OPTIONS]
    action: allow

  - paths:
      - '/bbl/_search'
    conditions:
      - method:
          verbs: [GET, POST]
    action: allow

  - paths: ['/bbl/.*']
    conditions:
      - method:
          verbs: [GET]
    action: allow

  - paths: ['/bbl/.*']
    conditions:
      - method:
          verbs: [PUT, DELETE]
      - basic_auth:
          users: [readwrite]
    action: allow
Share this article on
Avatar

David Pilato

20+ years of experience, mostly in Java. Living in Cergy, France.