Secure Your ELK Stack Using Free X‑Pack: TLS, Auth, and RBAC

This guide explains how to enable and configure the free core security features of Elastic Stack 6.8/7.1, including TLS encryption, user and role management, Kibana Spaces for multi‑tenant protection, and step‑by‑step setup of certificates, keystore passwords, and Logstash‑to‑Elasticsearch authentication across multiple nodes.

Ops Development Stories
Ops Development Stories
Ops Development Stories
Secure Your ELK Stack Using Free X‑Pack: TLS, Auth, and RBAC

Scenario

Elasticsearch and Kibana are often used by multiple users, so implementing access control is essential for security.

On May 21, 2019 Elastic announced that the core security features of Elastic Stack 6.8.0 and 7.1.0 are now free.

The free features include TLS encryption, user and role management, role‑based access control for cluster and index APIs, and Kibana Spaces for multi‑tenant protection.

1. X‑Pack Evolution

Before 5.x there was no X‑Pack; security, watch, and alert were separate modules. In 5.x they were packaged together as X‑Pack. Prior to 6.3 an extra installation was required; from 6.3 onward X‑Pack is bundled, with basic security in the paid Gold tier. Starting with 7.1 the basic security features became free.

2. How Security Was Handled Before Free Features

Scenario 1: No protection – services run on internal networks without exposing ports.

Scenario 2: Simple protection using Nginx basic auth and firewall rules.

Scenario 3: Third‑party security plugins such as SearchGuard or ReadonlyREST.

Scenario 4: Purchasing Elastic X‑Pack Gold or Platinum for advanced security, alerts, and machine‑learning features.

3. Configuring TLS and Authentication

Generate certificates:

/usr/share/elasticsearch/bin/elasticsearch-certutil ca</code>
<code>/usr/share/elasticsearch/bin/elasticsearch-certutil cert --ca elastic-stack-ca.p12</code>
<code># Press Enter for all prompts; no password needed</code>
<code># Move generated certificates to /etc/elasticsearch/</code>
<code>mv elastic-* /etc/elasticsearch/</code>
<code>chown elasticsearch.elasticsearch elastic-*</code>
<code>chgrp elasticsearch /etc/elasticsearch/elastic-certificates.p12 /etc/elasticsearch/elastic-stack-ca.p12</code>
<code>chmod 640 /etc/elasticsearch/elastic-certificates.p12 /etc/elasticsearch/elastic-stack-ca.p12

Copy the two certificate files to the other nodes.

Elasticsearch Master Node Configuration

cluster.name: elk-cluster
node.name: elk-1
node.master: true
node.data: true
path.data: /var/lib/elasticsearch
path.logs: /var/log/elasticsearch
bootstrap.memory_lock: false
network.host: 192.168.73.133
http.port: 9200
discovery.zen.ping.unicast.hosts: ["192.168.73.133", "192.168.73.135"]
discovery.zen.minimum_master_nodes: 1
http.cors.enabled: true
http.cors.allow-origin: "*"
http.cors.allow-credentials: true
http.cors.allow-methods: OPTIONS, HEAD, GET, POST, PUT, DELETE
http.cors.allow-headers: Authorization,X-Requested-With,Content-Length,Content-Type
xpack.security.enabled: true
xpack.security.transport.ssl.enabled: true
xpack.security.transport.ssl.verification_mode: certificate
xpack.security.transport.ssl.keystore.path: /etc/elasticsearch/elastic-certificates.p12
xpack.security.transport.ssl.truststore.path: /etc/elasticsearch/elastic-certificates.p12

Restart the service:

systemctl restart elasticsearch

Set Up Authentication Passwords

# Auto‑generate passwords
/usr/share/elasticsearch/bin/elasticsearch-setup-passwords auto
# Or interactively set passwords
/usr/share/elasticsearch/bin/elasticsearch-setup-passwords interactive

Add the passwords to the keystore:

