Debian + Postfix + Dovecot + Multidomain + SSL + IPv6 + OpenVPN + Multi-Schnittstellen + SpamAssassin-learn + Bind

Dieser Artikel handelt davon, wie man einen modernen Mailserver einrichtet.
Postfix + Dovecot. SPF + DKIM + rDNS. Mit IPv6.
Mit TSL-VerschlĂŒsselung. Mit UnterstĂŒtzung fĂŒr mehrere Domains – Teil mit echtem SSL-Zertifikat.
Mit Antispam-Schutz und hoher Antispam-Bewertung bei anderen Mailservern.
Mit UnterstĂŒtzung fĂŒr mehrere physische Schnittstellen.
Mit OpenVPN, dessen Verbindung ĂŒber IPv4 erfolgt und das IPv6 bereitstellt.

Wenn Sie all diese Technologien nicht lernen möchten, aber einen solchen Server einrichten wollen – dann ist dieser Artikel fĂŒr Sie.

Der Artikel enthĂ€lt keine Versuche, jedes Detail zu erklĂ€ren. Die ErklĂ€rungen beziehen sich darauf, was nicht standardmĂ€ĂŸig eingerichtet ist oder aus Sicht des Verbrauchers wichtig ist.

Die Motivation, einen Mailserver einzurichten, ist ein lange gehegter Traum von mir. Vielleicht klingt das lÀcherlich, aber IMHO ist es viel besser, als von einem neuen Auto meiner Lieblingsmarke zu trÀumen.

Die Motivation, IPv6 einzurichten, hat zwei GrĂŒnde. IT-Profis mĂŒssen stĂ€ndig neue Technologien lernen, um zu ĂŒberleben. Ich möchte meinen bescheidenen Beitrag im Kampf gegen Zensur leisten.

Die Motivation zur Einrichtung von OpenVPN – nur damit IPv6 auf der lokalen Maschine funktioniert.
Die Motivation, mehrere physische Schnittstellen einzurichten – ich habe auf dem Server eine Schnittstelle "langsam, aber unbegrenzt" und eine andere "schnell, aber mit Tarif".

Die Motivation, Bind einzurichten – mein Provider stellt einen instabilen DNS-Server zur VerfĂŒgung, und Google hat auch manchmal AusfĂ€lle. Ich möchte einen stabilen DNS-Server fĂŒr den persönlichen Gebrauch.

Die Motivation, einen Artikel zu schreiben – der Entwurf wurde vor 10 Monaten verfasst, und ich habe ihn bereits zweimal angesehen. Wenn der Autor das regelmĂ€ĂŸig braucht, ist die Wahrscheinlichkeit groß, dass auch anderen dies notwendig ist.

Es gibt keine universelle Lösung fĂŒr Mailserver. Aber ich werde versuchen, so etwas wie "machen Sie es so und dann, wenn alles funktioniert, wie es sollte – werfen Sie das ÜberflĂŒssige weg" zu schreiben.

Es gibt einen Colocation-Server bei der Firma tech.ru. Es ist möglich, mit OVH, Hetzner, AWS zu vergleichen. FĂŒr diese Aufgabe wird die Zusammenarbeit mit tech.ru viel effizienter sein.

Auf dem Server ist Debian 9 installiert.

Der Server hat 2 Schnittstellen `eno1` und `eno2`. Die erste ist unbegrenzt, die zweite schnell.

Es gibt 3 statische IP-Adressen, XX.XX.XX.X0 und XX.XX.XX.X1 und XX.XX.XX.X2 auf der Schnittstelle `eno1` und XX.XX.XX.X5 auf der Schnittstelle `eno2`.

Es gibt XXXX:XXXX:XXXX:XXXX::/64 Pool von IPv6-Adressen, die der Schnittstelle `eno1` zugewiesen sind, und auf meine Anfrage hin wurde XXXX:XXXX:XXXX:XXXX:1:2::/96 zu `eno2` zugewiesen.

Es gibt 3 Domains `domain1.com`, `domain2.com`, `domain3.com`. FĂŒr `domain1.com` und `domain3.com` gibt es ein SSL-Zertifikat.

Es gibt ein Google-Konto, an das ich das Postfach `vasya.pupkin@domain1.com` (zum Empfangen und Senden von E-Mails direkt aus der Gmail-OberflÀche) anbinden möchte.
Es muss ein Postfach `support@domain2.com` eingerichtet werden, von dem ich eine Kopie der E-Mails in meinem Gmail-Postfach sehen möchte. Und ich sollte selten die Möglichkeit haben, etwas im Namen von `support@domain2.com` ĂŒber die Web-OberflĂ€che zu senden.

Es muss ein Postfach `ivanov@domain3.com` eingerichtet werden, das von Ivanov auf seinem iPhone genutzt wird.

Die gesendeten E-Mails mĂŒssen allen modernen Anforderungen an Antispam entsprechen.
Es muss das höchste Maß an VerschlĂŒsselung vorgesehen sein, das in öffentlichen Netzwerken verfĂŒgbar ist.
Es muss IPv6-UnterstĂŒtzung sowohl fĂŒr das Senden als auch fĂŒr das Empfangen von E-Mails geben.
Es muss SpamAssassin vorhanden sein, der niemals E-Mails löschen wird, sondern entweder zurĂŒckwerfen oder durchlassen oder in den IMAP-Ordner „Spam“ verschieben wird.
Es muss ein automatisches Lernen von SpamAssassin eingerichtet werden: Wenn ich eine E-Mail in den Ordner „Spam“ verschiebe, soll er daraus lernen; wenn ich eine E-Mail aus dem Ordner „Spam“ verschiebe, soll er auch daraus lernen. Die Lernergebnisse von SpamAssassin sollen die Wahrscheinlichkeit beeinflussen, dass eine E-Mail im Ordner „Spam“ landet.
PHP-Skripte mĂŒssen in der Lage sein, E-Mails im Namen einer beliebigen Domain auf diesem Server zu senden.
Es muss einen OpenVPN-Dienst mit der Möglichkeit geben, IPv6 auf einem Client zu nutzen, der kein IPv6 hat.

Zuerst mĂŒssen die Schnittstellen und das Routing, einschließlich IPv6, eingerichtet werden.
Dann muss OpenVPN eingerichtet werden, das sich ĂŒber IPv4 verbindet und dem Client eine statische, reale IPv6-Adresse bereitstellt. Dieser Client hat Zugang zu allen IPv6-Diensten auf dem Server und Zugriff auf alle Ressourcen im Internet mit IPv6.
Dann muss Postfix zum Senden von E-Mails + SPF + DKIM + rDNS und andere Àhnliche Dinge eingerichtet werden.
Dann muss Dovecot eingerichtet und Multidomain konfiguriert werden.
Dann muss SpamAssassin eingerichtet und das Lernen konfiguriert werden.
Zum Schluss muss Bind installiert werden.

============= Multi-interfaces =============

FĂŒr die Konfiguration der Schnittstellen muss Folgendes in „/etc/network/interfaces“ geschrieben werden.

# The loopback network interface
auto lo
iface lo inet loopback

# The primary network interface
allow-hotplug eno1
iface eno1 inet static
        address XX.XX.XX.X0/24
        gateway XX.XX.XX.1
        dns-nameservers 127.0.0.1 213.248.1.6
        post-up ip route add XX.XX.XX.0/24 dev eno1 src XX.XX.XX.X0 table eno1t
        post-up ip route add default via XX.XX.XX.1 table eno1t
        post-up ip rule add table eno1t from XX.XX.XX.X0
        post-up ip rule add table eno1t to XX.XX.XX.X0

auto eno1:1
iface eno1:1 inet static
address XX.XX.XX.X1
netmask 255.255.255.0
        post-up ip rule add table eno1t from XX.XX.XX.X1
        post-up ip rule add table eno1t to XX.XX.XX.X1
        post-up   ip route add 10.8.0.0/24 dev tun0 src XX.XX.XX.X1 table eno1t
        post-down ip route del 10.8.0.0/24 dev tun0 src XX.XX.XX.X1 table eno1t

auto eno1:2
iface eno1:2 inet static
address XX.XX.XX.X2
netmask 255.255.255.0
        post-up ip rule add table eno1t from XX.XX.XX.X2
        post-up ip rule add table eno1t to XX.XX.XX.X2

iface eno1 inet6 static
        address XXXX:XXXX:XXXX:XXXX:1:1::/64
        gateway XXXX:XXXX:XXXX:XXXX::1
        up   ip -6 addr add XXXX:XXXX:XXXX:XXXX:1:1:1:1/64 dev $IFACE
        up   ip -6 addr add XXXX:XXXX:XXXX:XXXX:1:1:1:2/64 dev $IFACE
        down ip -6 addr del XXXX:XXXX:XXXX:XXXX:1:1:1:1/64 dev $IFACE
        down ip -6 addr del XXXX:XXXX:XXXX:XXXX:1:1:1:2/64 dev $IFACE

