21x9.org

SAML Authentifikation mit Apache und mod_auth_mellon

Categories: [blog]
Tags: [linux], [apache], [debian], [saml], [sso], [idp], [sp], [mellon], [auth]

Eigentlich ist HTTP Basic-Auth ja eine durchaus feine Sache. Schnell eingerichtet und für die meisten Zwecke ausreichend sicher. Aber es gibt auch Nachteile, so können viele (alle?) Browsererweiterungen von gängigen Kennwortsafes diese nicht automatisch ausfüllen. Schlimmer noch, in vielen Browsern verhindert der Anmeldedialog, dass ich überhaupt an meinen Kennwortsafe herankomme (zumindest wenn diese als Browsererweiterung implementiert ist), weil das Fenster den Fokus hat und auch nicht abgeben mag. Also Anmeldevorgang abbrechen, Zugangsdaten raussuchen, neu versuchen. Nervt. Bliebe noch ein Benutzername und Kennwort die man sich merken kann, auch nicht schön.

Schön wäre SSO (und nicht nur, weil es insbesondere komfortabler ist, als das oben geschilderte Szenario). Viele Dienste für Kennwortsafes bieten SAML-IdP (Identity Provider) von Haus aus gleich mit an und wenn man sowas nicht hat, ein IdP ist z.B. mit simplesamlphp auch recht schnell selbst aufgesetzt. Aber wie bringt man das jetzt Apache bei?

Hier hilft mod_auth_mellon (https://github.com/latchset/mod_auth_mellon).

Bei Debian ist mod_auth_mellon bereits als Paket enthalten, die Installation ist also denkbar einfach:

apt install mod_auth_mellon
a2enmod mellon
systemctl restart apache2

Aber ein wenig Konfiguration ist natürlich auch noch nötig. In diesem Beispiel nehmen wir an, dass ein einzelnes Verzeichnis (/restricted) eines Servers (https://test.21x9.org) geschützt werden soll. Hierzu führen wir zunächst das Script /usr/sbin/mellon_create_metadata aus. Es benötigt zwei Parameter ENTITY_ID und ENDPOINT-URL. Das Script erzeugt drei Dateien, die wir in unsere Apache-Konfiguration benötigen. Also erzeugen wir einen entsprechenden Unterordner in /etc/apache2/ und rufen das Script dort auf:

mkdir -p /etc/apache2/mellon
cd /etc/apache2/mellon
/usr/sbin/mellon_create_metadata https://test.21x9.org/restricted/saml/metadata https://test.21x9.org/restricted/saml

Der Output sollte wie folgt aussehen:

Output files:
Private key:               https_test.21x9.org_restricted_saml_metadata.key
Certificate:               https_test.21x9.org_restricted_saml_metadata.cert
Metadata:                  https_test.21x9.org_restricted_saml_metadata.xml

Host:                      test.21x9.org

Endpoints:
SingleLogoutService:       https://test.21x9.org/restricted/saml/logout
AssertionConsumerService:  https://test.21x9.org/restricted/saml/postResponse

Nun können wir uns an die eigentliche Apache-Konfiguration machen. Wir editieren hierzu unsere bestehende VirtualHost-Konfiguration und erweitern diese um die folgenden Einträge:

<Location /restricted>
    MellonEnable "auth"

    MellonSPPrivateKeyFile /etc/apache2/mellon/https_test.21x9.org_restricted_saml_metadata.key
    MellonSPCertFile /etc/apache2/mellon/https_test.21x9.org_restricted_saml_metadata.cert
    MellonSPMetadataFile /etc/apache2/mellon/https_test.21x9.org_restricted_saml_metadata.xml

    MellonIdPMetadataFile /etc/apache2/mellon/idp-metadata.xml
    MellonIdPPublicKeyFile /etc/apache2/mellon/idp-pubkey.pem

    MellonEndpointPath "/restricted/saml"
    MellonIdP "https://identity.idp.example.com"
    Require valid-user
</Location>

Die Dateien /etc/apache2/mellon/idp-metadata.xml und /etc/apache2/mellon/idp-pubkey.pem erhalten wir von unserem SAML-IdP. Diesen müssen wir außerdem mit unseren ServiceProvider (SP) Metadaten bekannt machen. Bei den meisten IdPs reicht es aus hierzu die Datei /etc/apache2/mellon/https_test.21x9.org_restricted_saml_metadata.xml hochzuladen. Sollte der IdP nicht die Möglichkeit bieten, die SP-Metadaten als XML-Datei hochzuladen, hier ein paar oft verwendete Begriffe für die nötigen Angaben:

Sofern möglich sollte der IdP sha-256 statt sha-1 für die Signaturen seiner Antworten nutzen.

Werden mehrere IdPs genutzt, sollte man für jeden IdP natürlich separate XML/PEM-Dateien nutzen und diese bestenfalls weniger generisch benennen, als in diesem Beispiel. Oder sie gleich in eigenen Unterordnern von /etc/apache2/mellon/ ablegen. ;)

Den korrekten Parameter für MellonIdP erhalten wir aus der Datei /etc/apache2/mellon/idp-metadata.xml. Dort gibt es (meist in der 2. Zeile der Datei) folgenden Eintrag:

<EntityDescriptor xmlns="urn:oasis:names:tc:SAML:2.0:metadata" entityID="https://identity.idp.example.com">

Der Wert MellonIdP muss der entityID aus der Metadatendatei des IdP entsprechen. Nach einem Neustart von Apache sollte nun alles passen. Rufen wir nun unsere URL https://test.21x9.org/restricted auf - ohne bereits an unserem IdP angemeldet zu sein - werden wir zur Anmeldemaske unseres IdP weitergeleitet. Geben wir korrekte Anmeldedaten ein, werden wir zurück zu https://test.21x9.org/restricted geleitet und können auf unsere dort hinterlegten Inhalte zugreifen. Sind wir bereits am IdP angemeldet, entfällt die Anmeldemaske und wir können direkt zugreifen (es sollte nur eine kurze Umleitung (zum IdP und zurück) im Browser zu sehen sein und diese auch nur beim ersten Aufruf).

Wer mehrere Verzeichnisse mit immer demselben IdP schützen möchte, kann die Apache-Konfiguration auch wie folgt gestalten:

<Location /> 
    MellonEnable info 

    MellonSPPrivateKeyFile /etc/apache2/mellon/https_test.21x9.org_restricted_saml_metadata.key
    MellonSPCertFile /etc/apache2/mellon/https_test.21x9.org_restricted_saml_metadata.cert
    MellonSPMetadataFile /etc/apache2/mellon/https_test.21x9.org_restricted_saml_metadata.xml

    MellonIdPMetadataFile /etc/apache2/mellon/idp-metadata.xml
    MellonIdPPublicKeyFile /etc/apache2/mellon/idp-pubkey.pem

    MellonEndpointPath "/restricted/saml"
    MellonIdP "https://identity.idp.example.com"
</Location>

<Location /private> 
    AuthType Mellon 
    MellonEnable auth 
    Require valid-user 
</Location>

<Location /restricted> 
    AuthType Mellon 
    MellonEnable auth 
    Require valid-user 
</Location>