Goals:
- single node elasticsearch
- single node kibana
- password for all accounts
- https between all components
- behind traefik
- future post: collect network logs (routers)
- future post: collect application logs (web servers, dns servers, docker)
- future post: collect application metrics
- future post: correlate with threat intelligence
Create compose file
version: '3'
services:
es:
image: docker.elastic.co/elasticsearch/elasticsearch:7.16.3
container_name: elastic_es
restart: always
env_file:
- ./.env
environment:
ES_JAVA_OPTS: "-Xms2g -Xmx2g"
node.name: "es"
discovery.type: "single-node"
bootstrap.memory_lock: "true"
# minimal security
xpack.security.enabled: "true"
# no encryption on internode communication
xpack.security.transport.ssl.enabled: "false"
# https traffic
xpack.security.http.ssl.enabled: "true"
xpack.security.http.ssl.key: "${CERTS_DIR}/es.key"
xpack.security.http.ssl.certificate: "${CERTS_DIR}/es_chain.crt"
xpack.security.http.ssl.certificate_authorities: "${CERTS_DIR}/ca.crt"
ulimits:
memlock:
soft: -1
hard: -1
networks:
- reverseproxy
- default
volumes:
- data:/usr/share/elasticsearch/data
- certs:${CERTS_DIR}:ro
labels:
- "traefik.enable=true"
- "traefik.http.routers.elastic.rule=Host(`elasticsearch.foobar.com`)"
- "traefik.http.routers.elastic.service=elastic"
- "traefik.http.routers.elastic.tls=true"
- "traefik.http.routers.elastic.tls.certresolver=le"
- "traefik.http.routers.elastic.entrypoints=websecure"
- "traefik.http.services.elastic.loadbalancer.server.port=9200"
- "traefik.http.services.elastic.loadbalancer.server.scheme=https"
- "traefik.http.services.elastic.loadbalancer.serversTransport=elastic"
- "traefik.http.serversTransports.elastic.serverName=es"
- "traefik.http.serversTransports.elastic.insecureSkipVerify=true"
deploy:
resources:
limits:
cpus: "4.0"
memory: 4000M
memswap_limit: 4000M
kibana:
image: docker.elastic.co/kibana/kibana:7.16.3
container_name: elastic_kibana
restart: always
depends_on:
- es
env_file:
- ./.env
- ./.env.kibana
environment:
- ELASTICSEARCH_URL="https://es:9200"
- ELASTICSEARCH_HOSTS=["https://es:9200"]
# minimal security: defined in environment files
# kibana has to trust elasticsearch certificate
- ELASTICSEARCH_SSL_CERTIFICATEAUTHORITIES="${CERTS_DIR}/ca.crt"
# https traffic between other components and kibana
- SERVER_SSL_ENABLED=true
- SERVER_SSL_KEY=${CERTS_DIR}/kibana.key
- SERVER_SSL_CERTIFICATE=${CERTS_DIR}/kibana_chain.crt
- SERVER_PUBLICBASEURL=https://kibana.foobar.com
networks:
- reverseproxy
- default
volumes:
- certs:${CERTS_DIR}:ro
labels:
- "traefik.enable=true"
- "traefik.http.routers.kibana.rule=Host(`kibana.foobar.com`)"
- "traefik.http.routers.kibana.service=kibana"
- "traefik.http.routers.kibana.tls=true"
- "traefik.http.routers.kibana.tls.certresolver=le"
- "traefik.http.routers.kibana.entrypoints=websecure"
- "traefik.http.services.kibana.loadbalancer.server.port=5601"
- "traefik.http.services.kibana.loadbalancer.server.scheme=https"
- "traefik.http.services.kibana.loadbalancer.serversTransport=kibana"
- "traefik.http.serversTransports.kibana.serverName=kibana"
- "traefik.http.serversTransports.kibana.insecureSkipVerify=true"
deploy:
resources:
limits:
cpus: "4.0"
memory: 4000M
memswap_limit: 4000M
volumes:
data:
certs:
name: elastic_certs
external: true
networks:
reverseproxy:
external: true
Create a file named .env
with the following content:
COMPOSE_PROJECT_NAME=elastic
CERTS_DIR=/usr/share/elasticsearch/config/certificates
Create SSL CA and certificates for Elasticsearch and Kibana
Create a volume named elastic_certs
, create the certificates using a temporary container and change the ownership:
docker volume create elastic_certs
docker run -it --rm -v elastic_certs:/certs alpine:3.15.0 sh
apk update && apk add openssl && cd /certs
# create the CA
openssl req -x509 -nodes -newkey ec -pkeyopt ec_paramgen_curve:secp384r1 -keyout ca.key -out ca.crt -days 3652 -subj "/C=LU/ST=Luxembourg/L=Luxembourg/O=Xentoo/CN=elastic_ca" -extensions v3_ca
# create csr for elastic node
openssl req -nodes -newkey ec -pkeyopt ec_paramgen_curve:secp384r1 -keyout es.key -out es.csr -subj "/C=LU/ST=Luxembourg/L=Luxembourg/O=Xentoo/CN=es" -addext "subjectAltName=DNS:es" -extensions v3_req
# sign the certificate
openssl x509 -req -days 3652 -CA ca.crt -CAkey ca.key -CAcreateserial -extfile <(printf "subjectAltName=DNS:es") -in es.csr -out es.crt
# repeat for kibana
openssl req -nodes -newkey ec -pkeyopt ec_paramgen_curve:secp384r1 -keyout kibana.key -out kibana.csr -subj "/C=LU/ST=Luxembourg/L=Luxembourg/O=Xentoo/CN=es" -addext "subjectAltName=DNS:kibana" -extensions v3_req
openssl x509 -req -days 3652 -CA ca.crt -CAkey ca.key -CAcreateserial -extfile <(printf "subjectAltName=DNS:kibana") -in kibana.csr -out kibana.crt
# create certificate chains
cat es.crt ca.crt > es_chain.crt
cat kibana.crt ca.crt > kibana_chain.crt
# change ownership of certificates for elasticsearch & kibana
chown 1000:1000 es* kibana*
exit
In a production environment, you should sign the certificates with your existing CA, but for testing, this is enough.
Define passwords for default users
Start elasticsearch node: docker compose up es -d
Set the passwords for the default users:
docker exec -it elastic_es elasticsearch-setup-passwords auto --url https://es:9200 --batch
Save the passwords in a safe location, you will need them later to connect the various components to Elasticsearch.
Configure Kibana
Create a file named .env.kibana
and with the following content, use the password from previous step:
ELASTICSEARCH_USERNAME=kibana_system
ELASTICSEARCH_PASSWORD=password
Start kibana container: docker compose up kibana -d
At this point, you should be able to connect to Kibana with username elastic
.