Tag Archive: nginx

ownCloud Konfiguration mit Nginx: Hosting und Reverse Proxy

ownCloud

Da die Einrichtung doch etwas zickiger verlief als erwartet, fasse ich kurz meine Erfahrung für die Nachwelt zusammen.

Artikel zur Installation finden sich zur Genüge, daher bleibt dieser Schritt bei mir aus.

Eingesetzt habe ich Debian Jessie (amd64), auf dem Reverse Proxy läuft ein nginx/1.7.7, auf dem ownCloud-Server ein nginx/1.6.2 sowie ownCloud selber in Version 7.0.3.
Weiterlesen

Nginx als TCP-Proxy (Beispiel Dovecot)

Hintergrund

Ich betreibe zwei Dovecot-Installationen, die sich untereinander replizieren. Änderungen werden sofort/mit minimaler Verzögerung im entfernten Maildir übernommen. Ein master/master Szenario. (http://wiki2.dovecot.org/Replication)
Weil mir die Zeit fehlt, mich mit echten IMAP-Proxys auseinanderzusetzen, habe ich mich für das Nginx Modul nginx_tcp_proxy_module entschieden.
Weiterlesen

IIS, Apache, Nginx: SSL Hardening angelehnt an FIPS 140-2

SSL Lock

Changelog

  • 13. Jan 2015 – Apache DH Parameter werden in SSLCertificateFile definiert

Abgesehen von der stetigen Implementierung von Sicherheitspatches in das System, gibt es immer wieder Kleinigkeiten zu beachten.
Ich entscheide mich zugegeben relativ spät für einen Artikel zum Thema SSL Hardening, der Aufschrei verklang in den letzten Wochen ja zunehmend, dennoch…
 
 

Handshakes mit SSL nach FIPS 140-2 mit Nginx
Abbildung 1: Handshakes mit SSL nach FIPS 140-2 mit Nginx
Ich richte mich bei der Konfiguration nach FIPS 140-2, so schließe ich etwa SSL bis einschließlich v3 und diverse Cipher wie RC4 aus. Kompatibilität bietet anstatt RC4 der Cipher CBC.
Trotzdem besteht eine Kompatibilität zu beinahe allen Browsern, die noch Verwendung finden. Der Ausreißer aus Abbildung 1 ist keine wirkliche Überraschung…
Für Linux gilt, dass OpenSSL zu diesem Zeitpunkt mindestens in Version 1.0.1c vorliegt (zu überprüfen mit „openssl version“).
Nginx sollte in jedem Repository bereits eine Version höher 1.0.6 erreicht haben („nginx -v“).
Ein Apache Web-Server muss ab Version 2.4.7 installiert sein („apache2 -v“).

Nginx

Zuerst für den Diffie Hellman Schlüsselaustausch über 2048bit folgende Datei erstellen:

openssl dhparam -out /etc/nginx/dhparam.pem 2048

Anschließend die Site-Konfiguration ändern:

server {
        [...]
        ssl on;
        ssl_dhparam /etc/nginx/dhparam.pem;
        ssl_certificate path-to.crt;
        ssl_certificate_key path-to.key;
        ssl_session_cache    shared:SSL:10m;
        ssl_session_timeout  10m;
        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
        ssl_prefer_server_ciphers on;
        ssl_ciphers !aNULL:!eNULL:FIPS@STRENGTH;
        [...]

Mit obiger Konfiguration überlässt der Besucher Nginx die Auswahl des Ciphers, die Auswahl erfolgt von stärkster Methode an absteigend. Timeout und Cache werden auf 10m reduziert.

IIS

Nach langem Zögern und Hadern entscheide ich mich für die GUI-Methode, werde dafür aber etwas genauer. Ich finde es schade, dass das kleine Tool in meiner Umgebung relativ lange verborgen blieb:

IIS Crypto, SSL Hardening
Abbildung 2: IIS Crypto
Für den IIS ab Windows Server 2003 (-2012 R2) empfehle ich das Tool IIS Crypto. Aber Vorsicht: Benutzer des Windows Servers in Version 2003, müssen sich vorab eines Patches bedienen, um überhaupt AES als Cipher verwenden zu könnnen. Weiterhin unterliegen sie der Einschränkung, die Cipher nicht manuell anordnen zu können.

Einigen dürfte der über die „Local Security Policy“ einstellbare Wert „System cryptography: Use FIPS compliant algorithms for encryption, hashing, and signing“ ein Begriff sein.
Die Funktion triggert den DWORD32 Eintrag „Enabled“ in „HKLM\System\CurrentControlSet\Control\Lsa\FIPSAlgorithmPolicy“ auf 1. Eine hilfreiche Funktion, wenn wirklich das ganze Betriebssystem von der FIPS-Richtlinie profitieren soll. Allerdings ist der Modus sehr weitreichend und wird selbst von Microsoft nur bedingt empfohlen, da es zu einigen Einschränkungen kommt.

Der IIS Crypto liegt ebenso in einer Command Line Version vor, in beiden Fällen in .Net 2.0 sowie 4.0. Änderungen, die hiermit erzielt werden, können mit Software wie regshot eingefangen- und zu einem PowerShell-Script umgeschrieben werden. Das erwähnt, dürften auch die Scripter zufriedengestellt sein.

Apache2

Benutzer des Apache Web-Servers in Version 2, haben es je nach Konfiguration etwas schwieriger. Der vorhandene Schalter „SSLFIPS“ wird nur funktionieren, wenn Apache2 unter Verwendung einer FIPS SSL-Bibliothek gebaut wurde. Darauf verzichte ich jedoch und biete eine Konfiguration an, die ähnlich den obigen ist.
Zuerst für den Diffie Hellman Schlüsselaustausch über 2048bit folgende Datei erstellen:

openssl dhparam -out /etc/apache2/dhparam.pem 2048

Der Inhalt der Datei „/etc/apache2/dhparam.pem“ wird an das Ende des SSL-Zertifikates angehangen. Etwa:

cat /etc/apache2/dhparam.pem >> /etc/apache2/ssl/www.crt

Apache 2.4 extrahiert DH-Parameter wie auch alle Informationen zur Zertifikatskette aus einer Datei.

In der Datei „/etc/apache2/mods-enabled/ssl.conf“ (Ubuntu/Debian) ändere oder füge ich Folgendes hinzu:

SSLProtocol all -SSLv2 -SSLv3
SSLCompression off
SSLHonorCipherOrder on
SSLCipherSuite "EECDH+AESGCM EDH+AESGCM EECDH EDH RSA -CAMELLIA -SEED !aNULL !eNULL !LOW !MD5 !EXP !PSK !SRP !DSS !RC4"

Anmerkungen

Ein Hinweis zum Zertifikat der Certification Authority (CA): Einige Benutzer neigen dazu, die Zertifikate zu vereinen. Etwa das öffentliche Zertifikat der CA und das privat ausgestellte Zertifikat, wie auch in meiner eigenen Konfiguration.
SSL Test-Anwendungen wie „ssllabs.com“ weisen auf den untypischen Zustand hin, einen Einfluss auf die Sicherheit hat es jedoch nicht. Es ensteht unwesentlich mehr Netzwerkverkehr, wohl etwa 1kB.

Abschließend lässt sich noch sagen, dass es sich bei den Empfehlungen – wenn man es denn so nennen kann -, die ich in diesem Artikel beschreibe, nicht um absolut FIPS 140-2 konforme Einstellungen handelt. Aber wer würde sich bei sowas auch auf einen Blog verlassen…
Jedoch resultiert eine sichere Konfiguration, die weit enfernt von paranoid und somit hoch-kompatibel bleibt.

Seafile 4.0.x mit Nginx und MySQL-Backend auf Debian/Ubuntu

seafile nginx mysql

Dass Seafile ursprünglich in China entwickelt wurde, tut der Sache keinen Abbruch, dass es sich um eine sichere und gute Open-Source Software mit Entwicklern aus der ganzen Welt handelt.
Seafile ist ähnlich OwnCloud eine selbst gehostete Cloud-Lösung zum Austausch von Dateien. Und noch mehr…
Für weitere Information empfehle ich einen Blick auf die Webseite.

Ich beschreibe hier die Einrichtung auf Basis von MySQL/MariaDB, „verstecken“ werde ich den Dienst hinter Nginx mit HTTPS.

Wovon ich ausgehe:

  • Nginx Server in Grundkonfiguration (siehe Artikel)
  • SSL-Zertifikat, es darf selbstsigniert sein (Tipp: https://startssl.com)
  • MySQL oder MariaDB Datenbank
  • Erreichbarkeit unter Subdomain „cloud.domain.tld“
  • Als Servernamen verwende ich durchgehend „servername“

Eine schöne Übersicht zur Kommunikation des Dienstes auf Basis von Nginx (Quelle):
Nginx, Seafile

Changelog

  • 24. Januar 2015 – Korrektur für Webdienst ([fileserver] anstatt [httpserver]), Download von Seafile via wget gefixt, Pfad der „seafile.conf“ korrigiert, seit v3.10 lautet „HTTP_SERVER_ROOT“ „FILE_SERVER_ROOT“
  • 19. Mai 2014 – Init-Script Anpassungen an Seafile 3.0.3
  • 18. Mai 2014 – Artikel angepasst an Seafile 3.0.3, Runlevel des Init-Scripts angepasst
  • 13. Mär 2014 – HTTP_SERVER_ROOT fixed (keine Preview, kein Download)
  • 15. Mär 2014 – Service nicht installiert

Installation und Konfiguration

Seafile definiert folgende Abhängigkeiten für die Installation und Ausführung, welche via „apt-get“ installiert werden können:

apt-get install python2.7 python-setuptools python-simplejson python-imaging python-mysqldb

Einen unpriviligierten Benutzer erstellen, „-d“ definiert das Heimverzeichnis, das später neben den Cloud-Daten auch die gesamte Seafile-Installation beinhalten wird. Ein Passwort wird nicht vergeben, da ein Login mit der fiktiven Shell „false“ nicht möglich ist:

useradd -m -d /srv/seafile -s /bin/false seafile

Ich wechsel zum Benutzer „seafile“ unter manueller Angabe einer Shell, in diesem Fall Bash:

su - seafile -s /bin/bash

Den Verzeichnisbaum lege ich dem Muster der Empfehlung Seafiles nach an.

Auch ist darauf zu achten, dass die neueste Version heruntergeladen wird! v4.0.6 ist zum Zeitpunkt des Artikels (Update 22.01.2015) aktuell.
In meinem Fall benutze ich die x86_64-Version für ein 64bit-System, reine 32bit-Systeme greifen entsprechend zum anderen Paket.

„servername“ im ersten Befehl bitte zwei mal ersetzen, es muss natürlich nicht der echte Servername sein.

mkdir -p servername/installed && cd servername/installed
wget --content-disposition -O seafile-server.tar.gz https://bitbucket.org/haiwen/seafile/downloads/seafile-server_4.0.6_x86-64.tar.gz && tar -xzvf *tar.gz -C ../ && cd ..

Die Struktur im Überblick:

seafile@www:~/servername$ tree -L 2
.
├── installed
│   └── seafile-server_4.0.6_x86-64.tar.gz
└── seafile-server-4.0.6
    ├── check_init_admin.py
    ├── reset-admin.sh
    ├── runtime
    ├── seaf-fuse.sh
    ├── seafile
    ├── seafile.sh
    ├── seahub
    ├── seahub.sh
    ├── setup-seafile-mysql.py
    ├── setup-seafile-mysql.sh
    ├── setup-seafile.sh
    └── upgrade

Nun in das Verzeichnis „seafile-server-4.0.6“ wechseln und das Script zur Erstellung der MySQL Datenbanken anstoßen:

cd seafile-server-4.0.6/
./setup-seafile-mysql.sh

Die aufkommenden Fragen zur Konfiguration nun beantworten.
Für die meisten Optionen wähle ich die Vorgabe, indem ich mit „Enter“ bestätige.

Im Folgenden erwähne ich nur Optionen, deren Standardwert ich verändert habe

Zwischendurch wird das „root“-Passwort der MySQL-Installation abgefragt.
Folgende manuelle Eingaben sind wichtig:

What is the name of the server? It will be displayed on the client.
3 – 15 letters or digits
[ server name ] servername

What is the ip or domain of the server?
For example: www.mycompany.com, 192.168.1.101
[ This server’s ip or domain ] cloud.domain.tld

——————————————————-
Please choose a way to initialize seafile databases:
——————————————————-

[1] Create new ccnet/seafile/seahub databases
[2] Use existing ccnet/seafile/seahub databases

[ 1 or 2 ] 1

What is the host of mysql server?
[ default „localhost“ ] je nach Konfiguration

What is the port of mysql server?
[ default „3306“ ] je nach Konfiguration

What is the password of the mysql root user?
[ root password ] je nach Konfiguration

verifying password of user root … done

Enter the name for mysql user of seafile. It would be created if not exists.
[ default „root“ ] seafileusr (zum Beispiel)

Enter the password for mysql user „seafileusr“:
[ password for seafileusr ] Passwort für den neuen Benutzer „seafileusr“

———————————
This is your configuration
———————————
[…]
———————————
Press ENTER to continue, or Ctrl-C to abort
———————————
Enter
—————————————————————–
Your seafile server configuration has been finished successfully.
—————————————————————–

Bitte nicht „root“ als MySQL-Benutzer für Seafile benutzen.

Da ich Seafile via HTTPS benutzen möchte, ändere ich zwei Dateien:

nano ~/servername/ccnet/ccnet.conf

Hier die Option „SERVICE_URL“ suchen und aus „http“ „https“ mache, etwa:

SERVICE_URL = https://cloud.domain.tld

Die Zweite Datei öffnen:

nano ~/servername/seahub_settings.py

Am Ende der Datei einfügen:

FILE_SERVER_ROOT = 'https://cloud.domain.tld/seafhttp'
ACHTUNG: Seit Version 3 wird der Administrator nicht mehr mit dem Setup erstellt.

Erst durch ein einmalig manuelles Starten der Dienste wird hierzu aufgefordert.

~/servername/seafile-server-latest/seafile.sh start
~/servername/seafile-server-latest/seahub.sh start-fastcgi

Es folgt:

What is the email for the admin account?
[ admin email ] username@domain.tld

What is the password for the admin account?
[ admin password ] sicherespasswort

Enter the password again:
[ admin password again ] sicherespasswort

Zum Abschluss noch die manuell gestarteten Dienste wieder beenden:

~/servername/seafile-server-latest/seafile.sh stop
~/servername/seafile-server-latest/seahub.sh stop

Der lokale Webdienst sollte zudem auf „localhost“ gebunden, um direkten externen Zugriff zu verhindern:

nano ~/servername/seafile-data/seafile.conf

Hier nun folgende Änderung vorhehmen:

[fileserver]
host=127.0.0.1
port=8082

Ab hier bitte mit „exit“ die Shell verlassen und zum Beispiel als „root“ weiterarbeiten!

Da der Seafile-Server hinter einem Nginx-Backend via SSL läuft, benötige ich anstatt vier nur drei Freigaben in der Firewall:

443/TCP – HTTPS – IN/OUT
10001/TCP – Ccnet Daemon – IN/OUT
12001/TCP – Seafile Daemon – IN/OUT

Zum Beispiel (kann auch ignoriert werden):

/sbin/iptables -P INPUT DROP
/sbin/iptables -P OUTPUT ACCEPT
/sbin/iptables -I INPUT -i lo -p all -j ACCEPT # Interne Kommunikation via localhost vollständig freigeben
/sbin/iptables -I INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
/sbin/iptables -A INPUT -p tcp -d PUB.LIC.SRV.IP -m state --state NEW -m multiport --dport 10001,12001,443 -j ACCEPT

Achtung: Bitte nicht blind übernehmen, da ihr euch ansonsten von der SSH aussperrt!

Für Nginx richte ich eine neue Site mit der Subdomain „cloud.domain.tld“ ein.
Wird diese Konfiguration übernommen, so bitte den Pfad „/srv/seafile/servername/seafile-server-latest/seahub“ anpassen, ebenso „server_name“, ssl_certificate und ssl_certificate_key:

server {
        listen       80;
        server_name  cloud.domain.tld;
        rewrite ^/(.*) https://$server_name/$1 permanent;
}
server {
        listen 443; #IPv4
        #listen [::]:443; # IPv6
        ssl on;
        ssl_certificate /etc/nginx/certs/ssl-unified.crt;
        ssl_certificate_key /etc/nginx/certs/ssl.key;
        server_name cloud.domain.tld;

        location / {
                fastcgi_pass    127.0.0.1:8000;
                fastcgi_param   SCRIPT_FILENAME     $document_root$fastcgi_script_name;
                fastcgi_param   PATH_INFO           $fastcgi_script_name;

                fastcgi_param   SERVER_PROTOCOL     $server_protocol;
                fastcgi_param   QUERY_STRING        $query_string;
                fastcgi_param   REQUEST_METHOD      $request_method;
                fastcgi_param   CONTENT_TYPE        $content_type;
                fastcgi_param   CONTENT_LENGTH      $content_length;
                fastcgi_param   SERVER_ADDR         $server_addr;
                fastcgi_param   SERVER_PORT         $server_port;
                fastcgi_param   SERVER_NAME         $server_name;

                fastcgi_param   HTTPS on;
                fastcgi_param   HTTP_SCHEME https;
        }

        location /seafhttp {
                rewrite ^/seafhttp(.*)$ $1 break;
                proxy_pass http://127.0.0.1:8082;
                client_max_body_size 0;
        }

        location /media {
                root /srv/seafile/servername/seafile-server-latest/seahub;
        }
}

In diesem Fall erfolgt eine Weiterleitung von HTTP auf HTTPS. PHP oder Sonstiges braucht nicht definiert zu werden!

Nginx nun „reloaden“:

service nginx reload

Bevor das Init-Script angelegt- und der Dienst gestartet wird, werfe ich noch einen Blick in die Datei „hosts“:

nano /etc/hosts

Hier bitte sicherstellen, dass folgender Eintrag vorhanden ist:

127.0.0.1       cloud.domain.tld

Im Git-Repository findet sich ein Init-Script, das Seafile und Seahub als unprivilegierter Benutzer startet, auch lässt sich definieren, dass Seahub nur im FastCGI-Modus gestartet wird.
Ich habe es etwas angepasst.

Das Script erstellen:

nano /etc/init.d/seafile

Der Inhalt, in dem „user“ und „seafile_dir“ bitte angepasst werden:

#!/bin/bash

### BEGIN INIT INFO
# Provides:          seafile
# Required-Start:    $local_fs $remote_fs $network
# Required-Stop:     $local_fs
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Starts Seafile and Seahub
# Description:       starts Seafile and Seahub
### END INIT INFO

#### CONFIG START ####
user=seafile
seafile_dir=/srv/seafile/servername
##### CONFIG END #####

script_path=${seafile_dir}/seafile-server-latest
seafile_init_log=${seafile_dir}/logs/seafile.init.log
seahub_init_log=${seafile_dir}/logs/seahub.init.log
[ -d ${seafile_dir}/logs ] || mkdir ${seafile_dir}/logs && chown $user:$user ${seafile_dir}/logs

# Change the value of fastcgi to true if fastcgi is to be used
fastcgi=true
# Set the port of fastcgi, default is 8000. Change it if you need different.
fastcgi_port=8000

case "$1" in
        start)
                sudo -u ${user} ${script_path}/seafile.sh start >> ${seafile_init_log}
                if [  $fastcgi = true ];
                then
                        sudo -u ${user} ${script_path}/seahub.sh start-fastcgi ${fastcgi_port} >> ${seahub_init_log}
                else
                        sudo -u ${user} ${script_path}/seahub.sh start >> ${seahub_init_log}
                fi
        ;;
        restart)
                sudo -u ${user} ${script_path}/seafile.sh restart >> ${seafile_init_log}
                if [  $fastcgi = true ];
                then
                        sudo -u ${user} ${script_path}/seahub.sh restart-fastcgi ${fastcgi_port} >> ${seahub_init_log}
                else
                        sudo -u ${user} ${script_path}/seahub.sh restart >> ${seahub_init_log}
                fi
        ;;
        stop)
                ${script_path}/seafile.sh $1 >> ${seafile_init_log}
                ${script_path}/seahub.sh $1 >> ${seahub_init_log}
        ;;
        *)
                echo "Usage: /etc/init.d/seafile {start|stop|restart}"
                exit 1
        ;;
esac

Das Script noch als ausführbar markieren und den Dienst installieren sowie starten:

chmod +x /etc/init.d/seafile
update-rc.d seafile defaults
service seafile start

Der Client kann nun installiert und konfiguriert werden.
Vorab darf das Webpanel bewundert und ebenfalls konfiguriert werden: https://cloud.domain.tld

Danke an die Hinweise aus den Kommentaren!