ELK Stack — Enabling Security

4 minute read

Enabling Security

Elasticsearch 8.x ships with security enabled by default. When you start Elasticsearch for the first time it automatically generates certificates, creates the elastic superuser with a random password, and produces enrollment tokens for Kibana and other nodes.

If you are running Elasticsearch 7.x or have an existing cluster without security, you must enable it manually.


Security Enabled by Default (ES 8.x)

On a fresh Elasticsearch 8.x installation the first-start output looks like this:

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
✅ Elasticsearch security features have been automatically configured!

→ Authentication is enabled and cluster connections are encrypted.

🔑 Password for the elastic user:
   <auto-generated-password>

🔗 Kibana enrollment token (valid for 30 minutes):
   eyJ2ZXIiOiI4LjE1LjAiLCJhZHIiOi...

🔗 Node enrollment token (valid for 30 minutes):
   eyJ2ZXIiOiI4LjE1LjAiLCJhZHIiOi...
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

Save these values immediately — you will need them to enroll Kibana and additional nodes.


Enabling Security on an Existing Cluster

If security was not enabled at install time, add the following to elasticsearch.yml on every node:

# /etc/elasticsearch/elasticsearch.yml

xpack.security.enabled: true
xpack.security.enrollment.enabled: true

# Transport layer encryption (required when security is enabled)
xpack.security.transport.ssl.enabled: true
xpack.security.transport.ssl.verification_mode: certificate
xpack.security.transport.ssl.keystore.path: certs/transport.p12
xpack.security.transport.ssl.truststore.path: certs/transport.p12

# HTTP layer encryption
xpack.security.http.ssl.enabled: true
xpack.security.http.ssl.keystore.path: certs/http.p12

Important: You must generate TLS certificates before restarting. See the TLS/SSL page for the full process.

Restart the cluster one node at a time (rolling restart):

sudo systemctl restart elasticsearch

Enrollment Tokens

Enrollment tokens simplify adding Kibana instances and new Elasticsearch nodes to a secured cluster.

Generate a Kibana enrollment token:

/usr/share/elasticsearch/bin/elasticsearch-create-enrollment-token -s kibana

Generate a node enrollment token:

/usr/share/elasticsearch/bin/elasticsearch-create-enrollment-token -s node

Tokens expire after 30 minutes by default. You can regenerate them at any time.


Setting Passwords with elasticsearch-setup-passwords

For clusters upgraded from 7.x you can set passwords for all built-in users interactively:

/usr/share/elasticsearch/bin/elasticsearch-setup-passwords interactive

Output:

Initiating the setup of passwords for reserved users.
You will be prompted to enter passwords as the process progresses.

Enter password for [elastic]:
Reenter password for [elastic]:
Enter password for [apm_system]:
Reenter password for [apm_system]:
Enter password for [kibana_system]:
Reenter password for [kibana_system]:
Enter password for [logstash_system]:
Reenter password for [logstash_system]:
Enter password for [beats_system]:
Reenter password for [beats_system]:
Enter password for [remote_monitoring_user]:
Reenter password for [remote_monitoring_user]:

Changed password for user [elastic]
Changed password for user [apm_system]
Changed password for user [kibana_system]
Changed password for user [logstash_system]
Changed password for user [beats_system]
Changed password for user [remote_monitoring_user]

This command can only be run once. Use elasticsearch-reset-password afterwards.


Resetting Passwords

Reset a password for any built-in user at any time:

# Auto-generate a new password
/usr/share/elasticsearch/bin/elasticsearch-reset-password -u elastic

# Set a specific password interactively
/usr/share/elasticsearch/bin/elasticsearch-reset-password -u elastic -i

Output:

Password for the [elastic] user successfully reset.
New value: Kx9q_T2bRwZ=aJnPm5vL

Configuring the kibana_system User for Kibana

Kibana connects to Elasticsearch using the kibana_system user. Add the credentials to kibana.yml:

# /etc/kibana/kibana.yml

elasticsearch.username: "kibana_system"
elasticsearch.password: "your-kibana-system-password"

Alternatively, store the password in the Kibana keystore:

/usr/share/kibana/bin/kibana-keystore add elasticsearch.password

Restart Kibana:

sudo systemctl restart kibana

Configuring Logstash to Authenticate

Logstash needs credentials for its Elasticsearch output plugin:

# /etc/logstash/conf.d/output.conf

output {
  elasticsearch {
    hosts => ["https://es-node-1:9200"]
    user => "logstash_writer"
    password => "strong-password-here"
    ssl_enabled => true
    ssl_certificate_authorities => ["/etc/logstash/certs/ca.crt"]
  }
}

Create a dedicated logstash_writer role and user:

# Create the role
curl -k -u elastic:password -X POST "https://localhost:9200/_security/role/logstash_writer" \
  -H "Content-Type: application/json" -d'
{
  "cluster": ["manage_index_templates", "monitor", "manage_ilm"],
  "indices": [
    {
      "names": ["logstash-*", "logs-*"],
      "privileges": ["write", "create_index", "manage", "auto_configure"]
    }
  ]
}'

# Create the user
curl -k -u elastic:password -X POST "https://localhost:9200/_security/user/logstash_writer" \
  -H "Content-Type: application/json" -d'
{
  "password": "strong-password-here",
  "roles": ["logstash_writer"],
  "full_name": "Logstash Writer"
}'

Configuring Beats to Authenticate

Filebeat and other Beats agents need credentials to send data to Elasticsearch:

# /etc/filebeat/filebeat.yml

output.elasticsearch:
  hosts: ["https://es-node-1:9200"]
  username: "filebeat_writer"
  password: "strong-password-here"
  ssl:
    enabled: true
    certificate_authorities: ["/etc/filebeat/certs/ca.crt"]

Create a dedicated Beats user:

curl -k -u elastic:password -X POST "https://localhost:9200/_security/user/filebeat_writer" \
  -H "Content-Type: application/json" -d'
{
  "password": "strong-password-here",
  "roles": ["editor"],
  "full_name": "Filebeat Writer"
}'

Verifying Security Is Working

1. Test without credentials (should fail):

curl -k https://localhost:9200/

Response:

{
  "error": {
    "type": "security_exception",
    "reason": "missing authentication credentials for REST request [/]"
  },
  "status": 401
}

2. Test with valid credentials (should succeed):

curl -k -u elastic:your-password https://localhost:9200/

Response:

{
  "name": "es-node-1",
  "cluster_name": "production",
  "cluster_uuid": "abc123",
  "version": {
    "number": "8.15.0"
  },
  "tagline": "You Know, for Search"
}

3. Verify authenticated user:

curl -k -u elastic:your-password https://localhost:9200/_security/_authenticate

Response:

{
  "username": "elastic",
  "roles": ["superuser"],
  "full_name": null,
  "email": null,
  "authentication_realm": {
    "name": "reserved",
    "type": "reserved"
  },
  "enabled": true
}

Quick Reference

Task Command / Setting
Enable security xpack.security.enabled: true in elasticsearch.yml
Generate Kibana enrollment token elasticsearch-create-enrollment-token -s kibana
Generate node enrollment token elasticsearch-create-enrollment-token -s node
Set built-in passwords (first time) elasticsearch-setup-passwords interactive
Reset a user password elasticsearch-reset-password -u <user>
Configure Kibana credentials elasticsearch.username / elasticsearch.password in kibana.yml
Logstash authentication user / password in elasticsearch output plugin
Beats authentication username / password under output.elasticsearch
Verify authentication curl -u user:pass https://host:9200/_security/_authenticate

Next: TLS/SSL — encrypt all communication in your cluster.