# The secondary network interface
allow-hotplug eno2
iface eno2 inet static
        address XX.XX.XX.X5
        netmask 255.255.255.0
        post-up   ip route add XX.XX.XX.0/24 dev eno2 src XX.XX.XX.X5 table eno2t
        post-up   ip route add default via XX.XX.XX.1 table eno2t
        post-up   ip rule add table eno2t from XX.XX.XX.X5
        post-up   ip rule add table eno2t to XX.XX.XX.X5
        post-up   ip route add 10.8.0.0/24 dev tun0 src XX.XX.XX.X5 table eno2t
        post-down ip route del 10.8.0.0/24 dev tun0 src XX.XX.XX.X5 table eno2t

iface eno2 inet6 static
        address XXXX:XXXX:XXXX:XXXX:1:2::/96
        up   ip -6 addr add XXXX:XXXX:XXXX:XXXX:1:2:1:1/64 dev $IFACE
        up   ip -6 addr add XXXX:XXXX:XXXX:XXXX:1:2:1:2/64 dev $IFACE
        down ip -6 addr del XXXX:XXXX:XXXX:XXXX:1:2:1:1/64 dev $IFACE
        down ip -6 addr del XXXX:XXXX:XXXX:XXXX:1:2:1:2/64 dev $IFACE

# OpenVPN network
iface tun0 inet6 static
        address XXXX:XXXX:XXXX:XXXX:1:3::/80

Diese Einstellungen können auf jedem Server in tech.ru angewendet werden (mit kleiner Abstimmung mit dem Support) und es wird sofort wie gewĂŒnscht funktionieren.

Wenn Sie Erfahrung mit der Konfiguration Ă€hnlicher Dinge fĂŒr Hetzner, OVH haben – dort ist es anders. Komplizierter.

eno1 – das ist der Name der Netzwerkkarte #1 (langsam, aber unbegrenzt).
eno2 – das ist der Name der Netzwerkkarte #2 (schnell, aber kostenpflichtig).
tun0 – das ist der Name der virtuellen Netzwerkkarte von OpenVPN.
XX.XX.XX.X0 – IPv4 #1 auf eno1.
XX.XX.XX.X1 – IPv4 #2 auf eno1.
XX.XX.XX.X2 – IPv4 #3 auf eno1.
XX.XX.XX.X5 – IPv4 #1 auf eno2.
XX.XX.XX.1 – IPv4 Gateway.
XXXX:XXXX:XXXX:XXXX::/64 – IPv6 fĂŒr den gesamten Server.
XXXX:XXXX:XXXX:XXXX:1:2::/96 – IPv6 fĂŒr eno2, alles andere geht von außen ĂŒber eno1.
XXXX:XXXX:XXXX:XXXX::1 – IPv6 Gateway (es ist erwĂ€hnenswert, dass dies anders gemacht werden kann/sollte. Die IPv6 des Switches anzugeben).
dns-nameservers – angegeben sind 127.0.0.1 (da local bind installiert ist) und 213.248.1.6 (das ist von tech.ru).

„table eno1t“ und „table eno2t“ – der Sinn dieser route-rule ist, dass der Verkehr, der ĂŒber eno1 hereinkommt, auch darĂŒber hinausgeht, und der Verkehr, der ĂŒber eno2 hereinkommt, auch darĂŒber hinausgeht. Außerdem sollten Verbindungen, die vom Server initiiert werden, ĂŒber eno1 gehen.

ip route add default via XX.XX.XX.1 table eno1t

Mit diesem Befehl geben wir an, dass jeglicher unbekannter Verkehr, der unter eine Regel fĂ€llt, die mit „table eno1t“ gekennzeichnet ist, an das Interface eno1 weitergeleitet werden soll.

ip route add XX.XX.XX.0/24 dev eno1 src XX.XX.XX.X0 table eno1t

Mit diesem Befehl geben wir an, dass jeglicher serverinitiierten Verkehr an das Interface eno1 weitergeleitet wird.

ip rule add table eno1t from XX.XX.XX.X0
ip rule add table eno1t to XX.XX.XX.X0

Mit diesem Befehl geben wir die Regeln zur Markierung des Verkehrs an.

auto eno1:2
iface eno1:2 inet static
address XX.XX.XX.X2
netmask 255.255.255.0
        post-up ip rule add table eno1t from XX.XX.XX.X2
        post-up ip rule add table eno1t to XX.XX.XX.X2

Dieser Block legt die zweite IPv4-Adresse fĂŒr das Interface eno1 fest.

ip route add 10.8.0.0/24 dev tun0 src XX.XX.XX.X1 table eno1t

Mit diesem Befehl geben wir die Route von OpenVPN-Klienten zu den lokalen IPv4-Adressen, außer XX.XX.XX.X0, an.
Warum dieser Befehl fĂŒr alle IPv4 ausreichend ist, verstehe ich bis heute nicht.

iface eno1 inet6 static
        address XXXX:XXXX:XXXX:XXXX:1:1::/64
        gateway XXXX:XXXX:XXXX:XXXX::1

Hier geben wir die Adresse fĂŒr die Schnittstelle selbst an. Der Server wird sie als „ausgehende“ Adresse verwenden. Ansonsten wird sie nicht weiter genutzt.

Warum „:1:1::“ so kompliziert angegeben ist? Damit OpenVPN richtig funktioniert und nur dafĂŒr. DarĂŒber spĂ€ter mehr.

Zum Thema Gateway – so funktioniert es und damit gut. Aber richtig mĂŒsste hier die IPv6 des Switches angegeben werden, an den der Server angeschlossen ist.

Warum IPv6 jedoch nicht mehr funktioniert, wenn ich es so mache, ist mir ein RĂ€tsel. Wahrscheinlich sind das Probleme von tech.ru.

ip -6 addr add XXXX:XXXX:XXXX:XXXX:1:1:1:1/64 dev $IFACE

Dies ist das HinzufĂŒgen einer IPv6-Adresse zur Schnittstelle. Wenn man einhundert Adressen benötigt, bedeutet das einhundert Zeilen in dieser Datei.

iface eno1 inet6 static
        address XXXX:XXXX:XXXX:XXXX:1:1::/64
...
iface eno2 inet6 static
        address XXXX:XXXX:XXXX:XXXX:1:2::/96
...
iface tun0 inet6 static
        address XXXX:XXXX:XXXX:XXXX:1:3::/80

Ich habe die Adressen und Subnetze aller Schnittstellen markiert, um es ĂŒbersichtlich zu machen.
eno1 muss unbedingt "/64" sein, denn das ist unser gesamter Pool von Adressen.
tun0 muss unbedingt ein grĂ¶ĂŸeres Subnetz als eno1 haben. Andernfalls kann das IPv6-Gateway fĂŒr OpenVPN-Kunden nicht eingerichtet werden.
eno2 muss unbedingt ein grĂ¶ĂŸeres Subnetz als tun0 haben. Andernfalls können OpenVPN-Kunden nicht auf die lokalen IPv6-Adressen zugreifen.
Zur besseren Übersicht habe ich einen Subnetz-Schritt von 16 gewĂ€hlt, aber wenn gewĂŒnscht, kann man sogar einen Schritt von "1" machen.
Entsprechend 64+16 = 80 und 80+16 = 96.

Zur noch besseren Veranschaulichung:
XXXX:XXXX:XXXX:XXXX:1:1:YYYY:YYYY – das sind Adressen, die bestimmten Websites oder Diensten an der Schnittstelle eno1 zugewiesen werden sollen.
XXXX:XXXX:XXXX:XXXX:1:2:YYYY:YYYY – das sind Adressen, die bestimmten Websites oder Diensten an der Schnittstelle eno2 zugewiesen werden sollen.
XXXX:XXXX:XXXX:XXXX:1:3:YYYY:YYYY – das sind Adressen, die OpenVPN-Kunden zugewiesen werden sollen oder als Dienstadressen fĂŒr OpenVPN verwendet werden.

FĂŒr die Netzwerkkonfiguration muss der Server neu gestartet werden können.
IPv4-Änderungen werden beim AusfĂŒhren ĂŒbernommen (unbedingt in screen einwickeln – andernfalls wird diese Befehlszeile einfach das Netzwerk auf dem Server zum Absturz bringen):

/etc/init.d/networking restart

Am Ende der Datei "/etc/iproute2/rt_tables" hinzufĂŒgen:

100 eno1t
101 eno2t

Ohne dies kann man keine benutzerdefinierten Tabellen in der Datei "/etc/network/interfaces" verwenden.
Die Zahlen mĂŒssen eindeutig und kleiner als 65535 sein.

IPv6-Änderungen können leicht ohne Neustart vorgenommen werden, dafĂŒr muss man aber mindestens drei Befehle lernen:

