Elastic-Stack for network engineers (Initial setup)

Elastic-Stack is a distributed and horizontally scalable search, analytics and visualization platform based on the components Elasticsearch, Logstash, Kibana and Beats. I’m quite overwhelmed with the options and integrations an Elastic-Stack has to offer. Switching from traditional log monitoring to Elastic-Stack is like switching from a horse-drawn carriage to the Falcon 9 rocket. Therefore this journey to Elastic-Stack will be a series of blog posts.

The goal of this blog post is a running Elasticsearch cluster with four nodes, a working Kibana visualization plus Nginx as reverse proxy on the first node and some Beats (Metricbeat, Filebeat) to monitor the cluster itself. The architecture of the cluster will look in this stage (Initial setup) like this:

Elastic-Stack: Initial setup
Elastic-Stack: Initial setup

Knowledge and skills in those topics might be helpful:

  • Linux (Debian, CentOS, …)
  • Logging (Log files, Syslog, Netflow, …)
  • Network (IP addressing, Proxying, TCP/UDP ports, troubleshooting, …)
  • Packet analyzer (tshark for proofing of TLS encryption, …)
  • TLS (Certificates and Certificate Authority, …)
  • JSON (JavaScript Object Notation, data structure, …)
  • YAML (YAML Ain’t Markup Language, configuration files, …)

Preparing the virtual machines

My home network/lab environment has two physical servers using XCP-NG as virtualization platform. This means a creation of four virtual machines acting as Elastic-Stack nodes and distributing two nodes per physical server is possible. For my small home network/lab environment the virtual machines will get the following resource assignment:

  • 4 vCPU (4 socket / 1 core per socket)
  • 8 GiB RAM (fixed allocation)
  • 500 GiB Disk (on shared storage)
Elastic-Stack: Virtual machine resource assignments
Elastic-Stack: Virtual machine resource assignments

Preparing the Operating System

As Operating system for the Elastic-Stack nodes I’m using Debian 11 Bullseye with the latest netinstISO image. After a “standard” installation (Debian minimal plus SSH server) some additional, useful packages are installed. Those packages are:

  • gnupg (used to install elastic’s key to apt key-ring)
  • net-tools (to have netstat to check TCP/UDP ports)
  • tshark (to verify if elastic traffic is encrypted)

As one-liner for copy&paste:

    apt -y install gnupg net-tools tshark
Elastic-Stack: Install additional Debian packages

Because the virtual machines are all running on XCP-NG, the guest-tools will be installed as well. Detailed installation instructions are available in the documentation at XCP-NG guest-tools.

Installation of Elasticsearch

For the installation of Elasticsearch on Debian 11 I’m following the instructions provided at Install Elasticsearch with Debian Package. The documentation covers all aspects of setting up and configuring Elasticsearch and therefore I’m only referencing to it. Please note: The version at date of publishing this blog post is 7.15.

Configuration of Elasticsearch and Cluster bootstrapping (First node)

The first node is used to boot strap the cluster and therefore this node requires the configuration settings cluster.inital_master_node. Because Security and Encrypted communications are now included in the free and open-basic license I’m enabling the xpack feature in the YAML configuration file. For the licensing details included in free and open-basic, see Elastic Stack subscriptions.

To secure the cluster, the following instructions are provided and should (better: must) be set for production environments:

The /etc/elasticsearch/elasticsearch.yml configuration file for the First node and cluster bootstrapping might look like this:

    # ======================== Elasticsearch Configuration =========================
    cluster.name: "MY_CLUSTER-production"
    node.name: "HOST_1.TLD"
    node.attr.rack: "RACK_LOCATION"

    path.data: /var/lib/elasticsearch
    path.logs: /var/log/elasticsearch

    network.host: IP_ADDR_1
    http.port: 9200

    discovery.seed_hosts: ["IP_ADDR_1:9300", "IP_ADDR_2:9300", "IP_ADDR_3:9300", "IP_ADDR_4:9300"]

    # Required for Cluster Bootstrap only
    # Comment out after Bootstrap
    cluster.initial_master_nodes: ["HOST_1.TLD"]

    # Set Xpack to basic-license
    xpack.license.self_generated.type: basic
    xpack.monitoring.collection.enabled: true

    # Set Xpack security settings
    xpack.security.enabled: true
    xpack.security.transport.ssl.enabled: true
    xpack.security.transport.ssl.verification_mode: certificate
    xpack.security.transport.ssl.client_authentication: required
    xpack.security.transport.ssl.keystore.path: elastic-certificates.p12
    xpack.security.transport.ssl.truststore.path: elastic-certificates.p12
    xpack.security.http.ssl.enabled: true
    xpack.security.http.ssl.keystore.path: http.p12
    xpack.security.authc.token.enabled: true
    xpack.security.authc.api_key.enabled: true