/usr/share/elasticsearch/bin/elasticsearch-keystore add xpack.security.transport.ssl.keystore.secure_password
/usr/share/elasticsearch/bin/elasticsearch-keystore add xpack.security.transport.ssl.truststore.secure_password

Verify node status:

curl -u elastic:Goldwind@2019 http://192.168.73.133:9200/_cat/nodes?v

Other Elasticsearch Nodes Configuration

Copy the same certificates and keystore to the data nodes, then use a similar elasticsearch.yml (adjust node.name and network.host).

Kibana Configuration

server.port: 5601
server.host: "192.168.73.133"
server.name: "192.168.73.133"
elasticsearch.hosts: ["http://192.168.73.133:9200"]
kibana.index: ".kibana"
elasticsearch.username: "kibana"
elasticsearch.password: "Goldwind@2019"
logging.quiet: true
i18n.locale: "zh-CN"

Logstash Input Configuration (unchanged)

input {
    file { path => "/var/log/messages" type => "system" start_position => "beginning" }
    file { path => "/var/log/secure" type => "secure" start_position => "beginning" }
    file { path => "/var/log/httpd/access_log" type => "http" start_position => "beginning" }
    file { path => "/usr/local/nginx/logs/elk.access.log" type => "nginx" start_position => "beginning" }
}
output {
    if [type] == "http" { redis { host => "192.168.73.133" password => 'root123' port => "6379" db => "2" data_type => "list" key => 'nagios_http' } }
    if [type] == "nginx" { redis { host => "192.168.73.133" password => 'root123' port => "6379" db => "2" data_type => "list" key => 'nagios_nginx' } }
    if [type] == "secure" { redis { host => "192.168.73.133" password => 'root123' port => "6379" db => "2" data_type => "list" key => 'nagios_secure' } }
    if [type] == "system" { redis { host => "192.168.73.133" password => 'root123' port => "6379" db => "2" data_type => "list" key => 'nagios_system' } }
}

Logstash Output to Elasticsearch (with authentication)

output {
    if [type] == "system" {
        elasticsearch { hosts => ["192.168.73.133:9200"] index => "nagios-system-%{+YYYY.MM.dd}" user => "elastic" password => "Goldwind@2019" sniffing => false }
    }
    if [type] == "secure" {
        elasticsearch { hosts => ["192.168.73.133:9200"] index => "nagios-secure-%{+YYYY.MM.dd}" user => "elastic" password => "Goldwind@2019" sniffing => false }
    }
    if [type] == "http" {
        elasticsearch { hosts => ["192.168.73.133:9200"] index => "nagios-http-%{+YYYY.MM.dd}" user => "elastic" password => "Goldwind@2019" sniffing => false }
    }
    if [type] == "nginx" {
        elasticsearch { hosts => ["192.168.73.133:9200"] index => "nagios-nginx-%{+YYYY.MM.dd}" user => "elastic" password => "Goldwind@2019" sniffing => false }
    }
}

Fixing the Head Plugin after Installing X‑Pack

Add the following CORS settings to elasticsearch.yml:

http.cors.enabled: true
http.cors.allow-origin: "*"
http.cors.allow-headers: Authorization, X-Requested-With, Content-Length, Content-Type

Access the Head plugin with credentials, e.g.:

http://192.168.73.133:9100/?auth_user=elastic&auth_password=Goldwind@2019

Kibana Web UI

Kibana UI
Kibana UI
Kibana UI
Kibana UI

Finally, create new users and assign roles through the Kibana Management UI.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

ElasticsearchELKLogstashKibanaX-Pack
Ops Development Stories
Written by

Ops Development Stories

Maintained by a like‑minded team, covering both operations and development. Topics span Linux ops, DevOps toolchain, Kubernetes containerization, monitoring, log collection, network security, and Python or Go development. Team members: Qiao Ke, wanger, Dong Ge, Su Xin, Hua Zai, Zheng Ge, Teacher Xia.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.