Perfect RootServer
der Server soll hauptsächlich als Web- und Mailserver dienen.
Grundkonfiguration
User anlegen
useradd -m -G root,staff -c "Adminuser" -s /bin/bash adminuser
useradd -m -G staff -c "User XYZ" -s /bin/bash user
Alias root to admin
#/etc/aliases
root: admin
Hardening
- http://www.thefanclub.co.za/how-to/how-secure-ubuntu-1204-lts-server-part-1-basics
- http://www.debian.org/doc/manuals/securing-debian-howto/ch4.de.html
Default umask
/etc/login.defs
# UMASK is the default umask value for pam_umask and is used by
# useradd and newusers to set the mode of the new home directories.
# 022 is the "historical" value in Debian for UMASK
# 027, or even 077, could be considered better for privacy
# There is no One True Answer here : each sysadmin must make up his/her
# mind.
UMASK 077
http://www.cyberciti.biz/tips/understanding-linux-unix-umask-value-usage.html
/etc/fstab
tmpfs /dev/shm tmpfs defaults,noexec,nosuid 0 0
/dev/vg0/tmp /tmp ext4 defaults,nodev,nosuid,noexec 0 0
/dev/vg0/var /var ext4 defaults,nodev 0 0
/dev/vg0/mysql /xxx/mysql ext4 defaults,nodev,nosuid,noexec 0 0
/dev/vg0/mail /xxx/mail ext4 defaults,nodev,nosuid,noexec 0 0
/dev/vg0/home /home ext4 defaults,nosuid,nodev 0 0
/dev/vg0/www /xxx/www ext4 defaults,nodev,nosuid,noexec 0 0
add /etc/apt/apt.conf.d/00tempdir
APT::ExtractTemplates::TempDir "/var/tmp";
SSH Hardening - disable root login and change port.
#/etc/ssh/sshd_config
Port 563
AllowGroups staff
PermitRootLogin no
Harden network with sysctl settings
#/etc/sysctl.conf
# IP Spoofing protection
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
# Ignore ICMP broadcast requests
net.ipv4.icmp_echo_ignore_broadcasts = 1
# Disable source packet routing
net.ipv4.conf.all.accept_source_route = 0
net.ipv6.conf.all.accept_source_route = 0
net.ipv4.conf.default.accept_source_route = 0
net.ipv6.conf.default.accept_source_route = 0
# Ignore send redirects
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
# Block SYN attacks
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 2048
net.ipv4.tcp_synack_retries = 2
net.ipv4.tcp_syn_retries = 5
# Log Martians
net.ipv4.conf.all.log_martians = 1
net.ipv4.icmp_ignore_bogus_error_responses = 1
# Ignore ICMP redirects
net.ipv4.conf.all.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv6.conf.default.accept_redirects = 0
Security
Chkrootkit
Checksecurity
Logcheck
Shorewall
-> Ziel, alles von aussen sperren, nach innen nur 'named' port, wie z.b. 22(ssh),25(smtp),80(http),443(https),993(imaps),995(pop3s) als Firewall wird shorewall (mit iptables/netfilter) verwendet.
Konfiguration
nach der Installation wird entsprechend konfiguriert. Folgendes geändert, der Rest default.
/etc/default/shorewall
# prevent startup with default configuration # set the below varible to 1 in order to allow shorewall to start startup=1
/etc/shorewall/shorewall.conf
#IP_FORWARDING=off #DISABLE_IPV6=yes
/etc/shorewall/interfaces
############################################################################## #ZONE INTERFACE BROADCAST OPTIONS net eth0 detect tcpflags,logmartians,nosmurfs
/etc/shorewall/policy (für das 'Normalverhalten')
############################################################################### #SOURCE DEST POLICY LOG LIMIT:BURST $FW net ACCEPT net all DROP #info # The FOLLOWING POLICY MUST BE LAST all all REJECT #info
/etc/shorewall/zones
#ZONE TYPE OPTIONS IN OUT # OPTIONS OPTIONS fw firewall net ipv4
/etc/shorewall/rules (was wir explizit erlauben wollen)
#################################################################################################### #ACTION SOURCE DEST PROTO DEST SOURCE ORIGINAL RATE USER/ # PORT PORT(S) DEST LIMIT GROUP SECTION NEW ACCEPT all fw tcp 563 #ACCEPT all fw tcp 22 ACCEPT all fw tcp 443 ACCEPT all fw tcp 80 ACCEPT all fw tcp 25 ACCEPT all fw tcp 993 ACCEPT all fw tcp 995 Ping(ACCEPT) all fw # Drop Ping from the "bad" net zone.. and prevent your log from being flooded.. #Ping(DROP) net $FW # Permit all ICMP traffic FROM the firewall TO the net zone ACCEPT $FW net icmp
/etc/shorewall/accounting
##################################################################################### #ACTION CHAIN SOURCE DESTINATION PROTO DEST SOURCE USER/ # PORT(S) PORT(S) GROUP mail - eth0 - tcp 25,993,995 mail - - eth0 tcp - 25,993,995 mail - - eth0 tcp 25,993,995 COUNT mail eth0 COUNT mail - eth0 ssh - eth0 - tcp 22,563 ssh - - eth0 tcp - 22,563 COUNT ssh eth0 COUNT ssh - eth0 ftp - eth0 - tcp 21,20,33000:33100 ftp - - eth0 tcp - 21,20,33000:33100 COUNT ftp eth0 COUNT ftp - eth0 stream - eth0 - tcp 8000,8001 stream - - eth0 tcp - 8000,8001 COUNT stream eth0 COUNT stream - eth0 web - eth0 - tcp 80,443 web - - eth0 tcp - 80,443 COUNT web eth0 COUNT web - eth0 dns - eth0 - udp - 53 dns - - eth0 udp 53 COUNT dns eth0 COUNT dns - eth0 countall - eth0 countall - - eth0 COUNT countall eth0 COUNT countall - eth0 backup:COUNT - eth0 188.xx.xx.xx tcp - - backup:COUNT - 188.xx.xx.xx eth0 tcp - - DONE backup
Betrieb
ein
shorewall check
prüft die Konfig, ein
shorewall start
startet das ganze.
IP-Adressen blocken
Sind mal wieder böse Leute im Netz unterwegs, kann man diese einfach sperren, bzw. droppen:
shorewall drop 61.129.57.x
HDDTemp
NTP-Date
smartmontools
aktuelle Festplatten unterstützen smart, damit kann man den 'Gesundheitsstatus' abfragen:
/etc/smartd.conf
... #DEVICESCAN # First two SCSI disks. This will monitor everything that smartd can # monitor. Do extended self-tests Wednesdays at 6pm and Sundays at 1 am /dev/sda -d ata -a -s L/../../3/18 /dev/sdb -d ata -a -s L/../../7/01 ...
cron-apt
Per Cron werde die Paketlisten aktualisiert und es gibt ein syslog-Eintrag, falls es neue Updates gibt.
Dienste
Cron
root-crontabs:
54 08 * * * /bin/sh /srv/www/_server/bin/make_all_stats.sh
4 06 * * * /srv/backup/bin/packagelist.sh
Webserver
PHP4
Mod-Security
Webstatistiken
Mod-PAM
Mailserver
Webmail
Horde
Virusscanner
ClamAV
Spamschutz
Spamassissin
DCC-Distributed Checksum Clearinghouse
Blacklists
Pyzor
Razor
Statistiken
Mysql-Server
PHPMyAdmin
mysqldumper
File-Zugriff
PureFTP
Config
in /etc/pure-ftpd/conf
#in /etc/pure-ftpd/conf # more *
::::::::::::::
AllowDotFiles
::::::::::::::
yes
::::::::::::::
AltLog
::::::::::::::
clf:/var/log/pure-ftpd/transfer.log
::::::::::::::
Bind
::::::::::::::
x.x.x.x,21
::::::::::::::
BrokenClientsCompatibility
::::::::::::::
yes
::::::::::::::
ChrootEveryone
::::::::::::::
yes
::::::::::::::
CustomerProof
::::::::::::::
yes
::::::::::::::
DisplayDotFiles
::::::::::::::
yes
::::::::::::::
DontResolve
::::::::::::::
1
::::::::::::::
MaxClientsPerIP
::::::::::::::
3
::::::::::::::
MinUID
::::::::::::::
32
::::::::::::::
MySQLConfigFile
::::::::::::::
/etc/pure-ftpd/db/mysql.conf
::::::::::::::
NoAnonymous
::::::::::::::
yes
::::::::::::::
PAMAuthentication
::::::::::::::
no
::::::::::::::
PassivePortRange
::::::::::::::
33000 33100
::::::::::::::
PerUserLimits
::::::::::::::
2 0
::::::::::::::
PureDB
::::::::::::::
/etc/pure-ftpd/pureftpd.pdb
::::::::::::::
SyslogFacility
::::::::::::::
none
::::::::::::::
TLS
::::::::::::::
2
::::::::::::::
VerboseLog_off
::::::::::::::
yes
vboxadm als Auth-Backend (MySQL)
User must be an Domainadmin to login
#/etc/pure-ftpd/db/mysql.conf
# Optional : MySQL server name or IP. Don't define this for unix sockets.
# MYSQLServer 127.0.0.1
# Optional : MySQL port. Don't define this if a local unix socket is used.
# MYSQLPort 3306
# Optional : define the location of mysql.sock if the server runs on this host.
MYSQLSocket /var/run/mysqld/mysqld.sock
# Mandatory : user to bind the server as.
MYSQLUser dovecot
# Mandatory : user password. You must have a password.
MYSQLPassword xxxx
# Mandatory : database to open.
MYSQLDatabase vboxadm
# Mandatory : how passwords are stored
# Valid values are : "cleartext", "crypt", "sha1", "md5" and "password"
# ("password" = MySQL password() function)
# You can also use "any" to try "crypt", "sha1", "md5" *and* "password"
MYSQLCrypt crypt
# In the following directives, parts of the strings are replaced at
# run-time before performing queries :
#
# \L is replaced by the login of the user trying to authenticate.
# \I is replaced by the IP address the user connected to.
# \P is replaced by the port number the user connected to.
# \R is replaced by the IP address the user connected from.
# \D is replaced by the remote IP address, as a long decimal number.
#
# Very complex queries can be performed using these substitution strings,
# especially for virtual hosting.
# Query to execute in order to fetch the password
#MYSQLGetPW SELECT Password FROM users WHERE User='\L'
MYSQLGetPW SELECT passwd_crypt FROM mailboxes AS m LEFT JOIN domains AS d ON m.domain_id = d.id WHERE m.local_part = CONCAT(SUBSTRING_INDEX('\L', '@', 1)) AND d.name = CONCAT(SUBSTRING_INDEX('\L', '@', -1)) AND m.is_active AND d.is_active AND m.is_domainadmin = 1
# Query to execute in order to fetch the system user name or uid
MYSQLGetUID SELECT 33 as Uid FROM mailboxes AS m LEFT JOIN domains AS d ON m.domain_id = d.id WHERE m.local_part = CONCAT(SUBSTRING_INDEX('\L', '@', 1)) AND d.name = CONCAT(SUBSTRING_INDEX('\L', '@', -1)) AND m.is_active AND d.is_active
# Optional : default UID - if set this overrides MYSQLGetUID
#MYSQLDefaultUID 1000
# Query to execute in order to fetch the system user group or gid
MYSQLGetGID SELECT 33 as Gid FROM mailboxes AS m LEFT JOIN domains AS d ON m.domain_id = d.id WHERE m.local_part = CONCAT(SUBSTRING_INDEX('\L', '@', 1)) AND d.name = CONCAT(SUBSTRING_INDEX('\L', '@', -1)) AND m.is_active AND d.is_active
# Optional : default GID - if set this overrides MYSQLGetGID
#MYSQLDefaultGID 1000
# Query to execute in order to fetch the home directory
MYSQLGetDir SELECT CONCAT('/srv/www/',SUBSTRING_INDEX('\L', '@', -1)) as Dir FROM mailboxes AS m LEFT JOIN domains AS d ON m.domain_id = d.id WHERE m.local_part = CONCAT(SUBSTRING_INDEX('\L', '@', 1)) AND d.name = CONCAT(SUBSTRING_INDEX('\L', '@', -1)) AND m.is_active AND d.is_active
vpopmail als Auth-Backend (alt)
from http://www.qmailinfo.org/index.php/Horde-Procmail-Filters
das ganze wird benötigt, um von Horde aus z.b. den Mailfilter (maildrop) zu ändern.
/etc/init.d/pure-ftpd_vpopmail
#! /bin/sh
# Starts a pure-ftp-auth-process with vpopmail as backend and pure-ftpd on Port 2121
#
# Author: Jonathan Tietz <http://crazylinux.de>
#
# Version: 1.0 03-Dec-2006
#
set -e
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
DESC="Pure-Ftpd-vpopmail"
NAME=pure-authd
NAME2=pure-ftpd
DAEMON=/usr/sbin/pure-authd
PIDFILE=/var/run/pure-ftpd_auth_vpop.pid
PIDFILE2=/var/run/pure-ftpd_vpop.pid
SCRIPTNAME=/etc/init.d/pure-ftpd_vpop
# Gracefully exit if the package has been removed.
test -x $DAEMON || exit 0
# Read config file if it is present.
#if [ -r /etc/default/$NAME ]
#then
# . /etc/default/$NAME
#fi
#
# Function that starts the daemon/service.
#
d_start() {
#start-stop-daemon --start --quiet --pidfile $PIDFILE \
# --exec $DAEMON
/usr/sbin/pure-authd -p /var/run/pure-ftpd_auth_vpop.pid -s /var/run/pure-ftpd_auth_vpop.sock -r /usr/sbin/pure-authd_vpopmail &
/usr/sbin/pure-ftpd -0 -B -A -E -H -g /var/run/pure-ftpd_vpop.pid -S 127.0.0.1,2121 -lextauth:/var/run/pure-ftpd_auth_vpop.sock
}
#
# Function that stops the daemon/service.
#
d_stop() {
start-stop-daemon --stop --quiet --pidfile $PIDFILE \
--name $NAME
start-stop-daemon --stop --quiet --pidfile $PIDFILE2 \
--name $NAME2
}
#
# Function that sends a SIGHUP to the daemon/service.
#
d_reload() {
start-stop-daemon --stop --quiet --pidfile $PIDFILE \
--name $NAME --signal 1
start-stop-daemon --stop --quiet --pidfile $PIDFILE2 \
--name $NAME2 --signal 1
}
case "$1" in
start)
echo -n "Starting $DESC: $NAME"
d_start
echo "."
;;
stop)
echo -n "Stopping $DESC: $NAME"
d_stop
echo "."
;;
#reload)
#
# If the daemon can reload its configuration without
# restarting (for example, when it is sent a SIGHUP),
# then implement that here.
#
# If the daemon responds to changes in its config file
# directly anyway, make this an "exit 0".
#
# echo -n "Reloading $DESC configuration..."
# d_reload
# echo "done."
#;;
restart|force-reload)
#
# If the "reload" option is implemented, move the "force-reload"
# option to the "reload" entry above. If not, "force-reload" is
# just the same as "restart".
#
echo -n "Restarting $DESC: $NAME"
d_stop
sleep 1
d_start
echo "."
;;
*)
# echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2
echo "Usage: $SCRIPTNAME {start|stop|restart|force-reload}" >&2
exit 1
;;
esac
exit 0
Activate init-script:
update-rc.d pure-ftpd_vpop defaults
/usr/sbin/pure-authd_vpopmail
#!/bin/bash
# ftpauth: This program is called by pure-authd to check if the email l/p are correct
# Copyright (C) 2005 Roman Volf
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
VPOPHOME=/var/vpopmail
## Do not change anything below here
PATH=$PATH:$VPOPHOME/bin
VPOPMAIL_UID=`printf "%s\0%s\0%s\0" $AUTHD_ACCOUNT $AUTHD_PASSWORD Y123457 | vchkpw id -u vpopmail 3<&0`
VPOPMAIL_GID=`id -g vpopmail`
DOMAIN_DIR=`vdominfo -d $DOMAIN`
USER_DIR=`vuserinfo -d $AUTHD_ACCOUNT`
if [ $VPOPMAIL_UID ]; then
DOMAIN=`echo $AUTHD_ACCOUNT|cut -d "@" -f 2`
USER=`echo $AUTHD_ACCOUNT|cut -d "@" -f 1`
DOMAIN_DIR=`vdominfo -d $DOMAIN`
#not used
#if [ ! -f $DOMAIN_DIR/.qmail-$USER ]; then
# echo "| /var/qmail/bin/preline /usr/local/bin/preprocmail" > $DOMAIN_DIR/.qmail-$USER
# echo "| $VPOPHOME/bin/vdelivermail '' $USER_DIR/Maildir/" >> $DOMAIN_DIR/.qmail-$USER
# chown vpopmail $DOMAIN_DIR/.qmail-$USER
# chmod 600 $DOMAIN_DIR/.qmail-$USER
#fi
echo "auth_ok:1"
echo "uid:$VPOPMAIL_UID"
echo "gid:$VPOPMAIL_GID"
echo "dir:$USER_DIR"
echo "end"
exit
fi
echo "auth_ok:0"
echo "end"
Monitoring
Cacti
Munin
SNMP
/etc/snmp/snmpd.conf
... smuxsocket 127.0.0.1 # Check the / partition and make sure it contains at least 10 megs. disk / 10000 # Check for loads: load 12 14 14 ...
Integration von Qmail-Stats gibt's bei Cacti
IP-Accounting
Backup
Backup ist natürlich auch notwendig. Auch wenn das System sich auf einem gespiegelten Raid befindet, so hilft das nicht gegen Datenverlust, sondern nur vor Hardwareausfall. Deshalb müssen die folgenden Sachen gesichert werden. Backup-Dir ist /srv/backup. Unter /srv/backup/bin/ liegen die (Cron)Scripte.
Serverkonfiguration
Dateien mit rsnapshot
Config ist /etc/rsnapshot.conf, alles default-werte, sonst diese Änderungen. Im root-Dir liegen dann die Backups der letzten Woche.
# All snapshots will be stored under this root directory.
snapshot_root /srv/backup/rsnapshot/
#retain hourly 6
retain daily 7
#retain weekly 4
logfile /var/log/rsnapshot.log
backup /home/ localhost/
backup /etc/ localhost/
backup /srv/vmail/ localhost/
backup /srv/www/ localhost/
und das dazugehörige cronscript /etc/cron.d/rsnapshot:
30 3 * * * root /usr/bin/rsnapshot daily
Partitionstabelle
liegen unter /srv/backup/server (manuell erstellt, parted)
parted -l|tee /srv/backup/server/partitions
Liste der installierten Packeten
/srv/backup/server/package.list (cron, /srv/backup/bin/packagelist.sh):
#!/bin/sh
/usr/bin/dpkg -l>/srv/backup/server/package.list
SQL-Export
der Export wird via MySQLDumper (im AdminBereich unter Verwaltung) täglich per cron dürchgeführt. Jede DB hat ein eigene Datei. Die Files liegen unter .../msd/work/backup/ und werden jeweils 10 Tage aufgehoben.
Dateisystem extern via Duply
Backups auf nicht vertrauenswürdige (FTP-)Server
Wer seine Daten auf einem unbekannten Server sichert, muss sie verschlüsseln und signieren, um sie zuverlässig vor neugierigen Blicken und Manipulationen zu schützen. Dafür ist duplicity das richtige Werkzeug, und das c't-Skript ftplicity (jetzt duply) macht die Arbeit damit zu einem Kinderspiel.
/etc/duply/<profile>/exclude
/dev
/proc
/sys
/tmp
/home
/srv/mysql
/var/cache
/var/tmp
/var/spool/postfix/private
/run
/build
/mnt
/srv/backup
/srv/backupserver
/root/.cache/
Restore
Einzelne Dateien aus dem Backup restauriert man mit duply fetch. Der Befehl benötigt drei Optionen: Datei- beziehungsweise Verzeichnisname, Ziel und Alter:
duply <profile> fetch etc/passwd /root/pw 4D
beispielsweise restauriert /etc/passwd im Stand von vor 4 Tagen nach /root/pw, "now" liefert den aktuellen Stand. Details zu dem verwendeten Zeitformat finden sie in der Manpage von duplicity im Abschnitt TIME FORMATS.
Cronjobs
27 7 1 * * /usr/bin/duply <profile> backup_verify_purge --force
23 6 * * * /usr/bin/duply <profile> bkp 2>/dev/null
0 7 * * 5 /usr/bin/duply <profile> status 2>/dev/null
Links
- http://www.heise.de/security/artikel/Hinter-Schloss-und-Siegel-270834.html
- duply (extended ftplicity)
- Ubuntu-Packages
Tools
- rsnapshot http://www.rsnapshot.org/: Erzeugt inkrementele Backups mit Hilfe von rsync
- mySQLDumper http://www.mysqldumper.de/: Mysql-DB-Backups