Thruk is a modern web interface for Nagios, Icinga, Naemon, and Shinken monitoring systems. It provides a responsive interface with advanced features like reporting, dashboards, and mobile support. As a gateway to monitoring configuration and control, Thruk requires proper security hardening. This guide covers security measures for production Thruk deployments.
Thruk architecture includes these security-sensitive components:
Key security concerns include web interface protection, Livestatus access control, authentication security, API access control, and preventing unauthorized monitoring changes.
Configure firewall rules for Thruk:
# Thruk web interface (Apache/Nginx)
ufw allow from 10.0.0.0/8 to any port 80 proto tcp
ufw allow from 10.0.0.0/8 to any port 443 proto tcp
# Livestatus (if exposed directly)
ufw allow from 127.0.0.1 to any port 6557 proto tcp
# Block external access
ufw deny from any to any port 6557 proto tcp
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: thruk-network-policy
spec:
podSelector:
matchLabels:
app: thruk
ingress:
- from:
- namespaceSelector:
matchLabels:
name: monitoring
ports:
- protocol: TCP
port: 80
- protocol: TCP
port: 443
Configure web server binding:
# /etc/apache2/sites-available/thruk.conf
<VirtualHost 10.0.1.100:443>
ServerName thruk.company.com
DocumentRoot /usr/share/thruk/www
SSLEngine on
SSLCertificateFile /etc/ssl/certs/thruk.crt
SSLCertificateKeyFile /etc/ssl/private/thruk.key
<Directory /usr/share/thruk/www>
Require ip 10.0.0.0/8 192.168.0.0/16
Options None
AllowOverride None
</Directory>
</VirtualHost>
Configure Livestatus binding:
# /etc/thruk/thruk.conf
livestatus = {
'peer' => '/var/cache/nagios/rw/live', # Unix socket
# Or TCP with restriction
# 'peer' => 'tcp:127.0.0.1:6557',
}
Configure Thruk authentication:
# /etc/thruk/thruk.conf
# Multiple authentication backends
auth_type = "Apache"
auth_realm = "Thruk Monitoring"
# Session settings
session_timeout = 3600
session_secure = 1
session_httponly = 1
Configure Thruk roles:
# /etc/thruk/thruk.conf
roles = {
'admin' => {
'master' => 1,
},
'operator' => {
'read' => 1,
'write' => ['ack', 'downtime', 'schedule_check', 'comment'],
},
'viewer' => {
'read' => 1,
},
'guest' => {
'read' => 1,
'restricted' => 1, # Limited view
},
}
# User mappings
users = {
'admin' => ['admin', 'ops-lead'],
'operator' => ['operator1', 'operator2'],
'viewer' => ['viewer1', 'viewer2'],
}
Configure LDAP authentication:
# /etc/thruk/thruk.conf
auth_type = "LDAP"
ldap_host = "ldap.company.com"
ldap_port = 636
ldap_ssl = 1
ldap_binddn = "cn=thruk,ou=services,dc=company,dc=com"
ldap_bindpw = "${LDAP_PASSWORD}"
ldap_base = "dc=company,dc=com"
ldap_filter = "(objectClass=inetOrgPerson)"
ldap_uidattr = "uid"
ldap_nameattr = "cn"
ldap_mailattr = "mail"
Configure AD authentication:
# /etc/thruk/thruk.conf
auth_type = "AD"
ad_domain = "company.com"
ad_host = "dc.company.com"
ad_port = 636
ad_ssl = 1
ad_binddn = "cn=thruk,ou=services,dc=company,dc=com"
ad_bindpw = "${AD_PASSWORD}"
ad_base = "dc=company,dc=com"
ad_filter = "(&(objectClass=user)(objectCategory=person))"
ad_uidattr = "sAMAccountName"
ad_nameattr = "displayName"
Configure SAML/OIDC authentication:
# /etc/thruk/thruk.conf
auth_type = "OpenID"
openid_provider = "https://sso.company.com"
openid_client_id = "thruk"
openid_client_secret = "${OIDC_CLIENT_SECRET}"
openid_redirect_uri = "https://thruk.company.com/thruk/"
openid_scope = "openid profile email"
Configure HTTPS:
# /etc/apache2/sites-available/thruk-ssl.conf
<VirtualHost *:443>
ServerName thruk.company.com
DocumentRoot /usr/share/thruk/www
SSLEngine on
SSLCertificateFile /etc/ssl/certs/thruk.crt
SSLCertificateKeyFile /etc/ssl/private/thruk.key
SSLCertificateChainFile /etc/ssl/certs/ca-bundle.crt
SSLProtocol all -SSLv2 -SSLv3 -TLSv1 -TLSv1.1
SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256
SSLHonorCipherOrder on
# Security headers
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
Header always set X-Frame-Options "SAMEORIGIN"
Header always set X-Content-Type-Options "nosniff"
Header always set X-XSS-Protection "1; mode=block"
Header always set Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src * data:; font-src 'self' data:; connect-src 'self'"
<Directory /usr/share/thruk/www>
Options None
AllowOverride None
Require all granted
</Directory>
</VirtualHost>
Secure Livestatus connections:
# /etc/thruk/thruk.conf
livestatus = {
'peer' => 'ssl:127.0.0.1:6557',
'ssl_verify' => 1,
'ssl_ca_file' => '/etc/thruk/ssl/ca.crt',
'ssl_cert_file' => '/etc/thruk/ssl/thruk.crt',
'ssl_key_file' => '/etc/thruk/ssl/thruk.key',
}
Generate and manage certificates:
# Generate self-signed certificate
openssl req -new -x509 -days 365 -nodes \
-out /etc/ssl/certs/thruk.crt \
-keyout /etc/ssl/private/thruk.key \
-subj "/CN=thruk.company.com/O=Company"
# Or use Let's Encrypt
certbot --apache -d thruk.company.com
Secure Livestatus access:
# Nagios/Icinga Livestatus configuration
# /etc/nagios/modules/livestatus.cfg
load module=/usr/lib/nagios/modules/livestatus.so
livestatus_socket=tcp:127.0.0.1:6557
livestatus_allowed_clients=127.0.0.1,10.0.1.100
Secure Thruk API access:
| Endpoint | Risk Level | Access Control |
|---|---|---|
GET /thruk/api/status |
Low | Authenticated |
GET /thruk/api/hosts |
Low | Authenticated |
POST /thruk/api/command |
High | Operator+ |
PUT /thruk/api/config |
Critical | Admin only |
DELETE /thruk/api/host |
Critical | Admin only |
Implement API rate limiting:
# Nginx rate limiting for Thruk API
limit_req_zone $binary_remote_addr zone=thruk_api:10m rate=30r/s;
location /thruk/api/ {
limit_req zone=thruk_api burst=50 nodelay;
proxy_pass http://localhost:80;
}
Restrict monitoring commands:
# /etc/thruk/thruk.conf
# Restrict available commands
allowed_commands = [
'SCHEDULE_SVC_CHECK',
'SCHEDULE_HOST_CHECK',
'ACKNOWLEDGE_SVC_PROBLEM',
'ACKNOWLEDGE_HOST_PROBLEM',
'SCHEDULE_SVC_DOWNTIME',
'SCHEDULE_HOST_DOWNTIME',
'ADD_SVC_COMMENT',
'ADD_HOST_COMMENT',
];
# Deny dangerous commands
denied_commands = [
'SHUTDOWN_PROGRAM',
'RESTART_PROGRAM',
'SAVE_STATE_INFORMATION',
'READ_STATE_INFORMATION',
];
Configure web UI security:
# /etc/thruk/thruk.conf
# Security settings
disable_xss_protection = 0
enable_clickjacking_protection = 1
content_security_policy = "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'"
Protect Thruk configuration:
# Set restrictive permissions
chown root:www-data /etc/thruk/thruk.conf
chmod 640 /etc/thruk/thruk.conf
# Encrypt sensitive configuration
gpg -c /etc/thruk/thruk.conf
Secure sensitive credentials:
# /etc/thruk/thruk.conf
# Use environment variables
ldap_bindpw = $ENV{THRUK_LDAP_PASSWORD}
ad_bindpw = $ENV{THRUK_AD_PASSWORD}
openid_client_secret = $ENV{THRUK_OIDC_SECRET}
# Or use external secrets file
# include /etc/thruk/secrets.conf
Protect secrets file:
# Set restrictive permissions
chown root:www-data /etc/thruk/secrets.conf
chmod 640 /etc/thruk/secrets.conf
Configure secure sessions:
# /etc/thruk/thruk.conf
session_timeout = 3600
session_secure = 1
session_httponly = 1
session_samesite = "Strict"
# Session storage
session_storage = "DBI"
session_dbi_dsn = "dbi:SQLite:dbname=/var/lib/thruk/sessions.db"
Secure report data:
# /etc/thruk/thruk.conf
# Restrict report access
report_access = {
'admin' => ['all'],
'operator' => ['availability', 'sla'],
'viewer' => ['availability'],
}
# Encrypt stored reports
report_encryption = 1
report_encryption_key = "${REPORT_ENCRYPTION_KEY}"
Enable logging:
# /etc/thruk/thruk.conf
log_file = "/var/log/thruk/thruk.log"
log_level = "info"
# Audit logging
audit_log = "/var/log/thruk/audit.log"
audit_commands = 1
audit_logins = 1
audit_config_changes = 1
Configure web server access logging:
# /etc/apache2/sites-available/thruk.conf
CustomLog /var/log/apache2/thruk_access.log combined
ErrorLog /var/log/apache2/thruk_error.log
# Separate admin logging
CustomLog /var/log/apache2/thruk_admin_access.log combined env=admin
SetEnvIf Request_URI "^/thruk/admin" admin
Monitor Thruk for security events:
# /etc/thruk/thruk.conf
# Alert on security events
alert_on_failed_login = 1
alert_on_failed_login_threshold = 5
alert_on_command_execution = 1
alert_on_config_change = 1
alert_recipients = ['security@company.com']
Forward logs to SIEM:
# /etc/rsyslog.d/thruk.conf
:programname, isequal, "thruk" /var/log/thruk/syslog.log
:programname, isequal, "thruk" @siem.company.com:514