I will be showing how to setup OpenDistro Elasticsearch (ES) with TLS for Windows.

References:

  • https://opendistro.github.io/for-elasticsearch-docs/
  • https://aws.amazon.com/blogs/opensource/add-ssl-certificates-open-distro-for-elasticsearch/

Pre-requisites

  1. Docker Desktop
  2. WSL2
  3. Git Bash

Pull Docker Images

docker pull amazon/opendistro-for-elasticsearch:latest
docker pull amazon/opendistro-for-elasticsearch-kibana:latest

Docker Compose (default certs)

We will be using docker-compose.yml to run ES. Below is a sample.

version: '3'
services:
  odfe-node1:
    image: amazon/opendistro-for-elasticsearch:1.12.0
    container_name: odfe-node1
    environment:
      - cluster.name=odfe-cluster
      - node.name=odfe-node1
      - discovery.seed_hosts=odfe-node1
      - cluster.initial_master_nodes=odfe-node1
      - bootstrap.memory_lock=true # along with the memlock settings below, disables swapping
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m" # minimum and maximum Java heap size, recommend setting both to 50% of system RAM
    ulimits:
      memlock:
        soft: -1
        hard: -1
      nofile:
        soft: 262144 # maximum number of open files for the Elasticsearch user, set to at least 65536 on modern systems
        hard: 262144
    volumes:
      - odfe-data1:/usr/share/elasticsearch/data
    ports:
      - 9200:9200
      - 9600:9600 # required for Performance Analyzer
    networks:
      - odfe-net
  kibana:
    image: amazon/opendistro-for-elasticsearch-kibana:1.12.0
    container_name: odfe-kibana
    ports:
      - 5601:5601
    expose:
      - "5601"
    environment:
      ELASTICSEARCH_URL: https://odfe-node1:9200
      ELASTICSEARCH_HOSTS: https://odfe-node1:9200
    networks:
      - odfe-net

volumes:
  odfe-data1:


networks:
  odfe-net:

Potential error you might face:

Max virtual memory areas vm.max_map_count [65530] is too low, increase to at least [262144]

In this case, you need to increase the max_map_count for WSL2. Open powershell and run:

wsl -d docker-desktop
echo 262144 >> /proc/sys/vm/max_map_count

Checking that ES is up

Navigate to localhost:9200. You should be able to see the following message.

{
  "name" : "odfe-node1",
  "cluster_name" : "odfe-cluster",
  "cluster_uuid" : "fyO3IMS3SoiWqO8PRC6x4A",
  "version" : {
    "number" : "7.10.0",
    "build_flavor" : "oss",
    "build_type" : "tar",
    "build_hash" : "51e9d6f22758d0374a0f3f5c6e8f3a7997850f96",
    "build_date" : "2020-11-09T21:30:33.964949Z",
    "build_snapshot" : false,
    "lucene_version" : "8.7.0",
    "minimum_wire_compatibility_version" : "6.8.0",
    "minimum_index_compatibility_version" : "6.0.0-beta1"
  },
  "tagline" : "You Know, for Search"
}

Generating certificates

The previous steps works off the demo certificates. Next, I will show how to generate your own self-signed CA and node certificates. Welcome to OpenSSL. Windows Powershell comes with OpenSSL.

Step 1: Generate a private key (root-ca-key.pem) using genrsa command. This file should be kept private.

openssl genrsa -out root-ca-key.pem 2048

Step 2: Generate root certificate (root-ca.pem) Use the private key to generate a self-signed certification for the root CA:

openssl req -new -x509 -sha256 -key root-ca-key.pem -out root-ca.pem -days 3650

Follow the prompts to specify details (CN, OU, O, L, ST, C) for your organization. These details form the distinguished name (DN) of your CA.

If you encounter error in finding openssl.conf file, you need to update your env variable to point to openssl.conf. By deafult, when you install Git, it comes with OpenSSL. Update your env variable OPENSSL_CONFIG to point to your config file.

set OPENSSL_CONFIG=C:\Program Files\Git\usr\ssl\openssl.cnf
echo %OPENSSL_CONF%

Step 3: Generate admin certificate (admin-key.pem) Create a new key, convert key to PKCS#8 format for use in Java using PKCS#12-compatible algorithm (3DES)

openssl genrsa -out admin-key-temp.pem 2048
openssl pkcs8 -inform PEM -outform PEM -in admin-key-temp.pem -topk8 -nocrypt -v1 PBE-SHA1-3DES -out admin-key.pem

Next, create a certificate signing request (CSR) to act as an application to a CA (one we created earlier) for signed certificate.

openssl req -new -key admin-key.pem -out admin.csr

Finally, generate the certificate.

openssl x509 -req -in admin.csr -CA root-ca.pem -CAkey root-ca-key.pem -CAcreateserial -sha256 -out admin.pem -days 3650

OpenDistro provided a sample script for all certificates we need.

