Nagios is a widely-deployed monitoring solution with privileged visibility into infrastructure and command execution capabilities. Proper security hardening is essential to protect the monitoring system and prevent unauthorized access to sensitive operational data. This guide covers security measures for production Nagios deployments.
Nagios architecture includes several security-sensitive components:
Key security concerns include web interface protection, plugin execution security, remote command execution, and credential management.
Configure firewall rules for Nagios components:
# Nagios Web Interface (Apache)
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
# NRPE Agent
ufw allow from 10.0.1.0/24 to any port 5666 proto tcp
# NSCA Passive Checks
ufw allow from 10.0.1.0/24 to any port 5667 proto tcp
# Block external access
ufw deny from any to any port 5666 proto tcp
ufw deny from any to any port 5667 proto tcp
Network Architecture:
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Monitored │ │ Management │ │ Admin │
│ Network │ │ Network │ │ Network │
│ │ │ │ │ │
│ NRPE Agents │───▶│ Nagios Server │◀───│ Admin Workstations│
│ (Port 5666) │ │ (Web: 443) │ │ (SSH Access) │
└─────────────────┘ └─────────────────┘ └─────────────────┘
Configure Nagios web interface binding:
# /etc/apache2/sites-available/nagios.conf
<VirtualHost 10.0.1.100:443>
ServerName nagios.company.com
DocumentRoot /usr/share/nagios3/htdocs
SSLEngine on
SSLCertificateFile /etc/ssl/certs/nagios.crt
SSLCertificateKeyFile /etc/ssl/private/nagios.key
<Directory /usr/share/nagios3/htdocs>
Require ip 10.0.0.0/8 192.168.0.0/16
Options None
AllowOverride None
</Directory>
</VirtualHost>
Configure NRPE binding:
# /etc/nagios/nrpe.cfg
server_address=10.0.1.100
server_port=5666
allowed_hosts=10.0.1.0/24
Configure HTTP authentication:
# /etc/apache2/conf-available/nagios3.conf
<Directory /usr/share/nagios3/htdocs>
AuthType Basic
AuthName "Nagios Access"
AuthUserFile /etc/nagios3/htpasswd.users
Require valid-user
# Restrict by IP as well
Require ip 10.0.0.0/8
</Directory>
Manage users:
# Create initial admin user
htpasswd -c /etc/nagios3/htpasswd.users nagiosadmin
# Add additional users
htpasswd /etc/nagios3/htpasswd.users username
Configure role-based notifications:
# /etc/nagios3/conf.d/contacts.cfg
define contact {
contact_name admin
alias System Administrator
service_notification_period 24x7
host_notification_period 24x7
service_notification_options w,u,c,r
host_notification_options d,u,r
service_notification_commands notify-service-by-email
host_notification_commands notify-host-by-email
email admin@company.com
}
define contactgroup {
contactgroup_name admins
alias Nagios Administrators
members admin,ops-lead
}
Restrict command execution:
# /etc/nagios3/conf.d/commands.cfg
define command {
command_name check_ssh
command_line $USER1$/check_ssh -H $HOSTADDRESS$
}
# Restrictive command definitions
define command {
command_name restart-service
command_line /usr/local/bin/safe-restart.sh $ARG1$
}
Configure external authentication:
Apache mod_auth_openidc:
LoadModule auth_openidc_module modules/mod_auth_openidc.so
OIDCProviderMetadataURL https://sso.company.com/.well-known/openid-configuration
OIDCClientID nagios
OIDCClientSecret ${OIDC_CLIENT_SECRET}
OIDCRedirectURI https://nagios.company.com/redirect_uri
OIDCCryptoPassphrase your-secret-passphrase
<Location /nagios>
AuthType openid-connect
Require valid-user
</Location>
LDAP Authentication:
LoadModule authnz_ldap_module modules/mod_authnz_ldap.so
<Location /nagios>
AuthType Basic
AuthName "Nagios LDAP"
AuthBasicProvider ldap
AuthLDAPURL "ldaps://ldap.company.com/dc=company,dc=com?uid?sub"
AuthLDAPBindDN "cn=nagios,ou=services,dc=company,dc=com"
AuthLDAPBindPassword "${LDAP_PASSWORD}"
Require valid-user
</Location>
Enable two-factor authentication:
Google Authenticator with PAM:
# Install and configure
apt install libpam-google-authenticator
google-authenticator
# Configure PAM
cat >> /etc/pam.d/nagios << EOF
auth required pam_google_authenticator.so
EOF
Configure HTTPS for Nagios web interface:
# /etc/apache2/sites-available/nagios-ssl.conf
<VirtualHost *:443>
ServerName nagios.company.com
DocumentRoot /usr/share/nagios3/htdocs
SSLEngine on
SSLCertificateFile /etc/ssl/certs/nagios.crt
SSLCertificateKeyFile /etc/ssl/private/nagios.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'; style-src 'self' 'unsafe-inline'"
<Directory /usr/share/nagios3/htdocs>
Options None
AllowOverride None
Require valid-user
</Directory>
</VirtualHost>
Enable TLS for NRPE communications:
# /etc/nagios/nrpe.cfg
ssl_enabled=1
ssl_cert=/etc/nagios/ssl/nrpe.crt
ssl_key=/etc/nagios/ssl/nrpe.key
ssl_ca_cert=/etc/nagios/ssl/ca.crt
ssl_cipher_list="ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256"
ssl_legacy_options=0
# Require client certificate verification
ssl_client_cert_verify=1
Configure encryption for passive checks:
# /etc/nagios/nsca.cfg
encryption_method=AES256
password=${NSCA_PASSWORD}
Submit encrypted check results:
echo -e "hostname\tservice\tstatus\toutput" | \
send_nsca -H nagios.company.com -c /etc/nagios/nsca.cfg
Secure CGI access in Nagios:
# /etc/nagios3/cgi.cfg
use_authentication=1
default_user_name=nagiosviewer
authorized_for_system_information=admin,ops-lead
authorized_for_configuration_information=admin
authorized_for_system_commands=admin
authorized_for_all_services=admin,ops-lead
authorized_for_all_hosts=admin,ops-lead
authorized_for_all_service_commands=admin
authorized_for_all_host_commands=admin
Restrict plugin execution:
# /etc/nagios/resource.cfg
# Only allow specific plugin directories
$USER1$=/usr/lib/nagios/plugins
$USER2$=/usr/local/nagios/libexec
# Never store passwords in resource.cfg
# Use environment variables or secret management
Secure plugin permissions:
# Set restrictive permissions on plugins
chown root:nagios /usr/lib/nagios/plugins/*
chmod 750 /usr/lib/nagios/plugins/*
# Special handling for sensitive plugins
chown root:root /usr/lib/nagios/plugins/check_mysql
chmod 700 /usr/lib/nagios/plugins/check_mysql
Disable or restrict remote commands:
# /etc/nagios3/nagios.cfg
# Disable external commands by default
check_external_commands=0
# If needed, restrict command file permissions
command_file=/var/cache/nagios3/rw/nagios.cmd
command_check_interval=15s
Secure command file:
# Set restrictive permissions
chown nagios:nagios /var/cache/nagios3/rw/nagios.cmd
chmod 660 /var/cache/nagios3/rw/nagios.cmd
Protect Nagios configuration:
# Restrict configuration file access
chown -R nagios:nagios /etc/nagios3/
chmod -R 750 /etc/nagios3/
# Encrypt sensitive configuration files
# Use GPG for password files
gpg -c /etc/nagios3/conf.d/passwords.cfg
Never store plaintext credentials:
# Bad - Never do this
# define command {
# command_name check_mysql
# command_line $USER1$/check_mysql -u root -pPassword123
# }
# Good - Use environment variables
define command {
command_name check_mysql
command_line $USER1$/check_mysql -u $ARG1$
}
# Set via secure wrapper script
#!/bin/bash
export MYSQL_PWD=$(cat /etc/nagios/.mysql_password | gpg -d)
exec /usr/lib/nagios/plugins/check_mysql "$@"
Secure log files and archives:
# Restrict log file access
chown nagios:nagios /var/log/nagios3/
chmod 750 /var/log/nagios3/
# Encrypt log archives
find /var/log/nagios3/archives -name "*.gz" -exec gpg -e --recipient security@company.com {} \;
Secure Nagios backups:
#!/bin/bash
# Secure backup script
BACKUP_DIR="/secure/backups/nagios"
DATE=$(date +%Y%m%d)
tar -czf ${BACKUP_DIR}/nagios-config-${DATE}.tar.gz \
/etc/nagios3/ \
/var/lib/nagios3/
# Encrypt backup
gpg -e --recipient security@company.com ${BACKUP_DIR}/nagios-config-${DATE}.tar.gz
# Set restrictive permissions
chmod 600 ${BACKUP_DIR}/nagios-config-${DATE}.tar.gz.gpg
# Remove unencrypted backup
rm ${BACKUP_DIR}/nagios-config-${DATE}.tar.gz
Enable logging:
# /etc/nagios3/nagios.cfg
log_file=/var/log/nagios3/nagios.log
debug_level=63
debug_verbosity=2
debug_file=/var/log/nagios3/nagios.debug
# Log rotation
log_rotation_method=d
log_archive_path=/var/log/nagios3/archives
Configure web server access logging:
# /etc/apache2/sites-available/nagios.conf
CustomLog /var/log/apache2/nagios_access.log combined
ErrorLog /var/log/apache2/nagios_error.log
# Log format with timing
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %D" combined
Monitor Nagios for security events:
# /etc/nagios3/conf.d/security.cfg
define service {
host_name nagios-server
service_description Failed Login Attempts
check_command check_log!5!/var/log/apache2/nagios_access.log!"authentication failure"
max_check_attempts 3
check_interval 5
notification_interval 30
notification_period 24x7
notification_options c,w
contacts security-team
}
define service {
host_name nagios-server
service_description Configuration Changes
check_command check_file_age!/etc/nagios3/nagios.cfg!3600!7200
max_check_attempts 1
check_interval 60
notification_options c,w
contacts ops-team
}
Forward logs to SIEM:
# /etc/rsyslog.d/nagios.conf
:programname, isequal, "nagios3" /var/log/nagios3/syslog.log
:programname, isequal, "nagios3" @siem.company.com:514
# Apache logs
/var/log/apache2/nagios_access.log @siem.company.com:514