Das Aufsetzen eines Joomla-tauglichen Webservers habe ich ja schonmal ausführlich beschrieben. Jetzt stand ich vor der Aufgabe, diesen Webserver SSL-tauglich zu machen. Ich muss zugeben, von SSL und dem Erstellen von Zertifikaten nur wenig Ahnung zu haben. Dementsprechend bin ich auch erstmal einem Tutorial gefolgt, dass im Nachhinein betrachtet sehr rudimentär ist: Ich hatte ein Zertifikat erstellt, hier was kopiert, da was symbolisch verlinkt, den Apache-Webserver etwas umkonfiguriert und SSL lief. Mit Firefox war dieses Tutorial einigermaßen brauchbar. Ich brauchte das Zertifikat nur einmalig genehmigen und es lief. Der Internet Explorer sieht das allerdings etwas anders. Bei jedem neuen Besuch der Seite, beschwerte dieser sich über Zertifikatsfehler, gegen die auch das Importieren des Zertifikats nicht half.
Dank Chris bin ich dann auf die Fährte des Problems gelangt und seine zahlreichen Links und Tipps haben schlussendlich zum Ziel geführt. Meine Nutzer müssen nun nur noch einmalig ein Zertifikate importieren und werden im Internet-Explorer fortan nicht mehr mit Zertifikatfehlern genervt.
Ich habe übrigens Zertifikate selbst erstellen wollen, weil der Webserver nur in einem internen Netz verwendet wird. Er kann und wird somit nicht aus dem Internet angesprochen, womit ich ein kostenpflichtiges (und problemloses) Zertifikat einer Root-CA wie VeriSign überflüssig fand. Andererseits ist das interne Netz ziemlich groß und wird nicht nur von mir und meinen Nutzern verwendet, so dass ich Wert auf die verschlüsselte Übertragung gelegt habe.
Aus diesem Grund war es notwendig, dass ich mich selbst zu einer Certifcate Authority – kurz CA – mache, um meine selbsterstellten Zertifikate zu signieren. Ein Nutzer der Webseite braucht dann nur das CA-Zertifikat importieren und diesem vertrauen. Alle weiteren Zertifikate, die mit diesem signiert sind, werden dann automatisch als vertrauenswürdig eingestuft.
An dieser Stelle möchte ich nun meine Vorgehensweise zusammenfassen, die ich aus Tipps von Chris, Tutorials und persönlichen Trial&Error gesammelt habe.
Zertifikate ertsellen und signieren
Für das Erstellen der Zertifikate habe ich ein Tutorial von HowToForge verwendet, welches sehr ausführlich ist. Allerdings enthält es keine Anleitung zur Installation und vor allem Konfiguration eines Apache. Diesen Punkt habe ich weiter unten ausgeführt.
Zunächst habe ich stumpf nach Anleitung den Ordner ‚CA‘ und darin ’newcerts‘ und ‚private‘ angelegt. Ich habe dies im Home-Verzeichnis von root gemacht, da theoretisch noch andere Personen den Server administrieren können müssen und mein persönlicher Account nur temporär ist. Des Weiteren darf niemand unberechtigtes Zugriff auf diesen Ordner haben, da er Schlüssel enthalten wird, die geheimgehalten werden müssen. Sollte dieser private Schlüssel in falsche Hände gelangen, sind alle damit signierten Zertifikate nicht mehr vertrauenswürdig und müssen gesperrt werden.
server:~# cd /root
server:~# mkdir CA
server:~# cd CA
server:~# mkdir newcerts private
Im Ordner CA werden nun die Dateien ’serial‘ und ‚index.txt‘ erzeugt. ’serial‘ dient – wie der Name schon andeutet – als Quelle für eindeutige Seriennummer und wird bereits beim erstellen mit ’01‘ belegt. Jedesmal wenn ein Zertifikat erstellt wird, wird diese Ziffer automatisch hochgezählt. ‚index.txt‘ stellt eine kleine Datenbank dar, in der meine erstellten Zertifikate verwaltet werden.
server:~# echo '01' >serial
server:~# touch index.txt
Als nächstes wird eine Konfigurationsdatei namens ‚openssl.cnf‘ erstellt
server:~# vi openssl.cnf
und mit folgenden Inhalt befüllt
#
# OpenSSL Konfigurationsdatei
#
dir = .
[ ca ]
default_ca = CA_default
[ CA_default ]
serial = $dir/serial
database = $dir/index.txt
new_certs_dir = $dir/newcerts
certificate = $dir/cacert.pem
private_key = $dir/private/cakey.pem
default_days = 365
default_md = md5
preserve = no
email_in_dn = no
nameopt = default_ca
certopt = default_ca
policy = policy_match
[ policy_match ]
countryName = match
stateOrProvinceName = match
organizationName = match
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ req ]
default_bits = 1024 # size of keys
default_keyfile = key.pem # name of genarted keys
default_md = md5 # message digest algorithm
string_mask = nombstr # permitted characters
distinguished_name = req_distinguished_name
req_extensions = v3_req
[ req_distinguished_name ]
# Variable name Prombt string
#--------------------- --------------------
0.organizationName = Organization Name
organizationalUnitName = Organizational Unit
emailAddress = Email Address
emailAddress_max = 40
localityName = Locality Name
stateOrProvinceName = Province or State
countryName = Country Name (2 letter code)
countryName_min = 2
countryName_max = 2
commonName = Common Name
commonName_max = 64
# Default values for the above, for the consistency and less typing.
# Variable name Value
#----------------------------- ------------------------------------
0.organizationName_default = Meine Firma
localityName_default = Meine Stadt
stateOrProvinceName_default = Mein Bundesland
countryName_default = DE
[ v3_ca ]
basicConstraints = CA:TRUE
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer:always
[ v3_req ]
basicConstraints = CA:FALSE
subjectKeyIdentifier = hash
Konfigurationsdatei zum Download (muss anschließend in openssl.cnf umbenannt und an die eigenen Gegebenheiten angepasst werden).
Die Bedeutung der einzelnen Abschnitte können oben erwähnten HowTo entnommen werden. Ab jetzt werden Zertifikate erstellt. Als erstes wird das Zertifikat und der private Schlüssel der CA erstellt:
server:~# openssl req -new -x509 -extensions v3_ca -keyout private/cakey.pem↵
-out cacert.pem -days 3650 -config ./openssl.cnf
Mit ‚req -x509‘ wird das eigentliche Zertifikat generiert, ‚-extensions v3_ca‘ gibt dabei die Art des Zertifikats an, wie es im entsprechenden Abschnitt der Konfiguration angegeben ist (hier also ein CA-Zertifikat mit Passwort). Der private Schlüssel wird in das ‚private‘-Verzeichnis geschrieben, des Zertifikat selbst in den aktuellen Ordner. Das Zertifikat der CA selbst erhält eine Lebensdauer von 10 Jahren. Das ist durchaus sinnvoll, da mit Ablauf des CA-Zertifikats alle damit signierten Zertifikate ihre Gültigkeit verlieren würden. Die Gültigkeit der einzelnen Zertifikate ist in der Konfigurationsdatei mit ‚default_days = 365‘ auf ein Jahr festgelegt.
Im nächsten Schritt wird der Zertifikats-Request erstellt, mit dem zukünftig der Webserver authentifiziert werden soll.
server:~# openssl req -new -nodes -out req.pem -config ./openssl.cnf
Im folgenden Dialog sind der „Organizational Unit Name“ (OU), die Kontak-Email-Adresse sowie der „Common Name“ (CN) nacheinander anzugeben. Als OU kann man einen Hinweis daruf geben, wofür das Zertifikat gedacht ist (bsp. eben für den Webserver). Der CN ist die IP oder FQDN des Systems, dass mit diesem Zertifikat authentifiziert werden soll. Im Falle des Webservers wäre das genau die Adresse, die man im Browser angeben würde. Ist der CN falsch und stimmt nicht mit der Adresse überein wird sich der Browser über einen Zertifkatfehler beschweren, da er davon ausgeht, dass das Zertifikat missbraucht wird (dieser Fehler ist mir u.a. auch unterlaufen, weshalb der IE sich so penetrant beschwert hat).
Als Ergebnis erhält man zwei Dateien: den privaten Schlüssel des Zertifikats (key.pem) und den Zertifikats-Request (req.pem). Dieser Request kann übrigens wiederverwendet werden, wenn das Zertifikat nach Ablauf der Gültigkeit erneut signiert werden muss. Beide Dateien sollte man also aufheben.
Nun muss der Zertifikats-Request von der selbsterstellten CA signiert werden. Das abgefragte Passwort ist jenes, welches beim Erstellen des CA-Zertifikats zu Beginn vergeben wurde.
server:~# openssl ca -out cert.pem -config ./openssl.cnf -infiles req.pem
Als Output erhält man das Zertifikat (cert.pem) sowie eine Kopie im Ornder ’newcerts‘, welche die aktuelle Seriennummer (aus ’serial‘) als Namen trägt. Die Datenbank ‚index.txt‘ wurde um einen Eintrag erweitert.
Jede Zeile darin steht für ein Zertifikat. In der ersten Spalte steht ein Buchstabe, der das jeweilige Zertifkat als gültig (V wie valid), abgelaufen (E wie expired) oder zurückgezogen (R wie revoked) kennzeichnet. In der zweiten Spalte ist das Ablaufdatum des Zertifikats angegeben in der Form YYMMDDHHmmssZ (wobei Z für Zulu-Zeit steht – also Greenwich Mean Time). Die dritte Spalte enthält das Rückzugsdatum des Zertifikats und ist beim Status V oder E entsprechend leer. Die vierte Zeile enthält die Seriennummer, die aus der ’serial‘ heraus vergeben wurde. Die fünfte Spalte enthält den Speicherort und die sechste Spalte den Distinguished Name (also C,ST,O,OU und CN wie sie im CA-Zertifikat bzw. dem ausgestellten Zertifikat festgelegt wurden).
Die Ausgabedatei enthält nun die verschlüsselte und die lesbare Version des Zertifikats. Um beides zu trennen ist folgendes nötig:
server:~# mv cert.pem tmp.pem
server:~# openssl x509 -in tmp.pem -out cert.pem
Zu guter Letzt muss das CA-Zertifikat an den Nutzer gebracht werden. Je nach Möglichkeiten kann man es auf Netzlaufwerken oder per Mail den Nutzern zukommen lassen. Man kann das Zertifikat aber auch zum Download als crt-Datei anbieten. Dazu reicht es die Datei ‚cacert.pem‘ in das www-Verzeichnis zu kopieren und umzubennen und die Besitzverhältnisse neu zu regeln.
server:~# cp cacert.pem /var/www/meinpfad/beliebiger_name.crt
server:~# chown www-data:www-data /var/www/meinpfad/beliebiger_name.crt
Das Zertifikat kann nun über die entsprechende Web-Adresse abgerufen werden. Beim Öffnen des Zertifikats wird man in der Regel automatisch durch die lokale Installation geführt. Anschließend sollten alle damit signierten Zertifikate anstandslos von IE und Firefox akzeptiert werden.
Apache SSL-fähig machen
Um den Apache SSL-fähig zu machen, bin ich wie folgt vorgegangen. Ich habe zunächst im Apache-Ordner ein Verzeichnis für Zertifikate angelegt und mein Zertifikat nebst Schlüssel dorthin kopiert.
server:~# mkdir /etc/apache2/ssl
server:~# cp /root/CA/cert.pem /etc/apache2/ssl/cert.pem
server:~# cp /root/CA/key.pem /etc/apache2/ssl/key.pem
Im Ordner ‚/etc/apache2/sites-available‘ habe ich nun eine neue Datei namens ’ssl‘ angelegt
server:~# vi /etc/apache2/sites-available/ssl
und mit folgendem Inhalt befüllt:
<VirtualHost *:443>
DocumentRoot "/var/www/pfad"
<Directory "/var/www/pfad">
allow from all
Options +Indexes
</Directory>
SSLEngine on
SSLCertificateFile /etc/apache2/ssl/cert.pem
SSLCertificateKeyFile /etc/apache2/ssl/key.pem
</VirtualHost>
Nun noch einen Link unter ’sites-enabled‘ auf die eben erstellte Datei setzen
server:~# ln -s /etc/apache2/sites-available/ssl /etc/apache2/sites-enabled/ssl
Damit der Apache auch weiß, dass er auf Port 443 lauschen soll, notiert man dies in der ‚/etc/apache2/ports.conf‘ mit
Listen 443
Abschließend muss das SSL-Modul akitiviert und Apache neu gestartet werden
server:~# a2enmod ssl
server:~# /etc/init.d/apache2 restart
Alternativ kann man diese Konfiguration auch im Webmin vornehmen. Ab diesem Zeitpunkt sollte der Webserver SSL-verschlüsselt laufen.
Ich hoffe, das ich nichts vergessen oder durcheinander gebracht habe. Wenn doch, möge man mich kurz per Mail, Kommentar oder Twitter darauf hinweisen und ich arbeite dann die Korrektur ein. Ich kann Fehler – gerade im Bereich Apache – nicht aussschließen, da ich durch ein zu schnelles ‚Enter‘ mir zwischenzeitlich die komplette Apache-Konfigurations zerschossen habe.
U.a. bekam ich auch die Fehlermeldung „Could not bind on address [::]:443“ beim Start des Apache, was daran lag, dass – warum auch immer – in der ‚ports.conf‘ zweimal der Eintrag ‚Listen 443‘ stand.