Elastic-Stack: Configuration of Elasticsearch and Cluster bootstrapping (First node)

The first node of the Elastic-Stack cluster is then started with this command line:

    systemctl start elasticsearch
Elastic-Stack: Starting

Configuration of Elasticsearch (Second / Third / Fourth node)

A possible /etc/elasticsearch/elasticsearch.yml configuration file for the Second / Third / Fourth node might look like this:

    # ======================== Elasticsearch Configuration =========================
    cluster.name: "MY_CLUSTER-production"
    node.name: "HOST_[2|3|4].TLD"
    node.attr.rack: "RACK_LOCATION"

    path.data: /var/lib/elasticsearch
    path.logs: /var/log/elasticsearch

    network.host: IP_ADDR_[2|3|4]
    http.port: 9200

    discovery.seed_hosts: ["IP_ADDR_1:9300", "IP_ADDR_2:9300", "IP_ADDR_3:9300", "IP_ADDR_4:9300"]

    # Set Xpack to basic-license
    xpack.license.self_generated.type: basic
    xpack.monitoring.collection.enabled: true

    # Set Xpack security settings
    xpack.security.enabled: true
    xpack.security.transport.ssl.enabled: true
    xpack.security.transport.ssl.verification_mode: certificate
    xpack.security.transport.ssl.client_authentication: required
    xpack.security.transport.ssl.keystore.path: elastic-certificates.p12
    xpack.security.transport.ssl.truststore.path: elastic-certificates.p12
    xpack.security.http.ssl.enabled: true
    xpack.security.http.ssl.keystore.path: http.p12
    xpack.security.authc.token.enabled: true
    xpack.security.authc.api_key.enabled: true
Elastic-Stack: Configuration of Elasticsearch (Second / Third / Fourth node)

After a start with systemctl start elasticsearch the Second, Third and Fourth node will automatically join the cluster due to the Cluster Discovery Seeding. To ensure the communication between Elasticsearch is encrypted I quick-check the communication with tshark:

    tshark -i eth0 -Y 'tcp.dstport==9200 and tls.app_data'
Elastic-Stack: Checking encryption with tshark

The output of tshark should be similar like this:

    1475 15.945403055 nnn.nnn.nnn.nnn → nnn.nnn.nnn.nnn TLSv1.2 598 Application Data
    1503 16.009221770 nnn.nnn.nnn.nnn → nnn.nnn.nnn.nnn TLSv1.2 1326 Application Data
    1604 17.102084056 nnn.nnn.nnn.nnn → nnn.nnn.nnn.nnn TLSv1.2 268 Application Data
Elastic-Stack: Checking encryption, output of tshark capture

Configuration of Kibana (First node)

The First node will also act as Kibana Dashboard for the data visualization. To install Kibana I’m following the standard installation process as described in Install Kibana with Debian package.

Because I’m operating my own Public key infrastructure for my home network/lab environment I can create inside the PKI a Certificate signing request and sign it directly with the Root certificate. The Certificate is then exported as PEM (Privacy-Enhanced Mail) format and transferred by SCP to the First node.

A possible /etc/kibana/kibana.yml configuration file might look like this:

    # ======================== Kibana Configuration =========================
    server.port: 5601
    server.host: 127.0.0.1
    server.name: "HOST_1.TLD"

    server.publicBaseUrl: "https://NGINX_HOST_1.TLD"

    # Enable TLS for Kibana with PKI-signed Certificate
    server.ssl.enabled: true
    server.ssl.certificate: /etc/kibana/HOST_1.TLD.pem
    server.ssl.key: /etc/kibana/HOST_1.TLD.pem

    server.securityResponseHeaders.strictTransportSecurity: "max-age=31536000"
    server.securityResponseHeaders.disableEmbedding: true
    csp.strict: true

    # Elasticsearch setup, use all four nodes
    elasticsearch.hosts: ["https://HOST_1.FQDN:9200", "https://HOST_2.FQDN:9200", "https://HOST_3.FQDN:9200", "https://HOST_4.FQDN:9200"]
    elasticsearch.username: "kibana_system"
    elasticsearch.ssl.certificateAuthorities: /etc/kibana/ELASTIC_SEARCH_CA.pem

    elasticsearch.pingTimeout: 1500
    elasticsearch.requestTimeout: 30000
    elasticsearch.shardTimeout: 30000

    kibana.index: ".kibana"
    kibana.defaultAppId: "home"

    # Set Xpack security settings
    xpack.security.enabled: true

    # Set to false if Kibana is monitored with Metricbeat module
    monitoring.kibana.collection.enabled: false
