Munin is a networked resource monitoring tool that uses RRDtool for data storage and graphing. It consists of a master server that polls nodes (munin-nodes) for metrics. This guide covers security measures for production Munin deployments.
Munin architecture includes these security-sensitive components:
Key security concerns include node authentication, plugin execution security, web interface protection, and preventing information disclosure through metrics.
Configure firewall rules for Munin:
# Munin Master web interface
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
# Munin Node (default port 4949)
ufw allow from 10.0.1.0/24 to any port 4949 proto tcp
# Block external access
ufw deny from any to any port 4949 proto tcp
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: munin-network-policy
spec:
podSelector:
matchLabels:
app: munin-node
ingress:
- from:
- podSelector:
matchLabels:
app: munin-master
ports:
- protocol: TCP
port: 4949
Configure Munin node binding:
# /etc/munin/munin-node.conf
# Bind to specific interface
host *
# Or restrict to specific IP
# host 10.0.1.100
# Allowed hosts (master IPs)
allow ^10\.0\.1\.100$
allow ^10\.0\.1\.$
# Port
port 4949
Configure Munin master:
# /etc/munin/munin.conf
# Graph and HTML output
htmldir /var/cache/munin/www
logdir /var/log/munin
rundir /var/run/munin
dbdir /var/lib/munin
# CGI configuration
cgiurl /cgi-bin/munin-cgi-graph
Configure HTTP authentication:
Apache:
# /etc/apache2/conf-available/munin.conf
Alias /munin /var/cache/munin/www
<Directory /var/cache/munin/www>
AuthType Basic
AuthName "Munin Access"
AuthUserFile /etc/munin/.htpasswd
Require valid-user
# Also restrict by IP
Require ip 10.0.0.0/8 192.168.0.0/16
</Directory>
# CGI authentication
ScriptAlias /cgi-bin/munin-cgi-graph /usr/lib/munin/cgi/munin-cgi-graph
<Directory /usr/lib/munin/cgi>
AuthType Basic
AuthName "Munin CGI"
AuthUserFile /etc/munin/.htpasswd
Require valid-user
Require ip 10.0.0.0/8
</Directory>
Nginx:
# /etc/nginx/sites-available/munin
location /munin/ {
auth_basic "Munin Access";
auth_basic_user_file /etc/munin/.htpasswd;
alias /var/cache/munin/www/;
}
location /cgi-bin/munin-cgi-graph {
auth_basic "Munin CGI";
auth_basic_user_file /etc/munin/.htpasswd;
include fastcgi_params;
fastcgi_pass unix:/var/run/munin/fastcgi-munin-graph.sock;
}
Manage users:
# Create admin user
htpasswd -c /etc/munin/.htpasswd admin
# Add additional users
htpasswd /etc/munin/.htpasswd username
Configure munin-node access control:
# /etc/munin/munin-node.conf
# Only allow specific master hosts
allow ^10\.0\.1\.100$
allow ^10\.0\.2\.$
# Deny all others by default
deny ^.*$
Restrict plugin execution:
# /etc/munin/munin-node.conf
# Limit which plugins can be executed
# By default, only plugins in /etc/munin/plugins/ are allowed
# For sensitive plugins, use sudo
# /etc/sudoers.d/munin-plugins
munin-node ALL=(ALL) NOPASSWD: /usr/lib/munin/plugins/mysql_*
munin-node ALL=(ALL) NOPASSWD: /usr/lib/munin/plugins/postgres_*
For SSH-based munin communication:
# Configure SSH key for munin
ssh-keygen -t ed25519 -f /etc/munin/ssh/munin_key -N ""
# Add to authorized_keys on nodes with restrictions
cat >> /home/munin/.ssh/authorized_keys << EOF
command="/usr/sbin/munin-node",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty ssh-ed25519 AAAA...
EOF
Secure munin-node with stunnel:
# /etc/stunnel/munin-node.conf
[munin]
accept = 4949
connect = 127.0.0.1:4949
cert = /etc/munin/ssl/munin-node.crt
key = /etc/munin/ssl/munin-node.key
cafile = /etc/munin/ssl/ca.crt
verify = 2
Configure munin-node to listen on localhost:
# /etc/munin/munin-node.conf
host 127.0.0.1
port 4949
Master configuration for TLS:
# /etc/munin/munin.conf
[master-node]
address 10.0.1.50
port 4949
use_ssh no
# For stunnel, connect to TLS port
Generate certificates:
# Create CA
openssl genrsa -out ca.key 4096
openssl req -new -x509 -days 3650 -key ca.key -out ca.crt \
-subj "/CN=Munin CA/O=Company"
# Create node certificate
openssl genrsa -out munin-node.key 2048
openssl req -new -key munin-node.key -out munin-node.csr \
-subj "/CN=munin-node.company.com"
openssl x509 -req -days 365 -in munin-node.csr \
-CA ca.crt -CAkey ca.key -CAcreateserial \
-out munin-node.crt
Configure HTTPS for Munin:
Apache:
# /etc/apache2/sites-available/munin-ssl.conf
<VirtualHost *:443>
ServerName munin.company.com
SSLEngine on
SSLCertificateFile /etc/ssl/certs/munin.crt
SSLCertificateKeyFile /etc/ssl/private/munin.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
# 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"
Alias /munin /var/cache/munin/www
<Directory /var/cache/munin/www>
AuthType Basic
AuthName "Munin Access"
AuthUserFile /etc/munin/.htpasswd
Require valid-user
</Directory>
</VirtualHost>
Secure plugin execution:
# /etc/munin/munin-node.conf
# Only allow specific plugins
# user_config=yes allows plugins to be configured per-user
# Restrict plugin directory
plugin_dir /etc/munin/plugins
# Disable dangerous plugins
# [mysql_*]
# disable = yes
Secure sensitive plugins:
#!/bin/bash
# /etc/munin/plugins/mysql_secure
# Wrapper for MySQL monitoring with restricted access
if [ "$1" = "config" ]; then
echo "graph_title MySQL Status"
echo "graph_category database"
exit 0
fi
# Use credentials from secure file
MYSQL_CREDENTIALS=$(cat /etc/munin/.mysql_credentials | gpg -d 2>/dev/null)
mysql -e "SHOW STATUS" $MYSQL_CREDENTIALS
Restrict graph access:
# /etc/apache2/conf-available/munin.conf
# Restrict access to specific graph categories
<Location /munin/localdomain>
Require valid-user
</Location>
<Location /munin/localhost>
Require valid-user
Require ip 10.0.1.0/24
</Location>
Secure CGI execution:
# /etc/munin/munin.conf
# CGI configuration
cgiurl /cgi-bin/munin-cgi-graph
cgiurl_graph /cgi-bin/munin-cgi-graph
# Restrict CGI access
# In Apache config
<Directory /usr/lib/munin/cgi>
Options +ExecCGI
AddHandler cgi-script .cgi
Require valid-user
</Directory>
Secure Munin files:
# Munin master files
chown -R munin:munin /var/lib/munin
chmod -R 750 /var/lib/munin
chown -R munin:munin /var/cache/munin
chmod -R 755 /var/cache/munin
chown root:munin /etc/munin
chmod -R 750 /etc/munin
# Munin node files
chown root:root /etc/munin/munin-node.conf
chmod 640 /etc/munin/munin-node.conf
chown -R munin:munin /var/log/munin
chmod -R 750 /var/log/munin
Protect RRD data files:
# Set restrictive permissions
chown -R munin:munin /var/lib/munin/rrd
chmod -R 750 /var/lib/munin/rrd
# Use encrypted filesystem for RRD storage
# Mount /var/lib/munin on encrypted volume
Protect Munin configuration:
# Master configuration
chown root:munin /etc/munin/munin.conf
chmod 640 /etc/munin/munin.conf
# Node configuration
chown root:root /etc/munin/munin-node.conf
chmod 640 /etc/munin/munin-node.conf
# Plugin configurations
chown root:munin /etc/munin/plugin-conf.d/
chmod -R 750 /etc/munin/plugin-conf.d/
Secure plugin credentials:
# Store credentials securely
cat > /etc/munin/plugin-conf.d/mysql << EOF
[mysql_*]
env.mysqluser monitor
env.mysqlpassword ${MYSQL_PASSWORD}
env.mysqlconnection mysql://localhost
EOF
chown root:munin /etc/munin/plugin-conf.d/mysql
chmod 640 /etc/munin/plugin-conf.d/mysql
Use environment variables:
# /etc/default/munin-node
MYSQL_PASSWORD="${MYSQL_PASSWORD}"
POSTGRES_PASSWORD="${POSTGRES_PASSWORD}"
Secure Munin logs:
# Set restrictive permissions
chown munin:adm /var/log/munin/
chmod 750 /var/log/munin/
# Configure log rotation
cat > /etc/logrotate.d/munin << EOF
/var/log/munin/*.log {
weekly
rotate 4
compress
delaycompress
missingok
notifempty
create 640 munin adm
}
EOF
Enable logging:
# /etc/munin/munin-node.conf
log_level 5
log_file /var/log/munin/munin-node.log
# /etc/munin/munin.conf
# Master logging is configured in munin-update
log_file /var/log/munin/munin-update.log
Configure web server access logging:
# /etc/apache2/sites-available/munin.conf
CustomLog /var/log/apache2/munin_access.log combined
ErrorLog /var/log/apache2/munin_error.log
Monitor Munin for security events:
#!/bin/bash
# /usr/local/bin/check-munin-security.sh
# Check for unauthorized access attempts
grep -c "connection from.*denied" /var/log/munin/munin-node.log
if [ $? -gt 10 ]; then
echo "CRITICAL: Multiple denied connections to munin-node"
exit 2
fi
# Check for configuration changes
find /etc/munin -mmin -60 -type f
if [ $? -eq 0 ]; then
echo "WARNING: Munin configuration modified"
exit 1
fi
Forward logs to SIEM:
# /etc/rsyslog.d/munin.conf
:programname, isequal, "munin-node" /var/log/munin/node.log
:programname, isequal, "munin-node" @siem.company.com:514
:programname, isequal, "munin-update" @siem.company.com:514