# Root CA
openssl genrsa -out root-ca-key.pem 2048
openssl req -new -x509 -sha256 -key root-ca-key.pem -out root-ca.pem -days 30
# Admin cert
openssl genrsa -out admin-key-temp.pem 2048
openssl pkcs8 -inform PEM -outform PEM -in admin-key-temp.pem -topk8 -nocrypt -v1 PBE-SHA1-3DES -out admin-key.pem
openssl req -new -key admin-key.pem -out admin.csr
openssl x509 -req -in admin.csr -CA root-ca.pem -CAkey root-ca-key.pem -CAcreateserial -sha256 -out admin.pem -days 30
# Node cert
openssl genrsa -out node-key-temp.pem 2048
openssl pkcs8 -inform PEM -outform PEM -in node-key-temp.pem -topk8 -nocrypt -v1 PBE-SHA1-3DES -out node-key.pem
openssl req -new -key node-key.pem -out node.csr
openssl x509 -req -in node.csr -CA root-ca.pem -CAkey root-ca-key.pem -CAcreateserial -sha256 -out node.pem -days 30
#Client cert
openssl genrsa -out client-key-temp.pem 2048
openssl pkcs8 -inform PEM -outform PEM -in client-key-temp.pem -topk8 -nocrypt -v1 PBE-SHA1-3DES -out client-key.pem
openssl req -new -key client-key.pem -out client.csr
openssl x509 -req -in client.csr -CA root-ca.pem -CAkey root-ca-key.pem -CAcreateserial -sha256 -out client.pem -days 30
# Cleanup
rm admin-key-temp.pem
rm admin.csr
rm node-key-temp.pem
rm node.csr
rm client-key-temp.pem
rm client.csr

To get the DN of your certificates, run the following:

openssl x509 -subject -nameopt RFC2253 -noout -in node.pem

Only the following certificates are necessary:

  • root-ca.pem
  • admin.pem
  • admin-key.pem
  • node-cert.pem (Optional)
  • node-key.pem (Optional)

Docker Compose with own certs

We need to update the environment variables and volumes to include the custom elasticsearch.yml and directories of all certificates.

version: '3'
services:
  odfe-node1:
    image: amazon/opendistro-for-elasticsearch:1.12.0
    container_name: odfe-node1
    environment:
      - cluster.name=odfe-cluster
      - node.name=odfe-node1
      - discovery.seed_hosts=odfe-node1
      - cluster.initial_master_nodes=odfe-node1
      - bootstrap.memory_lock=true # along with the memlock settings below, disables swapping
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m" # minimum and maximum Java heap size, recommend setting both to 50% of system RAM
      - DISABLE_INSTALL_DEMO_CONFIG=true
      - network.host=0.0.0.0 # required if not using the demo security configuration
    ulimits:
      memlock:
        soft: -1
        hard: -1
      nofile:
        soft: 262144 # maximum number of open files for the Elasticsearch user, set to at least 65536 on modern systems
        hard: 262144
    volumes:
      - odfe-data1:/usr/share/elasticsearch/data
      - ./root-ca.pem:/usr/share/elasticsearch/config/root-ca.pem
      - ./node.pem:/usr/share/elasticsearch/config/node.pem
      - ./node-key.pem:/usr/share/elasticsearch/config/node-key.pem
      - ./admin.pem:/usr/share/elasticsearch/config/admin.pem
      - ./admin-key.pem:/usr/share/elasticsearch/config/admin-key.pem
      - ./custom-elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml
    ports:
      - 9200:9200
      - 9600:9600 # required for Performance Analyzer
    networks:
      - odfe-net
  kibana:
    image: amazon/opendistro-for-elasticsearch-kibana:1.12.0
    container_name: odfe-kibana
    ports:
      - 5601:5601
    expose:
      - "5601"
    environment:
      ELASTICSEARCH_URL: https://odfe-node1:9200
      ELASTICSEARCH_HOSTS: https://odfe-node1:9200
    networks:
      - odfe-net

volumes:
  odfe-data1:


networks:
  odfe-net:

Our new elasticsearch.yml should also be updated to include references to our certificates.

opendistro_security.ssl.transport.pemcert_filepath: node.pem
opendistro_security.ssl.transport.pemkey_filepath: node-key.pem
opendistro_security.ssl.transport.pemtrustedcas_filepath: root-ca.pem
opendistro_security.ssl.transport.enforce_hostname_verification: false
opendistro_security.ssl.http.enabled: true
opendistro_security.ssl.http.pemcert_filepath: node.pem
opendistro_security.ssl.http.pemkey_filepath: node-key.pem
opendistro_security.ssl.http.pemtrustedcas_filepath: root-ca.pem
opendistro_security.allow_default_init_securityindex: true
opendistro_security.authcz.admin_dn:
  - CN=A,OU=UNIT,O=ORG,L=TORONTO,ST=ONTARIO,C=CA
opendistro_security.nodes_dn:
  - 'CN=N,OU=UNIT,O=ORG,L=TORONTO,ST=ONTARIO,C=CA'
opendistro_security.audit.type: internal_elasticsearch
opendistro_security.enable_snapshot_restore_privilege: true
opendistro_security.check_snapshot_restore_write_privileges: true
opendistro_security.restapi.roles_enabled: ["all_access", "security_rest_api_access"]
cluster.routing.allocation.disk.threshold_enabled: false
opendistro_security.audit.config.disabled_rest_categories: NONE
opendistro_security.audit.config.disabled_transport_categories: NONE

Leave a comment