Secure Elastic Stack: End-to-End TLS, RBAC, and Password‑Free Beats Setup
Learn how to build a three‑node Elasticsearch cluster with full TLS encryption, configure Kibana’s HTTPS settings, create minimal‑privilege Beats‑writer roles, and eliminate clear‑text passwords using Elastic Stack’s keystore, all within a reproducible Vagrant environment for secure, scalable monitoring.
Prerequisites
The tutorial assumes the following software versions: Elastic Stack 7.8.0, macOS 10.15.5, Vagrant 2.2.9, VirtualBox 6.0, and CentOS 8.0. All configuration and test steps are based on the supplied Vagrantfile, which can be adapted to any comparable environment.
# -*- mode: ruby -*-
# vi: set ft=ruby :
# Every Vagrant development environment requires a box. You can search for
# boxes at https://atlas.hashicorp.com/search.
BOX_IMAGE = "bento/centos-8"
ES_COUNT = 3
NODE_COUNT = 4
Vagrant.configure("2") do |config|
# Set all guests to use the same static DNS resolution /etc/hosts
config.vm.provision :hosts, :sync_hosts => true
# Use Vagrant default key pair for SSH login
config.ssh.insert_key = false
# Deploy Elasticsearch servers
(1..ES_COUNT).each do |i|
config.vm.define "es#{i}" do |es_config|
es_config.vm.box = BOX_IMAGE
es_config.vm.hostname = "es#{i}.zenlab.local"
es_config.vm.network :private_network, ip: "192.168.50.#{i + 10}"
es_config.vm.provision :hosts, :sync_hosts => true
es_config.vm.provider :virtualbox do |vb|
vb.memory = 2048
vb.cpus = 1
end
es_config.vm.provision :shell, path: 'pre-install-ES.sh'
end
end
# Deploy Kibana, Logstash, APM Server, Heartbeat and Packetbeat
config.vm.define "lk" do |lk_config|
lk_config.vm.box = BOX_IMAGE
lk_config.vm.hostname = "lk.zenlab.local"
lk_config.vm.network :private_network, ip: "192.168.50.20"
lk_config.vm.network 'forwarded_port', guest: 5601, host: 5601
lk_config.vm.provision :hosts, :sync_hosts => true
lk_config.vm.provider :virtualbox do |vb|
vb.memory = 1024
vb.cpus = 1
end
end
# Two managed nodes for Beats agents
(1..NODE_COUNT).each do |i|
config.vm.define "node#{i}" do |node_config|
node_config.vm.box = BOX_IMAGE
node_config.vm.hostname = "node#{i}.zenlab.local"
node_config.vm.network :private_network, ip: "192.168.50.#{i + 20}"
node_config.vm.provider :virtualbox do |vb|
vb.memory = 1024
vb.cpus = 1
end
node_config.vm.provision :shell, path: 'pre-install-beats.sh'
end
end
config.vm.provision "shell", inline: <<-SHELL
sh -c "echo 'Welcome to Elastic Stack!'"
SHELL
endThree‑node Elasticsearch cluster
Start the three Elasticsearch VMs with: vagrant up es1 es2 es3 Generate a certificate bundle for inter‑node TLS using elasticsearch‑certutil and the instance.yml seed file:
# instance.yml
instances:
- name: 'es1'
ip: ['192.168.50.11']
dns: [ 'es1.zenlab.local' ]
- name: "es2"
ip: ['192.168.50.12']
dns: [ 'es2.zenlab.local' ]
- name: 'es3'
ip: ['192.168.50.13']
dns: [ 'es3.zenlab.local' ]
- name: 'lk'
ip: ['192.168.50.20']
dns: [ 'lk.zenlab.local' ] sudo /usr/share/elasticsearch/bin/elasticsearch-certutil cert --ca --pem --in /vagrant/certs/instance.yml --out /vagrant/certs/certs.zipUnzip the bundle and copy the CA certificate and each node’s certificate/key to /etc/elasticsearch/certs on the corresponding host.
sudo mkdir /etc/elasticsearch/certs
sudo cp /vagrant/certs/ca/ca.crt /etc/elasticsearch/certs
sudo cp /vagrant/certs/es1/* /etc/elasticsearch/certs # repeat for es2 and es3The certs directory now contains:
ca.crt – the root CA certificate
esX.crt – the node’s public certificate
esX.key – the node’s private key
Place these files in each Elasticsearch node’s configuration directory and enable TLS in elasticsearch.yml. Example for the first node:
# elasticsearch.yml
cluster.name: elk4devops
node.name: es1
path.data: /var/lib/elasticsearch
path.logs: /var/log/elasticsearch
network.host: es1.zenlab.local
cluster.initial_master_nodes: ["es1"]
discovery.seed_hosts: [ "es1.zenlab.local" ]
xpack.security.enabled: true
xpack.security.http.ssl.enabled: true
xpack.security.http.ssl.key: certs/es1.key
xpack.security.http.ssl.certificate: certs/es1.crt
xpack.security.http.ssl.certificate_authorities: certs/ca.crt
xpack.security.transport.ssl.enabled: true
xpack.security.transport.ssl.key: certs/es1.key
xpack.security.transport.ssl.certificate: certs/es1.crt
xpack.security.transport.ssl.certificate_authorities: certs/ca.crt
xpack.monitoring.collection.enabled: true
action.auto_create_index: ".app-search-*-logs-*,-.app-search-*,+*"Copy the file to /etc/elasticsearch/elasticsearch.yml, reload the systemd daemon and start the service:
sudo cp /vagrant/elasticsearch.yml /etc/elasticsearch/elasticsearch.yml
sudo systemctl daemon-reload
sudo systemctl start elasticsearchGenerate built‑in user passwords (the command prints random strong passwords):
sudo /usr/share/elasticsearch/bin/elasticsearch-setup-passwords auto -u "https://es1.zenlab.local:9200" -bStore the generated passwords securely. Verify HTTPS access with the CA certificate:
curl --cacert /vagrant/certs/ca/ca.crt -u elastic 'https://es1.zenlab.local:9200/_cat/nodes?v'Adding the second and third nodes
Repeat the certificate copy and configuration steps for es2 and es3, using the respective elasticsearch2.yml and elasticsearch3.yml files (shown below). After copying each file to /etc/elasticsearch/elasticsearch.yml, reload and start the service, then verify that the node joins the cluster with the same curl command.
# elasticsearch2.yml (excerpt)
cluster.name: elk4devops
node.name: es2
network.host: es2.zenlab.local
cluster.initial_master_nodes: ["es1"]
discovery.seed_hosts: [ "es1.zenlab.local" ]
xpack.security.enabled: true
xpack.security.http.ssl.enabled: true
xpack.security.http.ssl.key: certs/es2.key
xpack.security.http.ssl.certificate: certs/es2.crt
xpack.security.http.ssl.certificate_authorities: certs/ca.crt
xpack.security.transport.ssl.enabled: true
xpack.security.transport.ssl.key: certs/es2.key
xpack.security.transport.ssl.certificate: certs/es2.crt
xpack.security.transport.ssl.certificate_authorities: certs/ca.crt # elasticsearch3.yml (excerpt)
cluster.name: elk4devops
node.name: es3
network.host: es3.zenlab.local
cluster.initial_master_nodes: ["es1"]
discovery.seed_hosts: [ "es1.zenlab.local" ]
xpack.security.enabled: true
xpack.security.http.ssl.enabled: true
xpack.security.http.ssl.key: certs/es3.key
xpack.security.http.ssl.certificate: certs/es3.crt
xpack.security.http.ssl.certificate_authorities: certs/ca.crt
xpack.security.transport.ssl.enabled: true
xpack.security.transport.ssl.key: certs/es3.key
xpack.security.transport.ssl.certificate: certs/es3.crt
xpack.security.transport.ssl.certificate_authorities: certs/ca.crtKibana HTTPS configuration
Copy the CA certificate and the Kibana node’s certificate/key to /etc/kibana/certs:
sudo mkdir /etc/kibana/certs
sudo cp /vagrant/certs/ca/ca.crt /etc/kibana/certs
sudo cp /vagrant/certs/lk/* /etc/kibana/certsReplace the default kibana.yml with the prepared version and start the service:
sudo cp /vagrant/kibna.yml /etc/kibana/kibana.yml
sudo systemctl start kibanaMonitor the log file until Kibana reports a successful start, then open https://lk.zenlab.local:5601 in a browser and log in with the elastic user.
Beats role and user for write‑only access
Create a role that grants write access to the filebeat and metricbeat indices, then create a user beats-writer and assign the role. (Screenshots omitted for brevity.)
Initial Beats node
Bring up a Beats node with: vagrant up node1 The provisioning script pre-install-beats.sh installs Filebeat, Metricbeat and Auditbeat RPMs and enables the services.
#!/bin/bash
elastic_version='7.8.0'
sudo rpm -ivh /vagrant/rpm/filebeat-$elastic_version-x86_64.rpm
sudo systemctl enable filebeat.service
sudo rpm -ivh /vagrant/rpm/metricbeat-$elastic_version-x86_64.rpm
sudo systemctl enable metricbeat.service
sudo rpm -ivh /vagrant/rpm/auditbeat-$elastic_version-x86_64.rpm
sudo systemctl enable auditbeat.serviceDeploy the CA certificate to the system trust store:
sudo update-ca-trust enable
sudo cp /vagrant/certs/ca/ca.crt /etc/pki/ca-trust/source/anchors/
sudo update-ca-trust extractCopy the prepared Beat configuration files and enable the system module for Filebeat:
sudo cp -f /vagrant/filebeat.yml /etc/filebeat/filebeat.yml
sudo cp -f /vagrant/metricbeat.yml /etc/metricbeat/metricbeat.yml
sudo filebeat modules enable systemRun the setup commands once to create the required indices, pipelines and Kibana objects:
filebeat setup
metricbeat setupStart the Beats services and verify data flow with:
filebeat -e
metricbeat -eDeploy Beats to additional nodes
The add-agent.sh script automates installation, CA deployment, configuration replacement, keystore population and service start‑up for new Beats nodes.
#!/bin/bash
elastic_version='7.8.0'
b_user='beats-writer'
b_pwd='DevOps1234'
sudo rpm -ivh /vagrant/rpm/filebeat-$elastic_version-x86_64.rpm
sudo systemctl enable filebeat.service
sudo filebeat modules enable system
sudo rpm -ivh /vagrant/rpm/metricbeat-$elastic_version-x86_64.rpm
sudo systemctl enable metricbeat.service
sudo update-ca-trust enable
sudo cp /vagrant/certs/ca/ca.crt /etc/pki/ca-trust/source/anchors/
sudo update-ca-trust extract
sudo cp -f /vagrant/filebeat-v1.yml /etc/filebeat/filebeat.yml
sudo cp -f /vagrant/metricbeat-v1.yml /etc/metricbeat/metricbeat.yml
echo $b_user | sudo filebeat keystore add BEATS_WRITER_USERNAME --stdin --force
echo $b_pwd | sudo filebeat keystore add BEATS_WRITER_PW --stdin --force
echo $b_user | sudo metricbeat keystore add BEATS_WRITER_USERNAME --stdin --force
echo $b_pwd | sudo metricbeat keystore add BEATS_WRITER_PW --stdin --force
sudo systemctl start metricbeat.service
sudo systemctl start filebeat.serviceThe accompanying filebeat-v1.yml and metricbeat.yml files configure Elasticsearch output to the three cluster nodes, use the keystore variables for credentials, enable host and geo metadata, and apply best‑practice settings such as logging.level: error.
Summary
The tutorial completes the following secure configurations:
TLS‑encrypted inter‑node communication for a three‑node Elasticsearch cluster and HTTPS for Kibana.
Beats agents with TLS‑encrypted transport and role‑based access control (RBAC) using a write‑only beats-writer role.
Removal of clear‑text passwords from configuration files by storing credentials in the Beats keystore.
Open items include monitoring the health of the "Bests" node, tuning index lifecycle management, and automating hot‑warm data migration.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