Elastic-Stack: Configuration of Kibana (First node)

Configuration of Nginx as Reverse Proxy (First node)

Because Kibana is only reachable via localhost (127.0.0.1) I set up Nginx to act as a reverse proxy server between a web browser and Kibana. Nginx can be installed on Debian with the following command line:

    apt -y install nginx
Elastic-Stack: Install Nginx Debian Package

Because no other web site will be hosted on this server, the configuration can be done directly in the /etc/nginx/sites-available/default file. The configuration includes a certificate signed by my own PKI and acts as a Reverse Proxy for Kibana (running on 127.0.0.1:5601). A configuration file for Nginx might look like this:

    server {
      listen IP_ADDR_1:443 ssl;
      server_name NGINX.TLD;
      index index.html;

      ssl_certificate /etc/ssl/private/NGINX.TLD.pem;
      ssl_certificate_key /etc/ssl/private/NGINX.TLD.pem;

      ssl_session_cache shared:SSL:10m;
      ssl_session_timeout 5m;
      ssl_protocols TLSv1.3;
      ssl_ciphers ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE
      ssl_prefer_server_ciphers on;

      location / {
        proxy_pass https://127.0.0.1:5601;
        proxy_read_timeout 90;
        proxy_connect_timeout 90;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Proxy "";
      }
    }
Elastic-Stack: Configuration of Nginx as Reverse Proxy (First node)

When the configuration is completed, Nginx can be restarted with:

    systemctl restart nginx
Elastic-Stack: Restart Nginx as Reverse Proxy

A quick test in a web browser should show the Elastic Welcome web page:

Elastic-Stack: Kibana via Nginx Reverse Proxy
Elastic-Stack: Kibana via Nginx Reverse Proxy

Add GeoIP for Metricbeat with Kibana Dev Tools

To add GeoIP information like Country, City, etc. per IP addresss to Metricbeat, the Elastic-Stack must be able to connect to the public Elastic GeoIP endpoint (See GeoIP processor). With the Kibana Dev Tools a pipeline for GeoIP can be added (See Enrich events with geoIP information). The adding of the pipeline looks similar like this:

Elastic-Stack: Add GeoIP for Metricbeat with Kibana Dev Tools
Elastic-Stack: Add GeoIP for Metricbeat with Kibana Dev Tools

Configuration of Metricbeat (First node)

To monitor the Elastic-Stack by itself, Metricbeat must have the modules beat-xpack, elasticsearch-xpack and system enabled. Because on the First node Kibana is installed, Kibana is monitored by Metricbeat as well. To activate the modules, the following command lines can be used:

    metricbeat modules enable beat-xpack
    metricbeat modules enable elasticsearch-xpack
    metricbeat modules enable system
    metricbeat modules enable kibana-xpack
Elastic-Stack: Enable Metricbeat modules on the First node

