Ich habe häufiger das Problem, dass Dienste keine Authentifizierung haben und bequem per Internet erreichbar sein müssen oder man möchte bestimmte Ressourcen schützen. Weiterhin möchte man aus Bequemlichkeit ein Whitelisting für bestimmte IP-Netze oder IPs. Es gibt auch ein LDAP oder Active Directory. Im folgenden Beispiel gilt das Netz 192.88.99.0/24 und die IP 203.0.113.42 als vertrauenswürdig. Wir haben die Domains foo.example, bar.example, geheim.example und streng.geheim.example. Die Dienste geheim.example und streng.geheim.example müssen geschützt werden.
Umsetzung
Ich benutze wieder mein persönliches Schweizer Taschenmesser: HAProxy mit map-Files. Der HAProxy nimmt auf Port 80 undn 443 Verbindungen entgegen. Den Port 81 verwende ich nur für internen Traffic. Dieser ist nicht extern erreichbar. Alle HTTP Verbindungen von bekannten Domains bekommen einen Redirect zu HTTPS. Man sollte keine unbekannten Domains umleiten, da man für diese kein Zertifikat hat. Aus diesem Grund werden diese Anfragen zum Backend bk_error weitergeleitet. Dabei kann es sich um eine Fehlerseite oder eine Umleitung auf die eigene Homepage handeln.
Es gibt 2 Map-Files. In der Datei /etc/haproxy/hosts_for_basisauth.map
befinden sich alle Domains, welche eine
Authentifizierung benötigen. Die Datei /etc/haproxy/hostname2backend.map
ist ein klassisches Map-File, welches einer
Domain ein Backend zuordnet. Für die Authentifizierung kann man einen Apache mit einer Basic Auth und Reverse Proxy verwenden.
Dieser lauscht auf Port 127.0.0.1:8080 und leitet alles an den HAProxy zu 127.0.0.1:81 weiter. Das Whielisting wird über die
ACL intern gesteuert, wobei dst_port 81 Pflicht ist. Sonst hat man eine Schleife gebaut.
/etc/haproxy/hosts_for_basisauth.map
geheim.example
streng.geheim.example
/etc/haproxy/hostname2backend.map
foo.example foo_example
bar.example bar_example
geheim.example geheim_example
streng.geheim.example streng_geheim_example
Ausschnitt aus der haproxy.cfg
...
frontend http
bind *:80 name http
bind *:443 name https ssl crt /etc/haproxy/certs/star.pem
bind 127.0.0.1:81 name intern
# HSTS (31536000 seconds = 1 year)
http-response set-header Strict-Transport-Security max-age=31536000
# set protocoll headers to https
# works only if all https redirects happens in HAProxy
http-request set-header X-Forwarded-Proto https
# trusted sources
acl intern src 192.88.99.0/24
acl intern src 203.0.113.42
acl intern dst_port 81
# force https for known domains
acl hostname_has_backend hdr(Host),lower,map(/etc/haproxy/hostname2backend.map) -m found
http-request redirect scheme https code 301 if !{ ssl_fc } hostname_has_backend !{ dst_port 81 }
# routing with basic auth and whitelisting for ACL intern
acl basic-auth_domain hdr(Host),lower,map(/etc/haproxy/hosts_for_basisauth.map) -m found
use_backend bk_basic-auth if basic-auth_domain !intern
# routing for known domains
use_backend bk_%[hdr(Host),lower,map(/etc/haproxy/hostname2backend.map)] if hostname_has_backend
default_backend bk_error
backend bk_basic-auth
server apache 127.0.0.1:8080 check
...
Fazit
Mit diesem Ansatz kann man bequem eine Basic Auth realisieren. Man muss nur 2 Map-Files pflegen, was die Wartung und die Generierung der Konfiguration mit Puppet oder Ansible sehr einfach macht.