ip -6 addr ...
ip -6 route ...
ip -6 neigh ...

Konfiguration von "/etc/sysctl.conf"

# Uncomment the next line to enable packet forwarding for IPv4
net.ipv4.ip_forward = 1

# Do not accept ICMP redirects (prevent MITM attacks)
net.ipv4.conf.all.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0

# Do not send ICMP redirects (we are not a router)
net.ipv4.conf.all.send_redirects = 0

# For receiving ARP replies
net.ipv4.conf.all.arp_filter = 0
net.ipv4.conf.default.arp_filter = 0

# For sending ARP
net.ipv4.conf.all.arp_announce = 0
net.ipv4.conf.default.arp_announce = 0

# Enable IPv6
net.ipv6.conf.all.disable_ipv6 = 0
net.ipv6.conf.default.disable_ipv6 = 0
net.ipv6.conf.lo.disable_ipv6 = 0

# IPv6 configuration
net.ipv6.conf.all.autoconf = 1
net.ipv6.conf.all.accept_ra = 0

# For OpenVPN
net.ipv6.conf.all.forwarding = 1
net.ipv6.conf.all.proxy_ndp = 1

# For nginx on boot
net.ipv6.ip_nonlocal_bind = 1

Das sind die "sysctl"-Einstellungen meines Servers. Ich werde das Wichtige hervorheben.

net.ipv4.ip_forward = 1

Ohne dies wird OpenVPN ĂŒberhaupt nicht funktionieren.

net.ipv6.ip_nonlocal_bind = 1

Jeder, der versucht, IPv6 zu binden (zum Beispiel nginx), erhĂ€lt sofort einen Fehler, wenn die Schnittstelle aktiviert wurde – dass die Adresse nicht verfĂŒgbar ist.

Um diese Situation zu vermeiden, wird diese Einstellung vorgenommen.

net.ipv6.conf.all.forwarding = 1
net.ipv6.conf.all.proxy_ndp = 1

Ohne diese Einstellungen kann der IPv6-Verkehr vom OpenVPN-Kunden nicht in die Welt gelangen.

Andere Einstellungen beziehen sich entweder nicht darauf oder ich erinnere mich nicht, warum sie nötig sind.
Aber ich lasse es zur Sicherheit "wie es ist".

Um sicherzustellen, dass die Änderungen dieser Datei ohne einen Server-Neustart ĂŒbernommen werden, muss der Befehl ausgefĂŒhrt werden:

sysctl -p

Mehr Details zu den "tabellen"-Regeln: habr.com/post/108690

============= OpenVPN =============

OpenVPN IPv4 funktioniert nicht ohne iptables.

Ich habe solche iptables fĂŒr VPN:

iptables -A INPUT -p udp -s YY.YY.YY.YY --dport 1194 -j ACCEPT
iptables -A FORWARD -i tun0 -o eno1 -j ACCEPT
iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eno1 -j SNAT --to-source XX.XX.XX.X0
##iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eno1 -j MASQUERADE
iptables -A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -A INPUT -p udp --dport 1194 -j DROP
iptables -A FORWARD -p udp --dport 1194 -j DROP

YY.YY.YY.YY ist meine statische IPv4-Adresse des lokalen Rechners.
10.8.0.0/24 ist das IPv4-Netzwerk von openvpn. IPv4-Adressen fĂŒr openvpn-Clients.
Die Reihenfolge der Regeln ist wichtig.

iptables -A INPUT -p udp -s YY.YY.YY.YY --dport 1194 -j ACCEPT
iptables -A FORWARD -i tun0 -o eno1 -j ACCEPT
...
iptables -A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
iptables -A INPUT -p udp --dport 1194 -j DROP
iptables -A FORWARD -p udp --dport 1194 -j DROP

Diese EinschrÀnkung stellt sicher, dass nur ich von meiner statischen IP auf OpenVPN zugreifen kann.

iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eno1 -j SNAT --to-source XX.XX.XX.X0
  -- oder --
iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eno1 -j MASQUERADE

Um IPv4-Pakete zwischen OpenVPN-Clients und dem Internet weiterzuleiten, muss einer dieser Befehle eingegeben werden.

FĂŒr verschiedene FĂ€lle ist eine der Optionen nicht geeignet.
In meinem Fall sind beide Befehle geeignet.
Nach dem Lesen der Dokumentation habe ich die erste Option gewÀhlt, da sie weniger CPU-Ressourcen benötigt.

Um alle iptables-Einstellungen nach einem Neustart zu ĂŒbernehmen, mĂŒssen sie irgendwo gespeichert werden.

iptables-save > /etc/iptables/rules.v4
ip6tables-save > /etc/iptables/rules.v6

Diese Namen sind nicht zufĂ€llig gewĂ€hlt. Sie werden vom Paket „iptables-persistent“ verwendet.

apt-get install iptables-persistent

Installation des Hauptpakets OpenVPN:

apt-get install openvpn easy-rsa

Lassen Sie uns eine Vorlage fĂŒr die Zertifikate einrichten (setzen Sie Ihre Werte ein):

make-cadir ~/openvpn-ca
cd ~/openvpn-ca
ln -s openssl-1.0.0.cnf openssl.cnf

Lassen Sie uns die Einstellungen der Zertifikatvorlage bearbeiten:

mcedit vars

...
# Dies sind die Standardwerte fĂŒr die Felder
# die im Zertifikat platziert werden.
# Lassen Sie keines dieser Felder leer.
export KEY_COUNTRY="RU"
export KEY_PROVINCE="Krasnodar"
export KEY_CITY="Dinskaya"
export KEY_ORG="Eigentum"
export KEY_EMAIL="admin@domain1.com"
export KEY_OU="VPN"

# X509 Subject Field
export KEY_NAME="server"
...

Wir erstellen ein Serverzertifikat:

cd ~/openvpn-ca
source vars
./clean-all
./build-ca
./build-key-server server
./build-dh
openvpn --genkey --secret keys/ta.key

Bereiten wir die Möglichkeit vor, endgĂŒltige „client-name.opvn“-Dateien zu erstellen:

mkdir -p ~/client-configs/files
chmod 700 ~/client-configs/files
cp /usr/share/doc/openvpn/examples/sample-config-files/client.conf ~/client-configs/base.conf
mcedit ~/client-configs/base.conf

# Client mode
client

# Interface tunnel type
dev tun

# TCP protocol
proto tcp-client

# Address/Port of VPN server
remote XX.XX.XX.X0 1194

# Don't bind to local port/address
nobind

# Don't need to re-read keys and re-create tun at restart
persist-key
persist-tun

# Remote peer must have a signed certificate
remote-cert-tls server
ns-cert-type server

# Enable compression
comp-lzo

# Custom
ns-cert-type server
tls-auth ta.key 1
cipher DES-EDE3-CBC

Bereiten wir ein Skript vor, das alle Dateien zu einer einzigen opvn-Datei zusammenschnĂŒrt.

mcedit ~/client-configs/make_config.sh
chmod 700 ~/client-configs/make_config.sh

#!/bin/bash

# First argument: Client identifier

KEY_DIR=~/openvpn-ca/keys
OUTPUT_DIR=~/client-configs/files
BASE_CONFIG=~/client-configs/base.conf

cat ${BASE_CONFIG} 
    <(echo -e '<ca>') 
    ${KEY_DIR}/ca.crt 
    <(echo -e '</ca>n<cert>') 
    ${KEY_DIR}/${1}.crt 
    <(echo -e '</cert>n<key>') 
    ${KEY_DIR}/${1}.key 
    <(echo -e '</key>n<tls-auth>') 
    ${KEY_DIR}/ta.key 
    <(echo -e '</tls-auth>') 
    > ${OUTPUT_DIR}/${1}.ovpn

Wir erstellen den ersten OpenVPN-Client:

cd ~/openvpn-ca
source vars
./build-key client-name
cd ~/client-configs
./make_config.sh client-name

Die Datei «~\/client-configs\/files\/client-name.ovpn» wird an das GerÀt des Kunden gesendet.

FĂŒr iOS-Kunden muss ein Trick gemacht werden:
Der Inhalt des Tags «tls-auth» sollte ohne Kommentare sein.
Und außerdem «key-direction 1» sofort vor dem Tag «tls-auth» setzen.

Lass uns die Konfiguration des OpenVPN-Servers einstellen:

cd ~\/openvpn-ca\/keys
cp ca.crt ca.key server.crt server.key ta.key dh2048.pem \/etc\/openvpn
gunzip -c \/usr\/share\/doc\/openvpn\/examples\/sample-config-files\/server.conf.gz | tee \/etc\/openvpn\/server.conf
mcedit \/etc\/openvpn\/server.conf

# Listen port
port 1194

# Protocol
proto tcp-server

