Inleiding
Er is een tijd van komen en gaan, dat zeggen ze wel eens. Om even beeld te geven: ik heb diverse virtuele machines in mijn eigen Vmware cloud. Daarvan zijn er 2 met publieke functies te weten “uxx-001” en “uxx-002” met respectievelijk Centos6.8 en Centos5.11. De uxx-002 is de oudste in het ‘serverpark’. Waarom 002 ? Ik weet eerlijk niet meer wat de eerste 001 was.
De uxx-002 server is na ruim 5 jaar definitief uitgezet en verwijderd. Het OS is ouderwets en de software erop niet meer van deze tijd. Dat brengt mij op deze post.
Ik heb daarom ook ruim een jaar terug redelijk wat inhoud van websites uit Centos5.11 met PHP5.3 en functionaliteit verhuisd naar de uxx-001. Daar is tenminste PHP5.6 actief, MySQL (MariaDB) 5.6, Postfix i.p.v Sendmail en meer.
Echter; ik heb nog 2 service VM’s. Deze “services-001” en “services-002” doen bijzaken voor het gehele netwerk, dus ook de via VPN bereikbare thuis netwerken. Deze doen: DNS caching (met Adblock), SMTP (met TLS), LDAP, Tacacs en NTP. Het zijn relatief simpele en platte VM met 1 cpu, 1GB mem en 10GB disk, ook Centos6.8.
Het idee is dus nu ontstaan om deze service VM’s samen te voegen op de bestaande uxx-001 en de nieuwe uxx-002. En uiteindelijk de websites te verhuizen.
De nieuwe server
- Centos7 minimal install, x86_64
- default packages na installatie:
wget mailx mlocate open-vm-tools vim epel-release bind-utils ftp
- firewalld vervangen voor iptables
- httpd
- php7
- functionaliteit vanuit services-00x
- functionaliteit vanuit uxx-001
- mysql
- postfix voor pc-mania.nl domain
- rsyslog vervangen voor syslog-ng
- vsftpd
- cacti en snmpd
- phpmyadmin
Redelijk eenvoudig zou je zeggen.
Na de basis installatie:
Na de reboot is de basis er en kunnen we aan de slag. Het eerste is de firewalld vervangen voor iptables. Dit is puur gemak, firewalld werkt ook prima.
yum install -y iptables-services
systemctl stop firewalld
systemctl start iptables
systemctl start ip6tables
systemctl enable iptables
systemctl enable ip6tables
systemctl disable firewalld
yum -y remove firewalld
Dan, kunnen we beginnen aan de httpd en php setup. Hiervoor moeten we een extra Repo installeren. Dit is bij de voorkeur REMI. De webtatic en IUS repo’s zijn het over het algemeen nét niet.
wget -4 http://rpms.remirepo.net/enterprise/remi-release-7.rpm
rpm -Uvh remi-release-7.rpm
De installatie van httpd en php is dan als volgt
yum install -y httpd mod_ssl
yum install -y --enablerepo=remi-php70 php php70-php-mysqlnd php-mysqli php70-php-ldap php70-php-gd
Dan moet er, vanwege een externe Repo wat recht gezet gaan worden.
echo "extension=gd.so" > /etc/php.d/30-gd.ini
echo "extension=ldap.so" > /etc/php.d/30-ldap.ini
echo "date.timezone = Europe/Amsterdam" /etc/php.ini
mv /usr/lib64/php/modules /usr/lib64/php/modules.old
ln -s /opt/remi/php70/root/usr/lib64/php/modules /usr/lib64/php/modules
systemctl restart httpd
Nu dat gebeurd is kan ook de MySQL server geïnstalleerd. Hier is de voorkeur Percona 5.7 ten opzichte van MariaDB.
yum install -y http://www.percona.com/downloads/percona-release/redhat/0.1-3/percona-release-0.1-3.noarch.rpm
yum install -y Percona-Server-server-57
En niet te vergeten:
systemctl enable httpd
systemctl enable mysqld
systemctl start httpd
systemctl start mysqld
Gefeliciteerd! Er is een LAMP-stack actief. Goed, de firewall rules voor poort 80/443 moeten er nog in maar dat ter zijde.
SELinux?
Er is, wat dat moet opgevallen zijn, sprake van een “enforcing” SELinux policy. Vele zetten dit direct in het begin uit met “setenforce 0” maar dat is relatief laf. Daarom alles met Enforcing. Hier zijn later dus ook wat trucs voor. De belangrijkste nu omdat we zover zijn is:
setsebool -P httpd_can_network_connect_db 1
Je leest het goed. Anders werkt je website gewoon niet met MySQL samen.
Netwerk statisch maken
Er is vanuit de basis installatie middels DHCP een adres en via de IPV6_ND een IPv6 adres verkregen. Dit is voor de basis installatie prima geweest maar we veranderen dit nu. Hier is de VMware console voor nodig.
rm -f /var/lib/NetworkManager/dhclient*
systemctl stop NetworkManager
systemctl disable NetworkManager
Daarna kan je het ifcfg-eth0 bestand keurig invullen naar wens:
TYPE="Ethernet"
BOOTPROTO="none"
DEFROUTE="yes"
IPADDR="192.168.190.52"
PREFIX="24"
GATEWAY="192.168.190.254"
DNS1="192.168.190.21"
DOMAIN="192.168.190.22"
IPV4_FAILURE_FATAL="yes"
IPV6INIT="yes"
IPV6ADDR="2001:9a0:5004:1900::52/64"
IPV6_DEFAULTGW="2001:9a0:5004:1900::1"
IPV6_AUTOCONF="no"
IPV6_DEFROUTE="yes"
IPV6_FAILURE_FATAL="no"
IPV6_FORWARDING="no"
IPV6_ADDR_GEN_MODE="stable-privacy"
NAME="eth0"
# This is system specific and can be created using 'uuidgen eth0' command #
UUID="c27bbe86-3299-440e-88bc-9ed5901b2142"
DEVICE="ens192"
ONBOOT="yes"
NM_CONTROLLED=no
Het commando in de comment is mogelijk nog nodig om te draaien op de prompt. Let hier op. Na een extra ‘systemctl restart network’ moet je weer verbonden zijn en kan je het verifiëren met ‘ip a’ of ‘ifconfig’.
De laatste regel is met name van belang zodat deze file gebruikt word voor configuratie van het ‘eth0’ interface, in plaats dat de NetworkManager dit overneemt.
Syslog-NG met MySQL Logparser (Netlog)
Vanuit de Uxx-001 server heb ik een Syslog systeem wat dermate handig en simplistisch is in gebruik maar wel goed oogt dat dit ook mee moet. Hier is in de basis Syslog-NG voor nodig, als mede MySQL en een stukje PHP software. De laatst genoemde functionaliteit is mogelijk, dus nu Syslog-NG nog. Vanuit de CentOS community is er gekozen voor RSyslog en deze zal verwijderd moeten worden.
wget https://copr.fedorainfracloud.org/coprs/czanik/syslog-ng37/repo/epel-7/czanik-syslog-ng37-epel-7.repo
mv czanik-syslog-ng37-epel-7.repo /etc/yum.repos.d/syslog-ng37-epel-7.repo
systemctl stop rsyslog
systemctl disable rsyslog
yum -y remove rsyslog
yum install -y syslog-ng
systemctl start syslog-ng
systemctl enable syslog-ng
Meer is het niet, gelukkig en dat scheelt. Nu de meer interessante stukken. Eerst zal de basis van MySQL nog even goed gezet moeten worden.
Configureer in /root een bestand ‘.my.cnf’ . Zoek hiervoor het root password op via “cat /var/log/mysqld.log | grep root@”
[client]
user=root
pass=<wat je vond>
Nu kan je inloggen in de MySQL server. Hier zullen diverse changes doorgevoerd moeten worden als basis. Het eerste is je password opnieuw invoeren.
ALTER USER 'root'@'localhost' IDENTIFIED BY '<je password>';
Er zullen een aantal databases en tabellen aangemaakt moeten worden. Door onderstaand in te voeren is dat geregeld (voer indien gewenst een ander wachtwoord in op regels 5 en 6:
CREATE DATABASE `syslog`;
CREATE DATABASE `netlogconfig`;
GRANT ALL ON syslog.* TO 'syslog'@'localhost' IDENTIFIED BY 'WonFaznu$(s#3nCi';
GRANT ALL ON netlogconfig.* TO 'syslog'@'localhost' IDENTIFIED BY 'WonFaznu$(s#3nCi';
USE syslog;
CREATE TABLE `template` (
`id` int(15) unsigned NOT NULL AUTO_INCREMENT,
`HOST` varchar(39) NOT NULL,
`FAC` varchar(255) NOT NULL,
`PRIO` varchar(255) NOT NULL,
`LVL` varchar(255) NOT NULL,
`TAG` varchar(255) NOT NULL,
`DAY` varchar(10) NOT NULL,
`TIME` varchar(8) NOT NULL,
`PROG` varchar(255) NOT NULL,
`MSG` text NOT NULL,
PRIMARY KEY (`id`),
KEY `HOST` (`HOST`),
KEY `DAY` (`DAY`),
KEY `TIME` (`TIME`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
USE netlogconfig;
CREATE TABLE `hostnames` (
`id` int(10) unsigned NOT NULL auto_increment,
`hostip` text NOT NULL,
`hostname` text NOT NULL,
`hosttype` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
CREATE TABLE `hosttype` (
`id` int(10) unsigned NOT NULL auto_increment,
`name` text NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM;
CREATE TABLE `lograte` (
`id` int(10) NOT NULL auto_increment,
`hostnameid` int(10) NOT NULL,
`timestamp` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,
`1min` float default NULL,
`5min` float default NULL,
`10min` float default NULL,
PRIMARY KEY (`id`)
) ENGINE=MyISAM;
CREATE TABLE `lograteconf` (
`hostnameid` int(10) NOT NULL,
`samplerate` int(10) default NULL
) ENGINE=MyISAM;
CREATE TABLE `logscavenger` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`keyword` varchar(100) DEFAULT NULL,
`dateadded` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`active` int(1) NOT NULL,
`datedeleted` timestamp NULL DEFAULT NULL,
`emailrcpt` varchar(255) DEFAULT NULL,
`emailgroup` int(2) DEFAULT NULL,
KEY `id` (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
CREATE TABLE `emailgroups` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`groupname` varchar(40) NOT NULL,
`recepients` text NOT NULL,
`active` int(1) DEFAULT '1',
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
CREATE TABLE `logcache` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`timestamp` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
`host` varchar(39) NOT NULL,
`msg` text NOT NULL,
PRIMARY KEY (`id`),
KEY `host` (`host`),
KEY `timestamp` (`timestamp`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
Vervolgens kan de basis van Netlog geinstalleerd worden. Download de installatie files van de Netlog applicatie:
wget https://www.pc-mania.nl/netlog_v2.01.tgz
Dan kan het bestand uitgepakt worden, bij voorkeur in de /tmp of /root directory en de installatie uitgevoerd:
tar xvf netlog_v2.01.tgz
cd netlog_v2.01
./install.sh
Deze zal de bestanden verplaatsen naar de juiste directories. Na deze stap kan het nodige aan instellingen rechtgezet worden indien je bijvoorbeeld het wachtwoord van een of beide databases hebt aangepast. De 2 bestanden voor wachtwoorden zijn, zoals je zag in de install.sh output duidelijk te vinden.
Nu de belangrijkste 2 directory’s en bestanden bestaan is het tijd om deze ‘logparser’ als daemon (service) mee te laten draaien. Dit kan via de systemd systematiek binnen Centos7. De oude ‘/etc/inittab’ met runlevels (3 bijv.) zijn niet meer namelijk.
Maak een bestand aan met de naam ‘/usr/lib/systemd/system/logparser.service‘ en vul deze met:
[Unit]
Description=System Logger Parser Daemon
After=mysqld.service
[Service]
ExecStart=/usr/bin/php /usr/share/syslog-ng/php/logparser.php
Restart=on-failure
[Install]
WantedBy=multi-user.target
Alias=logparser.service
Dan kan het systeem herladen worden en de service gestart.
systemctl daemon-reload
systemctl enable logparser.service
systemctl status logparser
De service word nog niet gestart! Dat is met reden dat de Syslog-NG backend nog verteld moet worden wat deze moet doen en hoe deze inkomende berichten moet verwerken.
In het bestand ‘/etc/syslog-ng/syslog-ng.conf’ moeten er 2 sources, 1 destination en 2 log methodes voor toegevoegd worden.
#voer in onder de stanza van 'source s_sys'
source s_network_udp {
network(
ip(0.0.0.0)
port(514)
transport("udp")
);
};
source s_network_tcp {
network(
ip(0.0.0.0)
port(514)
transport("tcp")
);
};
#voer in onder de stanza van 'destination d_mlal'
destination d_mysql {
pipe("/var/log/syslog.fifo"
template("HOST_:_$SOURCEIP _,_ FAC_:_$FACILITY _,_ PRIO_:_$PRI _,_ LVL_:_$LEVEL _,_ TAG_:_$TAG _,_ DAY_:_$YEAR-$MONTH-$DAY _,_ TIME_:_$HOUR:$MIN:$SEC _,_ PROG_:_$PROGRAM _,_ MSG_:_$MSG\n")
template-escape(yes));
};
#voer in onder de laatste stanza van 'log { source(s_sys)'
log { source(s_network_udp); destination(d_mysql); };
log { source(s_network_tcp); destination(d_mysql); };
Sla het werk op en herstart de Syslog-NG daemon via “systemctl restart syslog-ng“. Voer desgewenst een check uit met “systemctl status syslog-ng” en “ss -ln|grep 514”:
udp UNCONN 0 0 *:514 *:*
tcp LISTEN 0 128 *:514 *:*
Nu Syslog-NG weet wat er moet gebeuren met de inkomende berichten en deze dus met een specifieke opmaak naar het FiFo bestand in ‘/var/log/syslog.fifo‘ moet schrijven kunnen we de logparser service starten.
systemctl start logparser
systemctl status logparser
● logparser.service - System Logger Parser Daemon
Loaded: loaded (/usr/lib/systemd/system/logparser.service; enabled; vendor preset: disabled)
Active: active (running) since Wed 2017-03-29 13:33:37 CEST; 4s ago
Main PID: 3155 (php)
CGroup: /system.slice/logparser.service
└─3155 /usr/bin/php /usr/share/syslog-ng/php/logparser.php
Mar 29 13:33:37 uxx-002.pc-mania.nl systemd[1]: Started System Logger Parser Daemon.
Mar 29 13:33:37 uxx-002.pc-mania.nl systemd[1]: Starting System Logger Parser Daemon...
Voila. De Netlog parser service draait en als alles goed verlopen is zal ook de website werken. Browse naar http://192.168.190.52/ en de website moet getoond worden. Uiteraard zonder informatie, hosts of categorieen.
Vergeet niet de jobs in ‘/etc/crontab’ actief te zetten. Let op; de laatste regel met “prunelog.php” is alleen noodzakelijk bij een archiver situatie. In dit geval dus even niet.
Test door middel van een extra host of netwerk device of je logging werkt. Een check kan als volgt uitgevoerd worden:
iptables -L -nv
Chain INPUT (policy DROP 0 packets, 0 bytes)
pkts bytes target prot opt in out source destination
...
96 17444 ACCEPT udp -- * * 0.0.0.0/0 0.0.0.0/0 state NEW udp dpt:514
mysqlshow --count syslog
Database: syslog
+-------------------------------------+----------+------------+
| Tables | Columns | Total Rows |
+-------------------------------------+----------+------------+
| HST_192_168_190_254_DATE_2017_03_29 | 10 | 235 |
| template | 10 | 0 |
+-------------------------------------+----------+------------+
2 rows in set.
Voor de lograte pagina moet er een correctie gedaan worden. Vanwege PHP7 is GD nog niet volledig up to date. Bewerk het bestand ‘/usr/share/php/jpgraph/gd_image.inc.php’ op regel 110 en zet de “//” voor deze regel
//JpGraphError::RaiseL(25128);//(......
Om de pagina direct beter te laten werken (er zijn namelijk wat functies missend in de settings.php) moet er handmatig even wat via MySQL gedaan worden:
use netlogconfig;
insert into hosttype values (1,"Firewall")
insert into hostnames (hostip,hostname,hosttype) values ("192.168.190.254","dc-firewall",1);
insert into lograteconf values (1,1);
exit;
Ga naar de logout knop op de pagina om de sessie te resetten. En dan zal de logging getoond moeten worden.
Webserver en TLS/SSL
De standaard inrichting van httpd en php zijn nog van toepassing. Ook de zojuist geïnstalleerde Netlog applicatie draait, jawel, in de standaard ‘/var/www/html’ directory. Geen probleem. Er zal wat aangepast moeten worden.
#Listen 80
Listen *:80
#ServerAdmin root@localhost
ServerAdmin bartjan [ at ] pc-mania [dot] nl
#ServerName www.example.com:80
ServerName uxx-002.pc-mania.nl
Maak een default site aan, zodat alle request daar op binnen komen in de configuratie ‘/etc/httpd/conf.d/_default-site.conf‘
<VirtualHost *:80>
DocumentRoot /var/www/html
ServerName uxx-002.pc-mania.nl
<Directory /var/www/html>
AllowOverride all
Options MultiViews IncludesNoExec FollowSymLinks
</Directory>
</VirtualHost>
Test de configuratie met het commando ‘httpd -t‘ en eventueel met de output van ‘httpd -S’ zoals hieronder (let op, het voorheen gebruikte ‘apachectl -S’ word niet meer gebruikt):
httpd -S
VirtualHost configuration:
*:443 uxx-002.pc-mania.nl (/etc/httpd/conf.d/ssl.conf:56)
*:80 is a NameVirtualHost
default server uxx-002.pc-mania.nl (/etc/httpd/conf.d/_default-site.conf:1)
port 80 namevhost uxx-002.pc-mania.nl (/etc/httpd/conf.d/_default-site.conf:1)
Nu kunnen er meer websites toegevoegd worden, door elke in zijn eigen .conf bestand te plaatsen. Verplaats de inhoud van de map ‘/var/www/html’ naar een nieuwe map ‘/var/www/syslog’ en voeg deze configuratie toe in ‘/etc/httpd/conf.d/syslog.pc-mania.nl.conf’
<VirtualHost *:80>
DocumentRoot /var/www/syslog
ServerName syslog.pc-mania.nl
<Directory /var/www/syslog>
AllowOverride all
Options MultiViews IncludesNoExec FollowSymLinks
</Directory>
</VirtualHost>
Voer een herstart uit met ‘apachectl restart’ of ‘systemctl restart httpd’ en controleer of de output van ‘httpd -S’ nu uitgebreid is.
TLS/SSL hardening toepassen
Voordat we TLS (of SSL) gaan toepassen moeten er wat regels gezet worden wat de beveiliging omhoog brengt. Dit voorkomt mogelijke man-in-the-middle aanvallen of andere meeluister praktijken. Dat zal niet hard lopen met de hobby matige informatie maar toch.
Maak een bestand aan ‘/etc/httpd/conf.d/security.conf en voeg onderstaande in.
ServerTokens Prod
ServerSignature Off
TraceEnable Off
Header set X-Content-Type-Options: "nosniff"
Header set X-Frame-Options: "sameorigin"
Header unset ETag
FileETag None
Nadat deze aangemaakt is moet ook de ‘/etc/httpd/conf.d/ssl.conf’ er aan geloven. Open deze en voeg het volgende toe onderaan het bestand:
SSLProtocol all -SSLv2 -SSLv3 -TLSv1 -TLSv1.1
SSLCipherSuite EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH:AES256+ED
SSLHonorCipherOrder on
##
## Header context
##
Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
Header always edit Set-Cookie ^(.*)$ $1;secure
Header always set X-Frame-Options "DENY"
Header always set X-XSS-Protection "1; mode=block"
Header always set X-Content-Type-Options "nosniff"
Header always set X-Permitted-Cross-Domain-Policies "none"
Verwijderd het gehele stuk van de ‘virtualhost _default_:443’ en voeg dit toe aan de ‘/etc/httpd/conf.d/_default-site.conf:
<VirtualHost *:443>
DocumentRoot /var/www/html
ServerName uxx-002.pc-mania.nl
SSLEngine on
SSLCertificateFile /etc/pki/tls/certs/localhost.crt
SSLCertificateKeyFile /etc/pki/tls/private/localhost.key
<Directory /var/www/html>
AllowOverride all
Options MultiViews IncludesNoExec FollowSymLinks
</Directory>
</VirtualHost>
En ook dat werkt nu, op het certificaat na, goed. Dat is eenvoudig toe te voegen door LetsEncrypt.
yum install -y python-certbot-apache
Zorg wel dat de server uiteraard bereikbaar is op DNS en IP adres, zowel poort 80 en 443.
certbot --apache certonly -m bartjan [ at ] pc-mania [dot] nl -d uxx-002.pc-mania.nl
Hierna zijn er diverse files gegenereerd en kan je de configuratie in de ‘/etc/httpd/conf.d/_default-site.conf’ aanpassen:
SSLCertificateFile /etc/letsencrypt/live/uxx-002.pc-mania.nl/cert.pem
SSLCertificateKeyFile /etc/letsencrypt/live/uxx-002.pc-mania.nl/privkey.pem
SSLCertificateChainFile /etc/letsencrypt/live/uxx-002.pc-mania.nl/chain.pem