Adding HTTPS to Kibana and Elasticsearch

This post will go over adding Kibana to my new ELK stack, enabling https, and talking to my Elasticsearch over https.

While moving ELK to my Docker Swarm, I want to encrypt everything going over the network. This post will go over adding Kibana to my new ELK stack, enabling https, and talking to my Elasticsearch over https.

I already took care of exposing my Elasticsearch over SSL in this post: https://www.frakkingsweet.com/elasticsearch-java-ssl/

Add a Kibana service to the main docker-compose.yml file, here is that section, see below for the full file:

version: '3.7'
services:
  kibana:
    image: docker.elastic.co/kibana/kibana:7.2.0
    ports: 
      - 5601:5601
    networks:
      - ext

Inside of my prod overrides file, docker-compose.prod.yml, I add the Kibana service with the appropriate overrides. I access my Elasticsearch instance through a DNS entry that is a CNAME pointing to my docker cluster. We'll say that entry is elasticsearch.example.com. I created another DNS entry, kibana.example.com, that points to the docker cluster. This will make it easier in the future when I setup a reverse proxy and instead of dealing with ports like https://kibana.example.com:5601 I will be able to access it by hitting https://kibana.example.com. No need to remember the port numbers.

Here is the Kibana services portion of the compose override file. See below for the full docker-compose.prod.yml file. Kibana uses a different format for the environment variables than Elasticsearch. With Kibana everything is upper case and all periods are replaced with a _. Another difference, we don't need to put the secrets in a special location, so that section is nice and simple.

version: '3.7'
services:
  kibana:
    environment:
      - SERVER_NAME=kibana.example.com
      - ELASTICSEARCH_HOSTS=https://elasticsearch.example.com:9200
      - ELASTICSEARCH_SSL_CERTIFICATEAUTHORITIES=/run/secrets/root.pub.pem
      - SERVER_SSL_ENABLED=true
      - SERVER_SSL_CERTIFICATE=/run/secrets/certificate.crt.pem
      - SERVER_SSL_KEY=/run/secrets/certificate.key.pem
      - SERVER_SSL_CERTIFICATEAUTHORITIES=/run/secrets/root.pub.pem
    secrets:
      - root.pub.pem
      - certificate.key.pem
      - certificate.crt.pem

And for the full, complete files.

docker-compose.yml

version: '3.7'
services:
  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:7.2.0
    environment: 
      - "ES_JAVA_OPTS=-Xms7g -Xmx7g"
      - discovery.type=single-node
    ports:
      - 9200:9200
    networks:
      - ext
  kibana:
    image: docker.elastic.co/kibana/kibana:7.2.0
    ports: 
      - 5601:5601
    networks:
      - ext
networks:
  ext:

docker-compose.prod.yml

version: "3.7"
services:
  elasticsearch:
    environment:
      - xpack.security.http.ssl.enabled=true
      - xpack.security.http.ssl.key=/usr/share/elasticsearch/config/secrets/certificate.key.pem
      - xpack.security.http.ssl.certificate=/usr/share/elasticsearch/config/secrets/certificate.crt.pem
      - xpack.security.http.ssl.certificate_authorities=/usr/share/elasticsearch/config/secrets/root.pub.pem
      - xpack.security.transport.ssl.enabled=false
      - xpack.security.transport.ssl.key=/usr/share/elasticsearch/config/secrets/certificate.key.pem
      - xpack.security.transport.ssl.certificate=/usr/share/elasticsearch/config/secrets/certificate.crt.pem
      - xpack.security.transport.ssl.certificate_authorities=/usr/share/elasticsearch/config/secrets/root.pub.pem
    volumes:
      - elasticsearchdata:/usr/share/elasticsearch/data
      - elasticsearchconfig:/usr/share/elasticsearch/config
      - elasticsearchlogs:/usr/share/elasticsearch/logs
    secrets:
      - source: root.pub.pem
        target: /usr/share/elasticsearch/config/secrets/root.pub.pem
        uid: '1000'
        gid: '1000'
      - source: certificate.key.pem
        target: /usr/share/elasticsearch/config/secrets/certificate.key.pem
        uid: '1000'
        gid: '1000'
      - source: certificate.crt.pem
        target: /usr/share/elasticsearch/config/secrets/certificate.crt.pem
        uid: '1000'
        gid: '1000'
  kibana:
    environment:
      - SERVER_NAME=kibana.example.com
      - ELASTICSEARCH_HOSTS=https://elasticsearch.example.com:9200
      - ELASTICSEARCH_SSL_CERTIFICATEAUTHORITIES=/run/secrets/root.pub.pem
      - SERVER_SSL_ENABLED=true
      - SERVER_SSL_CERTIFICATE=/run/secrets/certificate.crt.pem
      - SERVER_SSL_KEY=/run/secrets/certificate.key.pem
      - SERVER_SSL_CERTIFICATEAUTHORITIES=/run/secrets/root.pub.pem
    secrets:
      - root.pub.pem
      - certificate.key.pem
      - certificate.crt.pem

secrets:
  root.pub.pem:
    external: true
    name: certificates.example.com.ca.pub.pem
  certificate.key.pem:
    external: true
    name: certificates.wildcard.example.com.key.pem
  certificate.crt.pem:
    external: true
    name: certificates.wildcard.example.com.pub.pem
volumes:
  elasticsearchdata:
    driver: local
    driver_opts:
      type: nfs
      device: ":/volumes/elasticsearch/data"
      o: "addr=${NFSSERVER},vers=4,rw"
  elasticsearchconfig:
    driver: local
    driver_opts:
      type: nfs
      device: ":/volumes/elasticsearch/config"
      o: "addr=${NFSSERVER},vers=4,rw"
  elasticsearchlogs:
    driver: local
    driver_opts:
      type: nfs
      device: ":/volumes/elasticsearch/logs"
      o: "addr=${NFSSERVER},vers=4,rw"

As before, to deploy the updated stack:

docker stack deploy -c docker-compose.yml -c docker-compose.prod.yml prod --with-registry-auth

That's it. So far this is the easiest part of building a new ELK stack in Docker.