# IP tunnel
dev tun0
tun-ipv6
push tun-ipv6

# Master certificate
ca ca.crt

# Server certificate
cert server.crt

# Server private key
key server.key

# Diffie-Hellman parameters
dh dh2048.pem

# Allow clients to communicate with each other
client-to-client

# Client config dir
client-config-dir /etc/openvpn/ccd

# Run client-specific script on connection and disconnection
script-security 2
client-connect "/usr/bin/sudo -u root /etc/openvpn/server-clientconnect.sh"
client-disconnect "/usr/bin/sudo -u root /etc/openvpn/server-clientdisconnect.sh"

# Server mode and client subnets
server 10.8.0.0 255.255.255.0
server-ipv6 XXXX:XXXX:XXXX:XXXX:1:3::/80
topology subnet

# IPv6 routes
push "route-ipv6 XXXX:XXXX:XXXX:XXXX::/64"
push "route-ipv6 2000::/3"

# DNS (for Windows)
# These are OpenDNS
push "dhcp-option DNS 208.67.222.222"
push "dhcp-option DNS 208.67.220.220"

# Configure all clients to redirect their default network gateway through the VPN
push "redirect-gateway def1 bypass-dhcp"
push "redirect-gateway ipv6" #For iOS

# Don't need to re-read keys and re-create tun at restart
persist-key
persist-tun

# Ping every 10s. Timeout of 120s.
keepalive 10 120

# Enable compression
comp-lzo

# User and group
user vpn
group vpn

# Log a short status
status openvpn-status.log

# Logging verbosity
##verb 4

# Custom config
tls-auth ta.key 0
cipher DES-EDE3-CBC

Das ist nötig, um jedem Kunden eine statische Adresse zuzuweisen (nicht zwingend, aber ich verwende es):

# Client config dir
client-config-dir /etc/openvpn/ccd

Das ist das komplizierteste und wichtigste Detail.

Leider kann OpenVPN noch nicht automatisch eine IPv6-Gateway fĂŒr die Kunden einrichten.
Man muss das „manuell“ fĂŒr jeden Kunden weiterleiten.

# Run client-specific script on connection and disconnection
script-security 2
client-connect "/usr/bin/sudo -u root /etc/openvpn/server-clientconnect.sh"
client-disconnect "/usr/bin/sudo -u root /etc/openvpn/server-clientdisconnect.sh"

Die Datei «\/etc\/openvpn\/server-clientconnect.sh»:

#!/bin/sh

# Check client variables
if [ -z "$ifconfig_pool_remote_ip" ] || [ -z "$common_name" ]; then
        echo "Missing environment variable."
        exit 1
fi

# Load server variables
. /etc/openvpn/variables

ipv6=""

# Find out if there is a specific config with fixed IPv6 for this client
if [ -f "/etc/openvpn/ccd/$common_name" ]; then
        # Get fixed IPv6 from client config file
        ipv6=$(sed -nr 's/^.*ifconfig-ipv6-push[ t]+([0-9a-fA-F:]+).*$/1/p' "/etc/openvpn/ccd/$common_name")
        echo $ipv6
fi

# Get IPv6 from IPv4
if [ -z "$ipv6" ]; then
        ipp=$(echo "$ifconfig_pool_remote_ip" | cut -d. -f4)
        if ! [ "$ipp" -ge 2 -a "$ipp" -le 254 ] 2>/dev/null; then
                echo "Invalid IPv4 part."
                exit 1
        fi
        hexipp=$(printf '%x' $ipp)
        ipv6="$prefix$hexipp"
fi

# Create proxy rule
/sbin/ip -6 neigh add proxy $ipv6 dev eno1

Die Datei «\/etc\/openvpn\/server-clientdisconnect.sh»:

#!/bin/sh

# Check client variables
if [ -z "$ifconfig_pool_remote_ip" ] || [ -z "$common_name" ]; then
        echo "Missing environment variable."
        exit 1
fi

# Load server variables
. /etc/openvpn/variables

ipv6=""

# Find out if there is a specific config with fixed IPv6 for this client
if [ -f "/etc/openvpn/ccd/$common_name" ]; then
        # Get fixed IPv6 from client config file
        ipv6=$(sed -nr 's/^.*ifconfig-ipv6-push[ t]+([0-9a-fA-F:]+).*$/1/p' "/etc/openvpn/ccd/$common_name")
fi

# Get IPv6 from IPv4
if [ -z "$ipv6" ]; then
        ipp=$(echo "$ifconfig_pool_remote_ip" | cut -d. -f4)
        if ! [ "$ipp" -ge 2 -a "$ipp" -le 254 ] 2>/dev/null; then
                echo "Invalid IPv4 part."
                exit 1
        fi
        hexipp=$(printf '%x' $ipp)
        ipv6="$prefix$hexipp"
fi

# Delete proxy rule
/sbin/ip -6 neigh del proxy $ipv6 dev eno1

Beide Skripte verwenden die Datei «\/etc\/openvpn\/variables»:

# Subnet
prefix=XXXX:XXXX:XXXX:XXXX:2:
# netmask
prefixlen=112

Warum hier so geschrieben ist — kann ich mich nicht erinnern.

Jetzt sieht es seltsam aus, netmask = 112 (hier sollte 96 sein).
Und das PrÀfix ist seltsam, entspricht nicht dem Netzwerk tun0.
Aber gut, ich lasse es „wie es ist“.

cipher DES-EDE3-CBC

Das ist Geschmackssache — ich habe diesen VerschlĂŒsselungsweg gewĂ€hlt.

Mehr Details zur Einrichtung von OpenVPN IPv4.

Mehr Details zur Einrichtung von OpenVPN IPv6.

============= Postfix =============

Installation des Hauptpakets:

apt-get install postfix

Bei der Installation „internet-site“ auswĂ€hlen.

Meine «\/etc\/postfix\/main.cf» sieht so aus:

smtpd_banner = $myhostname ESMTP $mail_name (Debian/GNU)
biff = nein

# Das AnhÀngen von .domain liegt in der Verantwortung des MUA.
append_dot_mydomain = nein

readme_directory = nein

# Siehe http://www.postfix.org/COMPATIBILITY_README.html -- standardmĂ€ĂŸig 2 bei
# frischen Installationen.
compatibility_level = 2

# TLS-Parameter
smtpd_tls_cert_file=/etc/ssl/domain1.com.2018.chained.crt
smtpd_tls_key_file=/etc/ssl/domain1.com.2018.key
smtpd_use_tls=ja
smtpd_tls_auth_only = ja
smtp_bind_address = XX.XX.XX.X0
smtp_bind_address6 = XXXX:XXXX:XXXX:XXXX:1:1:1:1

smtp_tls_security_level = kann
smtp_tls_ciphers = export
smtp_tls_protocols = !SSLv2, !SSLv3
smtp_tls_loglevel = 1

smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated defer_unauth_destination
myhostname = domain1.com
alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
myorigin = domain1.com
mydestination = localhost
relayhost =
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
mailbox_size_limit = 0
recipient_delimiter = +
inet_interfaces = all
inet_protocols = ipv4

internal_mail_filter_classes = bounce

# Speichertyp
virtual_transport = lmtp:unix:private/dovecot-lmtp
virtual_mailbox_domains = mysql:/etc/postfix/mysql-virtual-mailbox-domains.cf
virtual_mailbox_maps = mysql:/etc/postfix/mysql-virtual-mailbox-maps.cf
virtual_alias_maps = mysql:/etc/postfix/mysql-virtual-alias-maps.cf

# SMTP-Auth-Einstellungen
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_sasl_auth_enable = ja
smtpd_recipient_restrictions =
        permit_sasl_authenticated,
        permit_mynetworks,
        #reject_invalid_hostname,
        #reject_unknown_recipient_domain,
        reject_unauth_destination,
        reject_rbl_client sbl.spamhaus.org,
        check_policy_service unix:private/policyd-spf

smtpd_helo_restrictions =
        #reject_invalid_helo_hostname,
        #reject_non_fqdn_helo_hostname,
        reject_unknown_helo_hostname

smtpd_client_restrictions =
        permit_mynetworks,
        permit_sasl_authenticated,
        reject_non_fqdn_helo_hostname,
        permit

# SPF
policyd-spf_time_limit = 3600

# OpenDKIM
milter_default_action = accept
milter_protocol = 6
smtpd_milters = unix:var/run/opendkim/opendkim.sock
non_smtpd_milters = unix:var/run/opendkim/opendkim.sock

# IP-Adresse pro Domain
sender_dependent_default_transport_maps = pcre:/etc/postfix/sdd_transport.pcre

Betrachten wir die Einzelheiten dieses Konfigs.

smtpd_tls_cert_file=/etc/ssl/domain1.com.2018.chained.crt
smtpd_tls_key_file=/etc/ssl/domain1.com.2018.key

