Encrypting communications in an Elasticsearch Docker Containeredit

Unless you are using a trial license, Elastic Stack security features require SSL/TLS encryption for the transport networking layer.

This section demonstrates an easy path to get started with SSL/TLS for both HTTPS and transport using the Elasticsearch Docker image. The example uses Docker Compose to manage the containers.

For further details, see Encrypting communications and available subscriptions.

Prepare the environmentedit

Install Elasticsearch with Docker.

Inside a new, empty directory, create the following four files:

instances.yml:

instances:
  - name: es01
    dns:
      - es01 
      - localhost
    ip:
      - 127.0.0.1

  - name: es02
    dns:
      - es02
      - localhost
    ip:
      - 127.0.0.1

Allow use of embedded Docker DNS server names.

.env:

CERTS_DIR=/usr/share/elasticsearch/config/certificates 
ELASTIC_PASSWORD=PleaseChangeMe 

The path, inside the Docker image, where certificates are expected to be found.

Initial password for the elastic user.

create-certs.yml:

version: '2.2'

services:
  create_certs:
    container_name: create_certs
    image: docker.elastic.co/elasticsearch/elasticsearch:7.1.1
    command: >
      bash -c '
        if [[ ! -d config/certificates/certs ]]; then
          mkdir config/certificates/certs;
        fi;
        if [[ ! -f /local/certs/bundle.zip ]]; then
          bin/elasticsearch-certgen --silent --in config/certificates/instances.yml --out config/certificates/certs/bundle.zip;
          unzip config/certificates/certs/bundle.zip -d config/certificates/certs; 
        fi;
        chgrp -R 0 config/certificates/certs
      '
    user: $\{UID:-1000\}
    working_dir: /usr/share/elasticsearch
    volumes: ['.:/usr/share/elasticsearch/config/certificates']

The new node certificates and CA certificate+key are placed under the local directory certs.

docker-compose.yml:

version: '2.2'

services:
  es01:
    container_name: es01
    image: docker.elastic.co/elasticsearch/elasticsearch:7.1.1
    environment:
      - node.name=es01
      - discovery.seed_hosts=es02
      - cluster.initial_master_nodes=es01,es02
      - ELASTIC_PASSWORD=$ELASTIC_PASSWORD 
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
      - xpack.license.self_generated.type=trial 
      - xpack.security.enabled=true
      - xpack.security.http.ssl.enabled=true
      - xpack.security.http.ssl.key=$CERTS_DIR/es01/es01.key
      - xpack.security.http.ssl.certificate_authorities=$CERTS_DIR/ca/ca.crt
      - xpack.security.http.ssl.certificate=$CERTS_DIR/es01/es01.crt
      - xpack.security.transport.ssl.enabled=true
      - xpack.security.transport.ssl.verification_mode=certificate 
      - xpack.security.transport.ssl.certificate_authorities=$CERTS_DIR/ca/ca.crt
      - xpack.security.transport.ssl.certificate=$CERTS_DIR/es01/es01.crt
      - xpack.security.transport.ssl.key=$CERTS_DIR/es01/es01.key
    volumes: ['esdata_01:/usr/share/elasticsearch/data', './certs:$CERTS_DIR']
    ports:
      - 9200:9200
    healthcheck:
      test: curl --cacert $CERTS_DIR/ca/ca.crt -s https://localhost:9200 >/dev/null; if [[ $$? == 52 ]]; then echo 0; else echo 1; fi
      interval: 30s
      timeout: 10s
      retries: 5

  es02:
    container_name: es02
    image: docker.elastic.co/elasticsearch/elasticsearch:7.1.1
    environment:
      - node.name=es02
      - discovery.seed_hosts=es01
      - cluster.initial_master_nodes=es01,es02
      - ELASTIC_PASSWORD=$ELASTIC_PASSWORD
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
      - xpack.license.self_generated.type=trial
      - xpack.security.enabled=true
      - xpack.security.http.ssl.enabled=true
      - xpack.security.http.ssl.key=$CERTS_DIR/es02/es02.key
      - xpack.security.http.ssl.certificate_authorities=$CERTS_DIR/ca/ca.crt
      - xpack.security.http.ssl.certificate=$CERTS_DIR/es02/es02.crt
      - xpack.security.transport.ssl.enabled=true
      - xpack.security.transport.ssl.verification_mode=certificate 
      - xpack.security.transport.ssl.certificate_authorities=$CERTS_DIR/ca/ca.crt
      - xpack.security.transport.ssl.certificate=$CERTS_DIR/es02/es02.crt
      - xpack.security.transport.ssl.key=$CERTS_DIR/es02/es02.key
    volumes: ['esdata_02:/usr/share/elasticsearch/data', './certs:$CERTS_DIR']

  wait_until_ready:
    image: docker.elastic.co/elasticsearch/elasticsearch:7.1.1
    command: /usr/bin/true
    depends_on: {"es01": {"condition": "service_healthy"}}

volumes: {"esdata_01": {"driver": "local"}, "esdata_02": {"driver": "local"}}

Bootstrap elastic with the password defined in .env. See The Elastic bootstrap password.

Automatically generate and apply a trial subscription, in order to enable security features.

Disable verification of authenticity for inter-node communication. Allows creating self-signed certificates without having to pin specific internal IP addresses.

Run the exampleedit

  1. Generate the certificates (only needed once):

    docker-compose -f create-certs.yml up
  2. Start two Elasticsearch nodes configured for SSL/TLS:

    docker-compose up -d
  3. Access the Elasticsearch API over SSL/TLS using the bootstrapped password:

    curl --cacert certs/ca/ca.crt -u elastic:PleaseChangeMe https://localhost:9200
  4. The elasticsearch-setup-passwords tool can also be used to generate random passwords for all users:

    Windows users not running PowerShell will need to remove \ and join lines in the snippet below.

    docker exec es01 /bin/bash -c "bin/elasticsearch-setup-passwords \
    auto --batch \
    -Expack.security.http.ssl.certificate=certificates/es01/es01.crt \
    -Expack.security.http.ssl.certificate_authorities=certificates/ca/ca.crt \
    -Expack.security.http.ssl.key=certificates/es01/es01.key \
    --url https://localhost:9200"