Configure Kibana alerting rules and Elasticsearch Watcher to automatically detect security threats and send notifications via email or Slack. Set up monitoring dashboards with automated responses for production security monitoring.
Prerequisites
- Root or sudo access
- 4GB RAM minimum
- Java 11 or later
- Network access for package installation
- Email account for notifications
What this solves
Kibana alerting with Elasticsearch Watcher enables automated threat detection by monitoring log patterns, security events, and system metrics in real-time. This setup automatically triggers notifications when suspicious activities are detected, helping security teams respond quickly to potential threats. You'll configure email and Slack integrations, create monitoring dashboards, and implement automated responses for comprehensive security monitoring.
Step-by-step configuration
Update system packages
Start by updating your system packages to ensure you have the latest security patches and package definitions.
sudo apt update && sudo apt upgrade -y
Install required dependencies
Install Java, curl, and other dependencies needed for Elasticsearch and Kibana operations.
sudo apt install -y openjdk-11-jdk curl wget gnupg apt-transport-https
Add Elasticsearch repository
Add the official Elasticsearch repository to install the latest stable version with Watcher support.
wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo gpg --dearmor -o /usr/share/keyrings/elasticsearch-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/elasticsearch-keyring.gpg] https://artifacts.elastic.co/packages/8.x/apt stable main" | sudo tee /etc/apt/sources.list.d/elastic-8.x.list
sudo apt update
Install Elasticsearch and Kibana
Install Elasticsearch with Watcher capabilities and Kibana for the web interface and alerting configuration.
sudo apt install -y elasticsearch kibana
Configure Elasticsearch for Watcher
Configure Elasticsearch with proper memory settings and enable Watcher for alerting functionality.
cluster.name: security-monitoring
node.name: watcher-node-1
network.host: localhost
http.port: 9200
discovery.type: single-node
Security settings
xpack.security.enabled: true
xpack.security.enrollment.enabled: true
xpack.security.http.ssl.enabled: false
xpack.security.transport.ssl.enabled: false
Watcher settings
xpack.watcher.enabled: true
xpack.notification.email.default_account: gmail_account
Set JVM heap size for Elasticsearch
Configure JVM memory allocation for optimal Elasticsearch performance. Use half of available RAM, up to 32GB maximum.
-Xms2g
-Xmx2g
Configure Kibana settings
Configure Kibana to connect to Elasticsearch and enable alerting features with proper network settings.
server.port: 5601
server.host: "0.0.0.0"
server.name: "kibana-alerting"
elasticsearch.hosts: ["http://localhost:9200"]
Security settings
xpack.security.enabled: true
xpack.encryptedSavedObjects.encryptionKey: "a7a6311933d3503b89bc2dbc36572c33a6c10925682e591bffcab6911c06786d"
xpack.reporting.encryptionKey: "a7a6311933d3503b89bc2dbc36572c33a6c10925682e591bffcab6911c06786d"
xpack.security.encryptionKey: "a7a6311933d3503b89bc2dbc36572c33a6c10925682e591bffcab6911c06786d"
Alerting settings
xpack.actions.enabled: true
xpack.alerting.enabled: true
openssl rand -hex 32 for production environments.Set up email notification configuration
Configure email settings for Watcher notifications. This example uses Gmail SMTP with app-specific passwords.
# Email notification settings
xpack.notification.email.account:
gmail_account:
profile: gmail
smtp:
auth: true
starttls.enable: true
host: smtp.gmail.com
port: 587
user: "your-email@gmail.com"
password: "your-app-specific-password"
Create directory structure and set permissions
Create necessary directories and set proper ownership for Elasticsearch and Kibana services.
sudo mkdir -p /var/log/elasticsearch /var/log/kibana /etc/kibana/certs
sudo chown -R elasticsearch:elasticsearch /etc/elasticsearch /var/lib/elasticsearch /var/log/elasticsearch
sudo chown -R kibana:kibana /etc/kibana /var/log/kibana
sudo chmod 750 /etc/elasticsearch /etc/kibana
sudo chmod 640 /etc/elasticsearch/elasticsearch.yml /etc/kibana/kibana.yml
Start and enable services
Start Elasticsearch first, then Kibana, and enable them to start automatically on boot.
sudo systemctl daemon-reload
sudo systemctl enable elasticsearch
sudo systemctl start elasticsearch
sudo systemctl status elasticsearch
Wait for Elasticsearch to start, then start Kibana
sleep 30
sudo systemctl enable kibana
sudo systemctl start kibana
sudo systemctl status kibana
Configure built-in users and passwords
Set up the built-in Elasticsearch users with secure passwords for authentication.
sudo /usr/share/elasticsearch/bin/elasticsearch-setup-passwords interactive
Create Slack webhook integration
Configure Slack webhook for notifications. First, create an incoming webhook in your Slack workspace, then add the configuration.
# Slack notification settings
xpack.notification.slack:
account:
monitoring:
url: "https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK"
Create a sample threat detection watcher
Create a watcher that monitors for failed SSH login attempts and sends alerts when thresholds are exceeded.
curl -X PUT "localhost:9200/_watcher/watch/ssh_brute_force_detector" -H 'Content-Type: application/json' -u elastic:your-password -d'
{
"trigger": {
"schedule": {
"interval": "1m"
}
},
"input": {
"search": {
"request": {
"search_type": "query_then_fetch",
"indices": ["auth-*"],
"body": {
"size": 0,
"query": {
"bool": {
"must": [
{
"match": {
"message": "Failed password"
}
},
{
"range": {
"@timestamp": {
"gte": "now-5m"
}
}
}
]
}
},
"aggs": {
"failed_logins_by_ip": {
"terms": {
"field": "source_ip.keyword",
"size": 10
}
}
}
}
}
}
},
"condition": {
"compare": {
"ctx.payload.hits.total": {
"gt": 5
}
}
},
"actions": {
"send_email": {
"email": {
"profile": "gmail",
"to": ["security@example.com"],
"subject": "SSH Brute Force Attack Detected",
"body": "Multiple failed SSH login attempts detected. Total attempts: {{ctx.payload.hits.total}} in the last 5 minutes."
}
},
"send_slack": {
"slack": {
"account": "monitoring",
"message": {
"to": ["#security-alerts"],
"text": "🚨 SSH Brute Force Attack Detected: {{ctx.payload.hits.total}} failed attempts in 5 minutes"
}
}
}
}
}'
Create anomaly detection watcher
Set up a watcher to detect unusual network traffic patterns and potential DDoS attempts.
curl -X PUT "localhost:9200/_watcher/watch/network_anomaly_detector" -H 'Content-Type: application/json' -u elastic:your-password -d'
{
"trigger": {
"schedule": {
"interval": "2m"
}
},
"input": {
"search": {
"request": {
"indices": ["network-*"],
"body": {
"size": 0,
"query": {
"range": {
"@timestamp": {
"gte": "now-10m"
}
}
},
"aggs": {
"requests_per_minute": {
"date_histogram": {
"field": "@timestamp",
"fixed_interval": "1m"
}
}
}
}
}
}
},
"condition": {
"array_compare": {
"ctx.payload.aggregations.requests_per_minute.buckets": {
"path": "doc_count",
"gt": {
"value": 1000
}
}
}
},
"actions": {
"log_anomaly": {
"logging": {
"level": "warn",
"text": "Network anomaly detected: High traffic volume"
}
},
"notify_team": {
"email": {
"profile": "gmail",
"to": ["network-ops@example.com"],
"subject": "Network Traffic Anomaly Alert",
"body": "Unusual network traffic pattern detected. Review immediately."
}
}
}
}'
Set up Kibana alerting rules
Access Kibana web interface and create alerting rules through the UI. Open your browser to configure additional alerts.
# Get the Kibana enrollment token
sudo /usr/share/elasticsearch/bin/elasticsearch-create-enrollment-token -s kibana
Access Kibana at http://your-server-ip:5601
echo "Access Kibana at: http://$(hostname -I | awk '{print $1}'):5601"
Configure firewall rules
Open necessary ports for Kibana web interface while maintaining security.
sudo ufw allow 5601/tcp comment "Kibana web interface"
sudo ufw allow from 203.0.113.0/24 to any port 9200 comment "Elasticsearch API from trusted network"
sudo ufw reload
Configure monitoring dashboards
Create security monitoring dashboard
Set up comprehensive security monitoring dashboards in Kibana to visualize threats and alerts in real-time. This integrates with existing ELK stack configurations for comprehensive log analysis.
curl -X POST "localhost:9200/_template/security-monitoring" -H 'Content-Type: application/json' -u elastic:your-password -d'
{
"index_patterns": ["security-*"],
"mappings": {
"properties": {
"@timestamp": { "type": "date" },
"event_type": { "type": "keyword" },
"severity": { "type": "keyword" },
"source_ip": { "type": "ip" },
"destination_ip": { "type": "ip" },
"user_agent": { "type": "text" },
"status_code": { "type": "integer" },
"threat_score": { "type": "float" }
}
}
}'
Set up automated response actions
Configure automated responses that can block IPs or escalate alerts based on threat severity levels.
curl -X PUT "localhost:9200/_watcher/watch/automated_ip_blocker" -H 'Content-Type: application/json' -u elastic:your-password -d'
{
"trigger": {
"schedule": {
"interval": "30s"
}
},
"input": {
"search": {
"request": {
"indices": ["security-*"],
"body": {
"query": {
"bool": {
"must": [
{ "range": { "threat_score": { "gte": 8.0 } } },
{ "range": { "@timestamp": { "gte": "now-2m" } } }
]
}
},
"aggs": {
"top_threat_ips": {
"terms": {
"field": "source_ip",
"size": 5
}
}
}
}
}
}
},
"condition": {
"compare": {
"ctx.payload.hits.total": {
"gte": 1
}
}
},
"actions": {
"block_threat_ips": {
"webhook": {
"scheme": "http",
"host": "localhost",
"port": 8080,
"method": "post",
"path": "/api/block-ip",
"params": {},
"headers": {
"Content-Type": "application/json"
},
"body": "{{#ctx.payload.aggregations.top_threat_ips.buckets}}{{key}},{{/ctx.payload.aggregations.top_threat_ips.buckets}}"
}
},
"escalate_alert": {
"email": {
"profile": "gmail",
"to": ["security-team@example.com"],
"subject": "HIGH PRIORITY: Automated Threat Response Triggered",
"body": "Critical threats detected. Automated IP blocking initiated. Review security dashboard immediately."
}
}
}
}'
Verify your setup
Test your alerting configuration and verify all components are working correctly.
# Check Elasticsearch cluster health
curl -u elastic:your-password "localhost:9200/_cluster/health?pretty"
Verify Watcher is enabled
curl -u elastic:your-password "localhost:9200/_watcher/stats?pretty"
List active watchers
curl -u elastic:your-password "localhost:9200/_watcher/watch/_search?pretty"
Test email configuration
curl -X POST "localhost:9200/_watcher/watch/test_email/_execute" -u elastic:your-password
Check Kibana status
curl -u elastic:your-password "localhost:5601/api/status"
View system logs for any errors
sudo journalctl -u elasticsearch -f
sudo journalctl -u kibana -f
Common issues
| Symptom | Cause | Fix |
|---|---|---|
| Watcher execution fails | Incorrect email credentials or SMTP settings | Verify SMTP settings and use app-specific passwords for Gmail |
| Kibana cannot connect to Elasticsearch | Authentication issues or service not started | Check elasticsearch.yml security settings and restart services |
| Email notifications not received | Firewall blocking SMTP ports or spam filters | Test with curl -X POST localhost:9200/_watcher/watch/_execute |
| High memory usage | JVM heap size too large or small | Adjust heap size in /etc/elasticsearch/jvm.options.d/heap.options |
| Slack notifications failing | Invalid webhook URL or permissions | Verify Slack webhook URL and channel permissions |
| Permission denied errors | Incorrect file ownership or permissions | Fix with chown elasticsearch:elasticsearch and proper chmod values |
Next steps
- Secure Elasticsearch with SSL/TLS encryption and authentication
- Configure Kibana LDAP authentication and RBAC
- Implement Elasticsearch index lifecycle management
- Set up Elasticsearch cross-cluster replication for disaster recovery
- Configure Logstash security pipelines with threat intelligence enrichment
- Implement custom Kibana dashboards for threat hunting and incident response
Automated install script
Run this to automate the entire setup
#!/usr/bin/env bash
set -euo pipefail
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
# Global variables
ELASTICSEARCH_VERSION="8.x"
KIBANA_PASSWORD=""
ELASTIC_PASSWORD=""
# Usage function
usage() {
echo "Usage: $0 [OPTIONS]"
echo "Options:"
echo " -h, --help Show this help message"
echo " -v, --version VERSION Elasticsearch version (default: 8.x)"
echo ""
echo "Example: $0 --version 8.x"
exit 1
}
# Logging functions
log_info() { echo -e "${GREEN}[INFO]${NC} $1"; }
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
# Cleanup function
cleanup() {
log_error "Installation failed. Cleaning up..."
systemctl stop elasticsearch kibana 2>/dev/null || true
if [[ "$PKG_MGR" == "apt" ]]; then
apt-mark unhold elasticsearch kibana 2>/dev/null || true
fi
}
# Error trap
trap cleanup ERR
# Parse arguments
while [[ $# -gt 0 ]]; do
case $1 in
-h|--help)
usage
;;
-v|--version)
ELASTICSEARCH_VERSION="$2"
shift 2
;;
*)
log_error "Unknown option: $1"
usage
;;
esac
done
# Check prerequisites
if [[ $EUID -ne 0 ]]; then
log_error "This script must be run as root or with sudo"
exit 1
fi
# Detect distribution
if [ -f /etc/os-release ]; then
. /etc/os-release
case "$ID" in
ubuntu|debian)
PKG_MGR="apt"
PKG_INSTALL="apt install -y"
PKG_UPDATE="apt update"
;;
almalinux|rocky|centos|rhel|ol|fedora)
PKG_MGR="dnf"
PKG_INSTALL="dnf install -y"
PKG_UPDATE="dnf update -y"
;;
amzn)
PKG_MGR="yum"
PKG_INSTALL="yum install -y"
PKG_UPDATE="yum update -y"
;;
*)
log_error "Unsupported distribution: $ID"
exit 1
;;
esac
else
log_error "Cannot detect distribution. /etc/os-release not found."
exit 1
fi
log_info "Detected distribution: $ID using $PKG_MGR"
# Step 1: Update system packages
echo "[1/8] Updating system packages..."
$PKG_UPDATE
if [[ "$PKG_MGR" == "apt" ]]; then
apt upgrade -y
fi
# Step 2: Install required dependencies
echo "[2/8] Installing required dependencies..."
if [[ "$PKG_MGR" == "apt" ]]; then
$PKG_INSTALL openjdk-11-jdk curl wget gnupg apt-transport-https
else
$PKG_INSTALL java-11-openjdk curl wget gnupg
fi
# Verify Java installation
if ! java -version >/dev/null 2>&1; then
log_error "Java installation failed"
exit 1
fi
# Step 3: Add Elasticsearch repository
echo "[3/8] Adding Elasticsearch repository..."
if [[ "$PKG_MGR" == "apt" ]]; then
wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | gpg --dearmor -o /usr/share/keyrings/elasticsearch-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/elasticsearch-keyring.gpg] https://artifacts.elastic.co/packages/${ELASTICSEARCH_VERSION}/apt stable main" > /etc/apt/sources.list.d/elastic-${ELASTICSEARCH_VERSION}.list
chmod 644 /etc/apt/sources.list.d/elastic-${ELASTICSEARCH_VERSION}.list
apt update
else
rpm --import https://artifacts.elastic.co/GPG-KEY-elasticsearch
cat > /etc/yum.repos.d/elasticsearch.repo << EOF
[elasticsearch]
name=Elasticsearch repository for ${ELASTICSEARCH_VERSION} packages
baseurl=https://artifacts.elastic.co/packages/${ELASTICSEARCH_VERSION}/yum
gpgcheck=1
gpgkey=https://artifacts.elastic.co/GPG-KEY-elasticsearch
enabled=0
autorefresh=1
type=rpm-md
EOF
chmod 644 /etc/yum.repos.d/elasticsearch.repo
fi
# Step 4: Install Elasticsearch
echo "[4/8] Installing Elasticsearch..."
if [[ "$PKG_MGR" == "apt" ]]; then
$PKG_INSTALL elasticsearch
else
$PKG_INSTALL --enablerepo=elasticsearch elasticsearch
fi
# Step 5: Configure Elasticsearch
echo "[5/8] Configuring Elasticsearch..."
# Enable Watcher and set basic configuration
cat >> /etc/elasticsearch/elasticsearch.yml << EOF
# Watcher configuration
xpack.watcher.enabled: true
xpack.security.enabled: true
discovery.type: single-node
network.host: localhost
http.port: 9200
EOF
# Set proper permissions
chown root:elasticsearch /etc/elasticsearch/elasticsearch.yml
chmod 660 /etc/elasticsearch/elasticsearch.yml
# Step 6: Start and enable Elasticsearch
echo "[6/8] Starting Elasticsearch service..."
systemctl daemon-reload
systemctl enable elasticsearch
systemctl start elasticsearch
# Wait for Elasticsearch to start
sleep 30
# Reset elastic password and get it
echo "[7/8] Setting up Elasticsearch security..."
ELASTIC_PASSWORD=$(systemctl cat elasticsearch | grep -o 'ELASTIC_PASSWORD=.*' | cut -d'=' -f2 || echo "")
if [[ -z "$ELASTIC_PASSWORD" ]]; then
# Generate and set password
cd /usr/share/elasticsearch
ELASTIC_PASSWORD=$(bin/elasticsearch-reset-password -u elastic -b 2>/dev/null | grep "New value:" | awk '{print $3}' || openssl rand -base64 12)
echo "elastic:$ELASTIC_PASSWORD" | bin/elasticsearch-users useradd elastic -p -r superuser 2>/dev/null || true
fi
# Install and configure Kibana
$PKG_INSTALL kibana
# Configure Kibana
cat > /etc/kibana/kibana.yml << EOF
server.port: 5601
server.host: "localhost"
elasticsearch.hosts: ["http://localhost:9200"]
elasticsearch.username: "elastic"
elasticsearch.password: "$ELASTIC_PASSWORD"
xpack.security.enabled: true
xpack.watcher.ui.enabled: true
EOF
chown root:kibana /etc/kibana/kibana.yml
chmod 660 /etc/kibana/kibana.yml
# Step 8: Start Kibana and configure firewall
echo "[8/8] Starting Kibana and configuring firewall..."
systemctl enable kibana
systemctl start kibana
# Configure firewall based on distribution
if command -v firewall-cmd >/dev/null 2>&1; then
firewall-cmd --permanent --add-port=9200/tcp
firewall-cmd --permanent --add-port=5601/tcp
firewall-cmd --reload
elif command -v ufw >/dev/null 2>&1; then
ufw allow 9200/tcp
ufw allow 5601/tcp
fi
# Verification
echo "Verifying installation..."
sleep 20
if ! systemctl is-active --quiet elasticsearch; then
log_error "Elasticsearch is not running"
exit 1
fi
if ! systemctl is-active --quiet kibana; then
log_error "Kibana is not running"
exit 1
fi
if ! curl -s -u "elastic:$ELASTIC_PASSWORD" http://localhost:9200 >/dev/null; then
log_error "Cannot connect to Elasticsearch"
exit 1
fi
# Success message
log_info "Installation completed successfully!"
echo ""
echo "Access Information:"
echo " Elasticsearch: http://localhost:9200"
echo " Kibana: http://localhost:5601"
echo " Username: elastic"
echo " Password: $ELASTIC_PASSWORD"
echo ""
echo "Next steps:"
echo "1. Access Kibana at http://localhost:5601"
echo "2. Configure Watcher alerts in Stack Management > Watcher"
echo "3. Set up email/Slack notifications in Kibana settings"
echo ""
log_warn "Save the password above - you'll need it to access Kibana!"
Review the script before running. Execute with: bash install.sh