Laut den Hubversern enthÀlt dieser Block `Desinformation und falsche Thesen`.Erst acht Jahre nach Beginn meiner Karriere begann ich zu verstehen, wie SSL funktioniert.

Deshalb werde ich es mir erlauben, zu beschreiben, wie man SSL verwendet (ohne die Fragen «Wie funktioniert das?» und «Warum funktioniert das?» zu beantworten).

Die Basis der modernen VerschlĂŒsselung ist die Erstellung eines SchlĂŒsselpaares (zwei sehr lange Zeichenfolgen).

Einer ist der „private“ SchlĂŒssel, der andere der „öffentliche“ SchlĂŒssel. Den privaten SchlĂŒssel bewahren wir sehr sorgfĂ€ltig geheim. Den öffentlichen SchlĂŒssel geben wir allen Interessierten weiter.

Mit dem öffentlichen SchlĂŒssel kann man eine Textzeile so verschlĂŒsseln, dass nur der Besitzer des privaten SchlĂŒssels sie entschlĂŒsseln kann.
Das ist also die Grundlage der Technologie.

Schritt Nr. 1 — https Webseiten.
Der Browser erfĂ€hrt beim Zugriff auf die Webseite vom Webserver, dass die Webseite https ist und fordert daher den öffentlichen SchlĂŒssel an.
Der Webserver gibt den öffentlichen SchlĂŒssel weiter. Der Browser verschlĂŒsselt die http-Anfrage mit dem öffentlichen SchlĂŒssel und sendet sie.
Den Inhalt der http-Anfrage kann nur der lesen, der den privaten SchlĂŒssel hat, also nur der Server, an den die Anfrage gerichtet wird.
Die Http-Anfrage enthĂ€lt mindestens eine URI. Daher ist es unmöglich, den Zugang in einem Land zu bestimmten Seiten fĂŒr https-Seiten zu beschrĂ€nken, wenn nicht die gesamte Website betroffen ist.

Schritt Nr. 2 – die verschlĂŒsselte Antwort.
Der Webserver gibt eine Antwort, die unterwegs leicht gelesen werden kann.
Die Lösung ist extrem einfach – der Browser bildet lokal ein solches Paar aus privatem und öffentlichem SchlĂŒssel fĂŒr jede https-Seite.
Und zusammen mit der Anfrage nach dem öffentlichen SchlĂŒssel der Seite sendet er seinen lokalen öffentlichen SchlĂŒssel.
Der Webserver merkt sich diesen und verschlĂŒsselt bei der Sendung der http-Antwort mit diesem öffentlichen SchlĂŒssel des spezifischen Clients.
Jetzt kann die http-Antwort nur vom Inhaber des privaten SchlĂŒssels des Client-Browsers entschlĂŒsselt werden (also vom Client selbst).

Schritt Nr. 3 – die Einrichtung einer gesicherten Verbindung ĂŒber einen öffentlichen Kanal.
Im Beispiel Nr. 2 gibt es eine Schwachstelle – nichts hindert Dritte daran, die http-Anfrage abzufangen und die Informationen ĂŒber den öffentlichen SchlĂŒssel zu Ă€ndern.
So kann der Mittelsmann den gesamten Inhalt der gesendeten und empfangenen Nachrichten sehen, solange der Kommunikationskanal nicht geÀndert wird.
Gegen dieses Problem ist es extrem einfach zu kĂ€mpfen – es reicht aus, den öffentlichen SchlĂŒssel des Browsers als mit dem öffentlichen SchlĂŒssel des Webservers verschlĂŒsseltes Nachrichten zu senden.
Der Webserver sendet dann zunĂ€chst die Antwort in der Art: „Dein öffentlicher SchlĂŒssel ist so und so“ und verschlĂŒsselt diese Nachricht mit diesem öffentlichen SchlĂŒssel.
Der Browser prĂŒft die Antwort – wenn die Nachricht „Dein öffentlicher SchlĂŒssel ist so und so“ eingetroffen ist, dann ist dies eine 100%ige Garantie, dass dieser Kommunikationskanal sicher ist.
Wie sicher ist er?
Die Erstellung eines solchen sicheren Kommunikationskanals erfolgt mit einer Geschwindigkeit von ping*2. Zum Beispiel 20 ms.
Ein Angreifer muss entweder im Voraus den privaten SchlĂŒssel einer der Seiten besitzen oder den privaten SchlĂŒssel innerhalb weniger Millisekunden erraten.
Das Knacken eines modernen privaten SchlĂŒssels wĂŒrde Jahrzehnte auf einem Supercomputer in Anspruch nehmen.

Schritt Nr. 4 – öffentliche Datenbank der öffentlichen SchlĂŒssel.
Es ist offensichtlich, dass in dieser ganzen Geschichte die Möglichkeit besteht, dass ein Angreifer zwischen dem Client und dem Server sitzt.
Die Möglichkeit, dass der Kunde sich als Server und der Server sich als Kunde ausgibt. Und ein Paar SchlĂŒssel in beide Richtungen zu simulieren.
Dann wird der Angreifer den gesamten Datenverkehr sehen und die Möglichkeit haben, den Datenverkehr „nachzubearbeiten“.
Zum Beispiel die Adresse Ă€ndern, wohin man Geld sendet, oder das Passwort fĂŒr das Online-Banking kopieren oder „unerwĂŒnschte“ Inhalte blockieren.
Um gegen solche Angreifer vorzugehen, wurden öffentliche Datenbanken mit öffentlichen SchlĂŒsseln fĂŒr jede HTTPS-Website geschaffen.
Jeder Browser „weiß“ von der Existenz von etwa 200 solchen Datenbanken. Das ist in jeden Browser eingebaut.
Das „Wissen“ wird durch den öffentlichen SchlĂŒssel jedes Zertifikats unterstĂŒtzt. Das bedeutet, dass eine Verbindung zu jedem bestimmten Zertifizierungszentrum nicht gefĂ€lscht werden kann.

Jetzt gibt es ein einfaches VerstĂ€ndnis, wie man SSL fĂŒr HTTPS nutzen kann.
Wenn man nachdenkt, wird klar, wie Geheimdienste in dieser Konstruktion etwas ausspionieren könnten. Aber das wird ihnen enorme Anstrengungen kosten.
Und fĂŒr Organisationen ist es fĂŒr NSA oder CIA praktisch unmöglich, das bestehende Schutzniveau selbst fĂŒr VIPs zu hacken.

Ich möchte auch etwas zu SSH-Verbindungen hinzufĂŒgen. Dort gibt es keine öffentlichen SchlĂŒssel, was tun wir also? Die Frage wird auf zwei Arten gelöst.
SSH-Passwort-Option:
Beim ersten Verbindungsaufbau muss der SSH-Client warnen, dass hier ein neuer öffentlicher SchlĂŒssel vom SSH-Server vorliegt.
Und bei weiteren Verbindungen wird die Warnung „neuer öffentlicher SchlĂŒssel vom SSH-Server“ bedeuten, dass man abgehört wird.
Oder beim ersten Verbindungsaufbau wurde man abgehört, und jetzt kommuniziert man mit dem Server ohne IntermediÀre.
Wirklich, weil das Abhören leicht, schnell und mĂŒhelos aufgedeckt wird, wird dieser Angriff nur in besonderen FĂ€llen gegen einen bestimmten Kunden eingesetzt.

SSH-SchlĂŒssel-Option:
Wir nehmen einen USB-Stick, speichern den privaten SchlĂŒssel fĂŒr den SSH-Server darauf (es gibt dafĂŒr Begriffe und eine Menge wesentlicher Feinheiten, aber ich schreibe eine EinfĂŒhrung und keine Gebrauchsanweisung).
Den öffentlichen SchlĂŒssel lassen wir auf der Maschine, wo der SSH-Client sein wird, und halten ihn ebenfalls geheim.
Wir bringen den USB-Stick zum Server, stecken ihn ein, kopieren den privaten SchlĂŒssel und verbrennen den Stick und verstreuen die Asche im Wind (oder formatieren ihn zumindest mit Nullen).
Das ist alles — nach einer solchen Operation wird es unmöglich sein, eine solche SSH-Verbindung zu knacken. NatĂŒrlich kann man in etwa 10 Jahren auf einem Supercomputer den Verkehr ansehen — aber das ist eine andere Geschichte.

Ich entschuldige mich fĂŒr den Offtopic.

Also, jetzt, wo die Theorie bekannt ist. Ich werde ĂŒber den Prozess der Erstellung eines SSL-Zertifikats sprechen.

Mit "openssl genrsa" erstellen wir den privaten SchlĂŒssel und "Vorlagen" fĂŒr den öffentlichen SchlĂŒssel.
"Vorlagen" senden wir an eine externe Firma, der wir etwa 9 $ fĂŒr das einfachste Zertifikat zahlen.

Nach ein paar Stunden erhalten wir von dieser externen Firma unseren "öffentlichen" SchlĂŒssel und noch eine Reihe weiterer öffentlicher SchlĂŒssel.

Warum eine externe Firma fĂŒr die Ausstellung meines öffentlichen SchlĂŒssels zu zahlen ist — das ist eine separate Frage, die wir hier nicht betrachten werden.

Jetzt ist klar, was der Sinn der Aufschrift ist:

smtpd_tls_key_file=\/etc\/ssl\/domain1.com.2018.key

Im Ordner "/etc/ssl" befinden sich alle Dateien fĂŒr SSL-Angelegenheiten.
domain1.com — Name der Domain.
2018 — Jahr der Erstellung der SchlĂŒssel.
"key" — Bezeichnung, dass die Datei den privaten SchlĂŒssel enthĂ€lt.

Und der Sinn dieser Datei ist:

smtpd_tls_cert_file=\/etc\/ssl\/domain1.com.2018.chained.crt
domain1.com — Name der Domain.
2018 — Jahr der Erstellung der SchlĂŒssel.
chained — Bezeichnung, dass hier eine Kette von öffentlichen SchlĂŒsseln ist (der erste — unser öffentlicher SchlĂŒssel und die anderen — was von der Firma kam, die den öffentlichen SchlĂŒssel ausgestellt hat).
crt — Bezeichnung, dass hier das fertige Zertifikat ist (öffentlicher SchlĂŒssel mit technischen ErlĂ€uterungen).

smtp_bind_address = XX.XX.XX.X0
smtp_bind_address6 = XXXX:XXXX:XXXX:XXXX:1:1:1:1

Diese Einstellung wird in diesem Fall nicht verwendet, ist aber als Beispiel angegeben.

Denn ein Fehler in diesem Parameter wĂŒrde dazu fĂŒhren, dass Ihr Server Spam verschickt (ohne Ihr EinverstĂ€ndnis).

Danach beweisen Sie allen, dass Sie unschuldig sind.

recipient_delimiter = +

Vielleicht wissen viele das nicht, aber das ist das Standardsymbol fĂŒr die Klassifizierung von E-Mails, und dies wird von den meisten modernen Mailservern unterstĂŒtzt.

Wenn Sie beispielsweise einen E-Mail-Account "username@gmail.com" haben, versuchen Sie, an "username+spam@gmail.com" zu senden — sehen Sie, was dabei herauskommt.

inet_protocols = ipv4

Das könnte verwirrend sein.

Aber das ist nicht ohne Grund. Jede neue Domain hat standardmĂ€ĂŸig nur IPv4, spĂ€ter aktiviere ich IPv6 fĂŒr jede einzeln.

virtual_transport = lmtp:unix:private\/dovecot-lmtp
virtual_mailbox_domains = mysql:\/etc\/postfix\/mysql-virtual-mailbox-domains.cf
virtual_mailbox_maps = mysql:\/etc\/postfix\/mysql-virtual-mailbox-maps.cf
virtual_alias_maps = mysql:\/etc\/postfix\/mysql-virtual-alias-maps.cf

Hier legen wir fest, dass alle eingehenden E-Mails an Dovecot gesendet werden.
Die Regeln fĂŒr Domain, Mailbox und Alias mĂŒssen in der Datenbank betrachtet werden.

/etc/postfix/mysql-virtual-mailbox-domains.cf

user = usermail
password = mailpassword
hosts = 127.0.0.1
dbname = servermail
query = SELECT 1 FROM virtual_domains WHERE name='%s'

/etc/postfix/mysql-virtual-mailbox-maps.cf

user = usermail
password = mailpassword
hosts = 127.0.0.1
dbname = servermail
query = SELECT 1 FROM virtual_users WHERE email='%s'

/etc/postfix/mysql-virtual-alias-maps.cf

user = usermail
password = mailpassword
hosts = 127.0.0.1
dbname = servermail
query = SELECT destination FROM virtual_aliases WHERE source='%s'

# SMTP-Auth settings
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_sasl_auth_enable = yes

Jetzt weiß Postfix, dass E-Mails nur mit Authentifizierung ĂŒber Dovecot akzeptiert werden können.

Ich verstehe wirklich nicht ganz, warum das hier doppelt angegeben werden muss. Wir haben doch bereits in „virtual_transport“ alles Wichtige angegeben.

Aber Postfix ist ein sehr altes System – wahrscheinlich sind das Überbleibsel aus alten Zeiten.

smtpd_recipient_restrictions =
        ...

smtpd_helo_restrictions =
        ...

smtpd_client_restrictions =
        ...

Das ist fĂŒr jeden Mailserver individuell einzustellen.

Ich habe drei Mailserver zur VerfĂŒgung, und diese Einstellungen sind aufgrund der unterschiedlichen Anforderungen sehr unterschiedlich.

Die Konfiguration muss sorgfĂ€ltig vorgenommen werden – andernfalls wird Spam zu Ihnen kommen oder, noch schlimmer, Spam wird von Ihnen ausgehen.

# SPF
policyd-spf_time_limit = 3600

Einstellung fĂŒr ein Plugin zur ÜberprĂŒfung von SPF fĂŒr eingehende E-Mails.

# OpenDKIM
milter_default_action = accept
milter_protocol = 6
smtpd_milters = unix:var/run/opendkim/opendkim.sock
non_smtpd_milters = unix:var/run/opendkim/opendkim.sock

Einstellung, dass alle ausgehenden E-Mails mit einer DKIM-Signatur versehen werden mĂŒssen.

# IP address per domain
sender_dependent_default_transport_maps = pcre:/etc/postfix/sdd_transport.pcre

Dies ist ein entscheidendes Detail bei der Routing von E-Mails, wenn sie von PHP-Skripten versendet werden.

Datei „/etc/postfix/sdd_transport.pcre“:

/^www-domain1@domain1.com$/ domain1:
/^www-domain2@domain1.com$/ domain2:
/^www-domain3@domain1.com$/ domain3:
/@domain1.com$/             domain1:
/@domain2.com$/             domain2:
/@domain3.com$/             domain3:

Links – regulĂ€re AusdrĂŒcke. Rechts – das Label, mit dem die E-Mail markiert wird.
Postfix berĂŒcksichtigt je nach Label noch einige weitere Konfigurationszeilen fĂŒr die spezifische E-Mail.

Wie genau Postfix fĂŒr eine spezifische E-Mail neu konfiguriert wird, wird in „master.cf“ angegeben.

Die Zeilen 4, 5, 6 sind entscheidend. In welchem Namen wir die E-Mail versenden, setzen wir das entsprechende Label.
Aber nicht immer wird im PHP-Skript im alten Code das Feld „from“ angegeben. Dann kommt der Benutzername ins Spiel.

Der Artikel ist ohnehin schon umfangreich – ich möchte mich nicht mit der Konfiguration von nginx+fpm ablenken.

Kurz gesagt – fĂŒr jede Website bestimmen wir einen eigenen Linux-Benutzer als EigentĂŒmer. Entsprechend auch einen eigenen fpm-Pool.

Der fpm-Pool kann jede PHP-Version verwenden (das ist großartig, wenn auf einem Server ohne Probleme fĂŒr benachbarte Websites unterschiedliche PHP-Versionen und sogar unterschiedliche php.ini verwendet werden können).

Der spezifische Linux-Benutzer „www-domain2“ hat die Website domain2.com. Auf dieser Website gibt es einen Code zum Versenden von E-Mails ohne Angabe des „from“-Feldes.

Selbst in einem solchen Fall werden die E-Mails korrekt versendet und landen niemals im Spam.

Mein „/etc/postfix/master.cf“ sieht so aus:

...
smtp      inet  n       -       y       -       -       smtpd
  -o content_filter=spamassassin
...
submission inet n       -       y       -       -       smtpd
  -o syslog_name=postfix/submission
  -o smtpd_tls_security_level=encrypt
  -o smtpd_sasl_auth_enable=yes
  -o smtpd_client_restrictions=permit_sasl_authenticated,reject
...
policyd-spf  unix  -       n       n       -       0       spawn
    user=policyd-spf argv=/usr/bin/policyd-spf

spamassassin unix -     n       n       -       -       pipe
    user=spamd argv=/usr/bin/spamc -f -e
    /usr/sbin/sendmail -oi -f ${sender} ${recipient}
...
domain1  unix -       -       n       -       -       smtp
   -o smtp_bind_address=XX.XX.XX.X1
   -o smtp_helo_name=domain1.com
   -o inet_protocols=all
   -o smtp_bind_address6=XXXX:XXXX:XXXX:XXXX:1:1:1:1
   -o syslog_name=postfix-domain1

domain2  unix -       -       n       -       -       smtp
   -o smtp_bind_address=XX.XX.XX.X5
   -o smtp_helo_name=domain2.com
   -o inet_protocols=all
   -o smtp_bind_address6=XXXX:XXXX:XXXX:XXXX:1:2:1:1
   -o syslog_name=postfix-domain2

domain3  unix -       -       n       -       -       smtp
   -o smtp_bind_address=XX.XX.XX.X2
   -o smtp_helo_name=domain3
   -o inet_protocols=all
   -o smtp_bind_address6=XXXX:XXXX:XXXX:XXXX:1:1:5:1
   -o syslog_name=postfix-domain3

Die Datei ist nicht vollstĂ€ndig - sie ist ohnehin schon sehr groß.
Ich habe nur das markiert, was geÀndert wurde.

smtp      inet  n       -       y       -       -       smtpd
  -o content_filter=spamassassin
...
spamassassin unix -     n       n       -       -       pipe
    user=spamd argv=/usr/bin/spamc -f -e
    /usr/sbin/sendmail -oi -f ${sender} ${recipient}

Dies sind die mit Spamassassin verbundenen Einstellungen, dazu spÀter mehr.

submission inet n       -       y       -       -       smtpd
  -o syslog_name=postfix/submission
  -o smtpd_tls_security_level=encrypt
  -o smtpd_sasl_auth_enable=yes
  -o smtpd_client_restrictions=permit_sasl_authenticated,reject

Wir erlauben die Verbindung zum Mailserver ĂŒber Port 587.
Dazu ist eine Authentifizierung erforderlich.

policyd-spf  unix  -       n       n       -       0       spawn
    user=policyd-spf argv=/usr/bin/policyd-spf

Wir aktivieren die SPF-ÜberprĂŒfung.

apt-get install postfix-policyd-spf-python

Wir installieren das Paket fĂŒr SPF-ÜberprĂŒfungen.

domain1  unix -       -       n       -       -       smtp
   -o smtp_bind_address=XX.XX.XX.X1
   -o smtp_helo_name=domain1.com
   -o inet_protocols=all
   -o smtp_bind_address6=XXXX:XXXX:XXXX:XXXX:1:1:1:1
   -o syslog_name=postfix-domain1

Und das ist das interessanteste. Dies ist die Möglichkeit, E-Mails fĂŒr eine bestimmte Domain von einer bestimmten IPv4/IPv6-Adresse zu senden.

Das geschieht wegen rDNS. rDNS - das Abrufen einer bestimmten Zeichenfolge ĂŒber die IP-Adresse.
Und fĂŒr E-Mails wird diese Möglichkeit verwendet, um zu bestĂ€tigen, dass helo tatsĂ€chlich mit rDNS der Adresse ĂŒbereinstimmt, von der die E-Mail gesendet wurde.

Wenn helo nicht mit der Domain der E-Mail ĂŒbereinstimmt, von der die E-Mail gesendet wurde, werden Spam-Punkte vergeben.

Helo stimmt nicht mit rDNS ĂŒberein - es werden viele Spam-Punkte vergeben.
Daher sollte jede Domain ihre eigene IP-Adresse haben.
FĂŒr OVH gibt es im Control Panel die Möglichkeit, rDNS anzugeben.
FĂŒr tech.ru wird das Problem ĂŒber den Support gelöst.
FĂŒr AWS wird das Problem auch ĂŒber den Support gelöst.
«inet_protocols» und «smtp_bind_address6» – hier aktivieren wir die UnterstĂŒtzung von IPv6.
FĂŒr IPv6 muss ebenfalls rDNS konfiguriert werden.
«syslog_name» – das dient zur besseren Lesbarkeit der Protokolle.

Zertifikate kaufen empfehle ich hier.

Einrichtung der Kombination postfix+dovecot hier.

SPF-Konfiguration.

============= Dovecot =============

apt-get install dovecot-imapd dovecot-pop3d dovecot-lmtpd dovecot-mysql dovecot-antispam

MySQL einrichten, wir installieren die Pakete selbst.

Datei «/etc/dovecot/conf.d/10-auth.conf»

disable_plaintext_auth = yes
auth_mechanisms = plain login

Authentifizierung nur in verschlĂŒsselter Form.

Datei «/etc/dovecot/conf.d/10-mail.conf»

mail_location = maildir:/var/mail/vhosts/%d/%n

Hier geben wir den Speicherort der E-Mails an.

Ich möchte, dass sie in Dateien gespeichert werden und nach Domains gruppiert sind.

Datei «/etc/dovecot/conf.d/10-master.conf»

service imap-login {
  inet_listener imap {
    port = 0
  }
  inet_listener imaps {
    address = XX.XX.XX.X1, XX.XX.XX.X2, XX.XX.XX.X5, [XXXX:XXXX:XXXX:XXXX:1:1:1:1], [XXXX:XXXX:XXXX:XXXX:1:2:1:1], [XXXX:XXXX:XXXX:XXXX:1:1:5:1]
    port = 993
    ssl = yes
  }
}
service pop3-login {
  inet_listener pop3 {
    port = 0
  }
  inet_listener pop3s {
    address = XX.XX.XX.X1, XX.XX.XX.X2, XX.XX.XX.X5, [XXXX:XXXX:XXXX:XXXX:1:1:1:1], [XXXX:XXXX:XXXX:XXXX:1:2:1:1], [XXXX:XXXX:XXXX:XXXX:1:1:5:1]
    port = 995
    ssl = yes
  }
}
service lmtp {
  unix_listener /var/spool/postfix/private/dovecot-lmtp {
    mode = 0600
    user = postfix
    group = postfix
  }
}
service imap {
}
service pop3 {
}
service auth {
  unix_listener auth-userdb {
    mode = 0600
    user = vmail
  }

  unix_listener /var/spool/postfix/private/auth {
    mode = 0666
    user = postfix
    group = postfix
  }
  user = dovecot
}
service auth-worker {
  user = vmail
}
service dict {
  unix_listener dict {
  }
}

Das ist die Hauptkonfigurationsdatei von dovecot.
Hier deaktivieren wir ungesicherte Verbindungen.
Und aktivieren gesicherte Verbindungen.

Datei «/etc/dovecot/conf.d/10-ssl.conf»

ssl = required
ssl_cert = </etc/nginx/ssl/domain1.com.2018.chained.crt
ssl_key = </etc/nginx/ssl/domain1.com.2018.key
local XX.XX.XX.X5 {
  ssl_cert = </etc/nginx/ssl/domain2.com.2018.chained.crt
  ssl_key =  </etc/nginx/ssl/domain2.com.2018.key
}

Wir konfigurieren ssl. Wir geben an, dass ssl erforderlich ist.
Und das Zertifikat selbst. Und ein wichtiger Punkt – die Direktive «local». Sie gibt an, welches ssl-Zertifikat bei einer Verbindung zu welcher lokalen IPv4 verwendet werden soll.

Übrigens, IPv6 ist hier nicht konfiguriert, ich werde dieses VersĂ€umnis spĂ€ter beheben.
XX.XX.XX.X5 (domain2) – kein Zertifikat. FĂŒr die Kundenverbindungen muss domain1.com angegeben werden.
XX.XX.XX.X2 (domain3) – es gibt ein Zertifikat, fĂŒr die Kundenverbindungen kann domain1.com oder domain3.com angegeben werden.

Datei «/etc/dovecot/conf.d/15-lda.conf»

protocol lda {
  mail_plugins = $mail_plugins sieve
}

Das wird spĂ€ter fĂŒr spamassassin benötigt.

Datei «/etc/dovecot/conf.d/20-imap.conf»

protocol imap {
  mail_plugins = $mail_plugins antispam
}

Das ist das Antispam-Plugin. Es wird benötigt, um spamassassin beim Verschieben in/von dem „Spam“-Ordner zu trainieren.

Datei «/etc/dovecot/conf.d/20-pop3.conf»

protocol pop3 {
}

Einfach eine solche Datei existiert.

Datei «/etc/dovecot/conf.d/20-lmtp.conf»

protocol lmtp {
  mail_plugins = $mail_plugins sieve
  postmaster_address = admin@domain1.com
}

Konfiguration von lmtp.

Datei „/etc/dovecot/conf.d/90-antispam.conf“

plugin {
  antispam_backend = pipe
  antispam_trash = Trash;trash
  antispam_spam = Junk;Spam;SPAM
  antispam_pipe_program_spam_arg = --spam
  antispam_pipe_program_notspam_arg = --ham
  antispam_pipe_program = /usr/bin/sa-learn
  antispam_pipe_program_args = --username=%Lu
}

Einstellungen fĂŒr das Training von SpamAssassin beim Verschieben in/aus dem „Spam“-Ordner.

Datei „/etc/dovecot/conf.d/90-sieve.conf“

plugin {
  sieve = ~/dovecot.sieve
  sieve_dir = ~/sieve
  sieve_after = /var/lib/dovecot/sieve/default.sieve
}

Datei, in der angegeben wird, was mit eingehenden E-Mails zu tun ist.

Datei „/var/lib/dovecot/sieve/default.sieve“

require ["fileinto", "mailbox"];

if header :contains "X-Spam-Flag" "YES" {
        fileinto :create "Spam";
}

Die Datei muss kompiliert werden: „sievec default.sieve“.

Datei „/etc/dovecot/conf.d/auth-sql.conf.ext“

passdb {
  driver = sql
  args = /etc/dovecot/dovecot-sql.conf.ext
}
userdb {
  driver = static
  args = uid=vmail gid=vmail home=/var/mail/vhosts/%d/%n
}

Angabe der SQL-Dateien zur Authentifizierung.
Und die Datei selbst — als Methode zur Authentifizierung.

Datei „/etc/dovecot/dovecot-sql.conf.ext“

driver = mysql
connect = host=127.0.0.1 dbname=servermail user=usermail password=password
default_pass_scheme = SHA512-CRYPT
password_query = SELECT email as user, password FROM virtual_users WHERE email='%u';

Dies entspricht den entsprechenden Einstellungen fĂŒr Postfix.

Datei „/etc/dovecot/dovecot.conf“

protocols = imap lmtp pop3
listen = *, ::
dict {
}
!include conf.d/*.conf
!include_try local.conf

Die Hauptkonfigurationsdatei.
Wichtig ist, dass wir hier die Protokolle angeben/hinzufĂŒgen.

============= SpamAssassin =============

apt-get install spamassassin spamc

Wir installieren die Pakete.

adduser spamd --disabled-login

Wir fĂŒgen den Benutzer hinzu, unter dessen Namen.

systemctl enable spamassassin.service

Wir aktivieren die Auto-Start-Funktion des SpamAssassin-Dienstes beim Booten.

Datei „/etc/default/spamassassin“:

CRON=1

Aktiviert die automatische Aktualisierung der „Standard“-Regeln.

Datei „/etc/spamassassin/local.cf“:

report_safe 0

use_bayes          1
bayes_auto_learn   1
bayes_auto_expire  1
bayes_store_module Mail::SpamAssassin::BayesStore::MySQL
bayes_sql_dsn      DBI:mysql:sa:localhost:3306
bayes_sql_username sa
bayes_sql_password password

Es ist notwendig, eine MySQL-Datenbank „sa“ mit dem Benutzer „sa“ und dem Passwort „password“ (durch etwas Angemessenes ersetzen) zu erstellen.

report_safe bedeutet, dass anstelle einer E-Mail ein Bericht ĂŒber die Spam-E-Mail gesendet wird.
use_bayes sind die Einstellungen fĂŒr das maschinelle Lernen von SpamAssassin.

Die ĂŒbrigen Einstellungen fĂŒr SpamAssassin wurden zuvor im Artikel angewendet.

Allgemeine Einstellungen fĂŒr „SpamAssassin“.
Über das Verschieben neuer Spam-E-Mails in den IMAP-Ordner „Spam“.
Über die einfache Verbindung von Dovecot + SpamAssassin.
Ich empfehle, die Theorie des Lernens von SpamAssassin beim Bewegen von E-Mails in IMAP-Ordnern zu lesen (und empfehle dies nicht zur Anwendung).

============= Kontakt zur Gemeinschaft =============

Ich wĂŒrde gerne eine Idee in die Gemeinschaft einbringen, wie man das Sicherheitsniveau beim Versenden von E-Mails erhöhen kann. Da ich mich so tief mit dem Thema E-Mail beschĂ€ftigt habe.

Damit der Benutzer auf seinem Client (Outlook, Thunderbird, Browser-Plugin, 
) ein Paar SchlĂŒssel erstellen kann. Ein öffentlicher und ein privater. Der öffentliche – wird im DNS gesendet. Der private – bleibt auf dem Client. Die Mailserver sollten in der Lage sein, den öffentlichen SchlĂŒssel fĂŒr den Versand an einen bestimmten EmpfĂ€nger zu verwenden.

Und um sich vor Spam bei solchen E-Mails zu schĂŒtzen (ja, der Mailserver kann den Inhalt nicht einsehen) – mĂŒssen drei Regeln eingefĂŒhrt werden:

  1. Verpflichtende echte DKIM-Signatur, verpflichtender SPF, verpflichtendes rDNS.
  2. Ein neuronales Netzwerk zum Thema Spam-Filterung + eine Datenbank dazu auf der Client-Seite.
  3. Der VerschlĂŒsselungsalgorithmus sollte so sein, dass die sendende Seite 100 Mal mehr CPU-Ressourcen fĂŒr die VerschlĂŒsselung aufbringen muss als die empfangende Seite.

Neben öffentlichen E-Mails – einen Standard fĂŒr ein Angebotsmail „geschĂŒtzte Kommunikation beginnen“ entwickeln. Ein Benutzer (E-Mail-Postfach) sendet einem anderen Postfach eine E-Mail mit einem Anhang. In der E-Mail steht der Vorschlag, einen geschĂŒtzten Kommunikationskanal fĂŒr den Austausch einzurichten, sowie der öffentliche SchlĂŒssel des Postfachinhabers (wĂ€hrend der private SchlĂŒssel auf der Client-Seite bleibt).

Man könnte sogar Paare von SchlĂŒsseln speziell fĂŒr jede Korrespondenz erstellen. Der Empfangsbenutzer kann dieses Angebot annehmen und seinen öffentlichen SchlĂŒssel (ebenfalls speziell fĂŒr diese Korrespondenz erstellt) senden. Danach sendet der erste Benutzer ein Kontrollmail (verschlĂŒsselt mit dem öffentlichen SchlĂŒssel des zweiten Benutzers) – bei dessen Erhalt kann der zweite Benutzer den eingerichteten Kommunikationskanal als zuverlĂ€ssig ansehen. Danach sendet der zweite Benutzer ein Kontrollmail – und dann kann auch der erste Benutzer den eingerichteten Kanal als geschĂŒtzt betrachten.

Um der Abfangung von SchlĂŒsseln auf dem Weg entgegenzuwirken – muss im Protokoll die Möglichkeit berĂŒcksichtigt werden, mindestens einen öffentlichen SchlĂŒssel ĂŒber einen USB-Stick zu ĂŒbertragen.

Und das Wichtigste – damit das alles funktioniert (Frage: „Wer bezahlt dafĂŒr?“):
Eingeben von E-Mail-Zertifikaten ab 10 $ fĂŒr 3 Jahre. Diese ermöglichen es dem Absender, im DNS anzugeben, dass „meine öffentlichen SchlĂŒssel dort sind“. Und sie geben die Möglichkeit, eine sichere Verbindung aufzubauen. Dabei sind solche Verbindungen kostenlos.
Gmail monetarisiert endlich seine Benutzer. FĂŒr 10 $ in 3 Jahren – das Recht, geschĂŒtzte KommunikationskanĂ€le zu erstellen.

============= Fazit =============

Zur Testung des gesamten Artikels wollte ich einen dedizierten Server fĂŒr einen Monat mieten und eine Domain mit SSL-Zertifikat kaufen.

Doch die LebensumstĂ€nde haben dazu gefĂŒhrt, dass sich diese Frage auf 2 Monate zog.
Und jetzt, als wieder freie Zeit verfĂŒgbar war, habe ich beschlossen, den Artikel so zu veröffentlichen, wie er ist, anstatt das Risiko einzugehen, dass die Veröffentlichung sich um ein weiteres Jahr verzögert.

Wenn genug Fragen auftauchen, wie „Hier ist nicht ausreichend detailliert beschrieben“ – dann werden wahrscheinlich die Ressourcen gefunden, einen dedizierten Server mit einer neuen Domain und einem neuen SSL-Zertifikat zu mieten und noch detaillierter zu beschreiben sowie alle wichtigen Details zu erkennen, die möglicherweise ĂŒbersehen wurden.

Ich wĂŒrde auch gerne Feedback zur Idee von E-Mail-Zertifikaten erhalten. Wenn die Idee gefĂ€llt, werde ich versuchen, die Ressourcen zu finden, um einen Entwurf fĂŒr die RFC zu schreiben.

Beim Kopieren großer Teile des Artikels – bitte auf diesen Artikel verweisen.
Bei der Übersetzung in eine andere Sprache – bitte auf diesen Artikel verweisen.
Ich werde versuchen, den Artikel selbst ins Englische zu ĂŒbersetzen und Querverweise zu hinterlassen.


Quelle: habr.com

ZuverlĂ€ssiges Hosting fĂŒr Websites mit DDoS-Schutz kaufen, VPS VDS Server đŸ”„ ZuverlĂ€ssiges Hosting fĂŒr Websites mit DDoS-Schutz kaufen, VPS VDS Server - ProHoster