A possible /etc/metricbeat/metricbeat.yml might look like the one shown below. Please note that this configuration is enriched with service tags to reflect the installed Metricbeat modules. The First node is also used to setup the Metricbeat dashboards in Kibana and requires therefore in the TLS configuration the Certificate of Kibana. Because the GeoIp pipeline was set up in Kibana Dev Tools, the pipeline can now be used by Metricbeat. The Elastic-Stack is monitoring itself (I’m not using a dedicated monitoring cluster) and therefore the monitoring.cluster_uuid must be set to itself.

    ###################### Metricbeat Configuration Example #######################
    metricbeat.config.modules:
      path: ${path.config}/modules.d/*.yml
      reload.enabled: false

    setup.template.settings:
      index.number_of_shards: 1
      index.codec: best_compression

    name: "HOST_1.TLD"
    tags: ["service-metricbeat", "service-beat-xpack", "service-elasticsearch-xpack", "service-kibana-xpack", "service-nginx", "service-system"]
    fields:
      env: production

    setup.dashboards.enabled: false
    setup.kibana:
      host: "https://127.0.0.1:5601"
      username: "USERNAME"
      password: "PASSWORD"
      ssl:
        enabled: true
        certificate_authorities: ["/etc/metricbeat/ELASTIC_SEARCH_CA.pem", "/etc/kibana/KIBANA_HOST.TLD.pem"]
        verification_mode: "certificate"

    output.elasticsearch:
      hosts: ["HOST_1.TLD:9200", "HOST_2.TLD:9200", "HOST_3.TLD:9200", "HOST_4.TLD:9200"]
      protocol: "https"
      pipeline: geoip-info
      username: "USERNAME"
      password: "PASSWORD"
      ssl:
        enabled: true
        certificate_authorities: ["/etc/metricbeat/ELASTIC_SEARCH_CA.pem"]
        verification_mode: "certificate"

    processors:
      - add_host_metadata: ~
      - add_cloud_metadata: ~
      - add_docker_metadata: ~
      - add_kubernetes_metadata: ~

    logging.level: warning

    # Metricbeat internal HTTP endpoint (localhost only)
    http.enabled: true
    http.host: localhost
    http.port: 5066
Elastic-Stack: Configuration of Metricbeat (First node)

Metricbeat module “system.yml” (First node)

A detailed description of this module is available at System module. The default configuration for the system.yml does not need any specific adjustments and therefore it might look like this:

    - module: system
      period: 10s
      metricsets:
        - cpu
        - load
        - memory
        - network
        - process
        - process_summary
        - socket_summary

    process.include_top_n:
      by_cpu: 5
      by_memory: 5

    - module: system
      period: 1m
      metricsets:
        - filesystem
        - fsstat
      processors:
      - drop_event.when.regexp:
          system.filesystem.mount_point: '^/(sys|cgroup|proc|dev|etc|host|lib|snap)($|/)'

    - module: system
      period: 15m
      metricsets:
        - uptime
Elastic-Stack: Metricbeat module “system.yml” (First node)

Metricbeat module “beat-xpack.yml” (First node)

A detailed description of this module is available at Beat module. I just make sure that xpack.enabled is set to true and that metricsets are removed as suggested in the documentation:

    - module: beat
      xpack.enabled: true
      period: 10s
      hosts: ["http://localhost:5066"]
      #username: "user"
      #password: "secret"
Elastic-Stack: Metricbeat module “beat-xpack.yml” (First node)

Metricbeat module “elasticsearch-xpack.yml” (First node)

A detailed description of this module is available at Elasticsearch module. In this module I set the hosts configuration to all four Elasticsearch nodes and add the certificate of the ELasticsearch CA in certificate_authorities. A possible configuration file might look like this:

    - module: elasticsearch
      xpack.enabled: true
      period: 10s
      hosts: ["https://HOST_1.TLD:9200", "https://HOST_2.TLD:9200", "https://HOST_3.TLD:9200", "https://HOST_4.TLD:9200"]
      username: "USERNAME"
      password: "PASSWORD"
      ssl:
        enabled: true
        certificate_authorities: ["/etc/metricbeat/ELASTIC_SEARCH_CA.pem"]
        verification_mode: "certificate"
Elastic-Stack: Metricbeat module “elasticsearch-xpack.yml” (First node)

Metricbeat module “kibana-xpack.yml” (First node)

A detailed description of this module is available at Kibana module. Because Kibana is only reachable through localhost (127.0.0.1) and with TLS encryption, the configuration file must be adjusted with settings for hosts and the host’s TLS certificate. A possible configuration might look like shown below:

    - module: kibana
      xpack.enabled: true
      period: 10s
      hosts: ["https://127.0.0.1:5601"]
      username: "USERNAME"
      password: "PASSWORD"
      ssl:
        enabled: true
        certificate_authorities: ["/etc/kibana/KIBANA_HOST.TLD.pem"]
        verification_mode: "certificate"
Elastic-Stack: Metricbeat module “kibana-xpack.yml” (First node)

To setup the Metricbeat assets in Kibana I’m using the following command line:

    metricbeat setup -e
Elastic-Stack: Set up Metricbeat assets in Kibana

Configuration of Metricbeat (Second / Third / Fourth node)

The configuration of Metricbeat for the Second, Third and Fourth node are similar to the ones described in Configuration of Metricbeat (First node), Metricbeat module “system.yml” (First node), Metricbeat module “beat-xpack.yml” (First node) and Metricbeat module “elasticsearch-xpack.yml” (First node) except for the kibana-xpack module. Please note: Because those nodes are not used to load Metricbeat dashboards into Kibana, the configuration part for Kibana Dashboards is removed.

After a restart of Metricbeat with systemctl restart metricbeat the Cluster monitoring should show in the overview that Elasticsearch and Kibana is monitored with Metricbeat-monitoring as shown below:

Elastic-Stack: Cluster with Metricbeat self-monitoring
Elastic-Stack: Cluster with Metricbeat self-monitoring

The screenshot shows that no Log data is found and for Log data Filebeat needs to be configured. This configuration will be done in one of my next blog posts.


Share: