Graphite vs. IOPS – experience exchange

Last year, Blerim told us how to benchmark a Graphite and now we want to share some experience on how to handle the emerging IOPS with its pro and contra. It is important to know that Graphite can store its metrics in 3 different ways (CACHE_WRITE_STRATEGY). Each one of them influences another system resource like CPU, RAM or IO. Let us start with an overview about each option and its function.

max

The cache will keep almost all the metrics in memory and only writes the one with the most datapoints. Sounds nice and helps a lot to reduce the general and random io. But this option should never be used without the WHISPER_AUTOFLUSH flag, because most of your metrics are only available in memory. Otherwise you have a high risk of losing your metrics in cases of unclean shutdown or system breaks.

The disadvantage here is that you need a strong CPU, because the cache must sort all the metrics. The required CPU usage increases with the amount of cached metrics and it is important to keep an eye on enough free capacity. Otherwise it will slow down the processing time for new metrics and dramatically reduce the rendering performance of the graphite-web app.

naive

This is the counterpart to the max option and writes the metrics randomly to the disk. It can be used if you need to save CPU power or have fast storage like solid state disk, but be aware that it generates a large amount of IOPS !

sorted

With this option the cache will sort all metrics according to the number of datapoints and write the list to the disk. It works similar to max, but writes all metrics, so the cache will not get to big. This helps to keep the CPU usage low while getting the benefit of caching the metrics in RAM.

All the mentioned options can be controlled with the MAX_UPDATES_PER_SECOND, but each one will be affected in its own way.

Summary

At the end, we made use of the sorted option and spread the workload to multiple cache instances. With this we reduced the amount of different metrics each cache has to process (consistent-hashing relay) and find the best solution in the mix of MAX_UPDATES_PER_SECOND per instance to the related IOPS and CPU/RAM usage. It may sound really low, but currently we are running 15 updates per second for each instance and could increase the in-memory-cache with a low CPU impact. So we have enough resources for fast rendering within graphite-web.

I hope this post can help you in understanding how the cache works and generates the IOPS and system requirements.

Ronny Biering

Autor: Ronny Biering

Vor NETWAYS arbeitete Ronny bei einem der großen deutschen Internet- und Hosting Provider. Hier betreut er zusammen mit seinen Kollegen aus dem Bereich Managed Services die Plattformen unserer Kunden. Im Gegensatz zu dem üblichen Admin-Cliche, gehört Fitness zu einer seiner Lieblingsfreizeitbeschäftigung.

Analyse der Konfigration bei Galera-MySQL-Cluster

Ich möchte in diesem Blog-Beitrag noch Ergänzungen zum Galera-Blog von Marius zum Thema Konfiguration-Check machen.

Zum Beispiel kann man bestimmte Statis abfragen, ob der Cluster synchronisiert ist oder wie viele Nodes der Cluster besitzt und noch einiges mehr.
Kurz zum Verständnis bei MySQL ist das Prozentzeichen(%) das Wildcard wie bei der Bash das Sternchen(*).
Das werde ich Anhand nachfolgender Beispiele erklären.

Die Anzahl der Nodes im Cluster:

mariaDB [(none)]> show status like 'wsrep_cluster_size%';
+--------------------+-------+
| Variable_name | Value |
+--------------------+-------+
| wsrep_cluster_size | 3 |
+--------------------+-------+

Wie man sehen kann sind hier 3 Nodes im Cluster.

Den aktuellen Sync-Status im Cluster wird so ermittelt:

MariaDB [(none)]> show status like 'wsrep_local_state_comment%';
+---------------------------+--------+
| Variable_name | Value |
+---------------------------+--------+
| wsrep_local_state_comment | Synced |
+---------------------------+--------+

Die Ausgabe sollte hier selbsterklärend sein.

Um alle Statis von dem Cluster abzurufen kann man dieses Kommando benutzen:
show status like 'wsrep_%';
| wsrep_provider_name | Galera |
| wsrep_provider_vendor | Codership Oy <info@codership.com> |
| wsrep_provider_version | 25.3.19(r3667) |
| wsrep_ready | ON |
| wsrep_received | 56804 |
| wsrep_received_bytes | 2506329647 |
| wsrep_repl_data_bytes | 352492270

Das ist nur ein kleiner Ausschnitt aus dem Ouput der hier herauskommt

Jetzt kommen wir zur eingestellten Konfiguration, die man hier auch auslesen kann, um spätere Anpassungen vorzunehmen kann.
Die Werte dafür sind in Variablen bei MySQL gespeichert und können wie folgt abgerufen werden:

Die max_allow Variablen kann man so ermitteln:

MariaDB [(none)]> show variables like '%max_allow%';
+--------------------------+------------+
| Variable_name | Value |
+--------------------------+------------+
| max_allowed_packet | 536870912 |
| slave_max_allowed_packet | 1073741824 |
+--------------------------+------------+

Wenn man hier etwas herumspielt mit den Werten, kann man erstaunliches und informatives herausfinden.

So als kleiner Einstieg sollte dieser Beitrag ausreichen damit man die wichtigsten Einstellungen beim Galera-Cluster ausgegeben bekommt.
Lesenswert Link:
Galera Dokumtentation

Empfehlenswert sind natürlich unsere Schulungen im Bereich, die auf jeden Fall einen Blick wert sind.

Johannes Carraro

Autor: Johannes Carraro

Bevor Johannes bei NETWAYS anheuerte war er knapp drei Jahre als Systemadministrator in Ansbach tätig. Seit Februar 2016 verstärkt er nun unser Managed Services Team als Systems Engineer. In seiner Freizeit spielt Johannes E-Gitarre in einer Metalband, bastelt an Linux Systemen zuhause herum und ertüchtigt sich beim Tischtennisspielen im Verein, bzw. Mountainbiken, Inlinern und nicht zuletzt Skifahren

SSL leicht gemacht – forcierte Weiterleitung von HTTP auf HTTPS einrichten

In den vorherigen Teilen der Serie wurde bereits die Erstellung und Einbindung der Zertifikate beschrieben. Eines Tages wünscht sich der Admin jedoch die sichere Verbindung aller Seitenbesucher, ohne dass diese manuell ein https voranstellen müssen. Gerade bei einer Migration einer bestehenden Seite wird der

Parallelbetrieb erst nach eingehenden Tests eingestellt und das SSL jeweils forciert, um Seitenbesucher nicht mit ungültigen Zertifikaten oder Mixed Content zu verunsichern.

Die eigentliche Umsetzung ist dann relativ einfach und wird in unserem Beispiel direkt in der Vhost-Definition des Apache vorgenommen. Übrigens, die verfügbaren Vhosts sind zu finden unter: /etc/apache2/sites-available. Hier wird nun der HTTP-Vhost (Port 80) um den unten aufgezeigten Block mit den Rewrites erweitert.

<VirtualHost *:80>
  ServerAdmin webmaster@netways.de
  ServerName www.netways.de
  DocumentRoot /var/www/html/netways.de/
  <Directory /var/www/html/netways.de/>
   Options FollowSymLinks
   AllowOverride All
  </Directory>
  ErrorLog /var/log/apache2/error.log
  LogLevel warn
  CustomLog /var/log/apache2/access.log combined
  RewriteEngine on
  RewriteCond %{SERVER_NAME} =www.netways.de [OR]
  RewriteCond %{SERVER_NAME} =netways.de
  RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,QSA,R=permanent]
 </VirtualHost>

Damit das Ganze nun auch funktioniert, muss natürlich der SSL-Vhost unter Port 443 erreichbar sein. Wie dieser initial erstellt wird, ist im Artikel SSL-Zertifikat einbinden beschrieben.

Übrigens: wer Let’s Encrypt verwendet, wird im Wizard gleich gefragt, ob SSL forciert werden soll. Der Wizard übernimmt dann die oben gezeigten Schritte. Wie man Let’s Encrypt einsetzt, haben wir natürlich auch schon einmal beschrieben. Damit später keine Seitenbesucher verloren gehen, sollte der HTTP-Vhost, der auf Port 80 läuft, nicht abgeschaltet werden. Die Verbindung ist mit dieser Maßnahme sicher und alle Besucher werden auf https umgeleitet.

Wer damit gar nichts zu tun haben will, und trotzdem stets auf der sicheren Seite sein will, der kann natürlich seine Seite auch bei NETWAYS im Managed Hosting betreuen lassen. Hier kümmern wir uns darum.

In den anderen (teilweise noch kommenden) Blogposts zum Thema SSL leicht gemacht geht es um:

Georg Mimietz

Autor: Georg Mimietz

Georg kam im April 2009 zu NETWAYS, um seine Ausbildung als Fachinformatiker für Systemintegration zu machen. Nach einigen Jahren im Bereich Managed Services ist er in den Vertrieb gewechselt und kümmerte sich dort überwiegend um die Bereiche Shop und Managed Services. Seit 2015 ist er als Teamlead für den Support verantwortlich und kümmert sich um Kundenanfragen und die Ressourcenplanung. Darüber hinaus erledigt er in Nacht-und-Nebel-Aktionen Dinge, für die andere zwei Wochen brauchen.

Icinga 2 – Monitoring automatisiert mit Puppet Teil 8: Integration von Icinga Web 2

This entry is part 8 of 8 in the series Icinga 2 Monitoring automatisiert mit Puppet

Zum Ausklang des Jahres 2017 gibt es nochmals einen Post zum Thema Puppet und Icinga. Es geht heute um das Ziel, einen Icinga-Server inklusive Icinga Web 2 mittels Puppet zu managen. Die Icinga IDO sowie eine Datenbank zur Authentifizierung am Icinga Web 2 sind beide als MySQL-Datenbanken realisiert. Kommandos von Icinga Web 2 werden zum Icinga-Core via Icinga-2-API übertragen.

Als Plattform kommt ein CentOS 7 zum Einsatz. Damit muss für die aktuellen Pakete zum Icinga Web 2 ab Version 2.5.0 der verwendete Apache den PHP-Code mittels FastCGI ausführen.

Voraussetzung ist, dass die erforderlichen Puppet-Module icinga-icinga2, icinga-icingaweb2, puppetlabs-mysql und deren jeweilige Abhängigkeiten installiert sein müssen.

Beginnen wir zuerst mit einigen Variablen, die wir setzen, um im nachfolgenden Code keine Redundanzen zu haben. Wir setzen hier wie die Datenbanken für die IDO und fürs Icinga Web 2 heißen sollen und mit welchem Account jeweils darauf zugegriffen werden soll. Zusätzlich kommt noch der Name und das Passwort des Benutzers für die Icinga-2-API hinzu.

$ido_db_name = 'icinga'
$ido_db_user = 'icinga'
$ido_db_pass = 'icinga'

$api_user    = 'icingaweb2'
$api_pass    = '12e2ef553068b519'

$web_db_name = 'icingaweb2'
$web_db_user = 'icingaweb2'
$web_db_pass = 'icingaweb2'

Der nun folgende Code ist für Puppet 4 und neuer gedacht, da das Feature bzgl. Reihenfolge der Deklarationen in der Datei vorausgesetzt wird.

Für CentOS werden im Vorfeld zusätzliche Repositories benötigt, EPEL für die Plugins und SCL für das FastCGI PHP in der Version 7. Die Klasse icinga2 kümmert sich nicht nur um die Grundkonfiguration, sondern außerdem auch um die Einbindung des Icinga-Repos.

package { ['centos-release-scl', 'epel-release']:
  ensure => installed,
}

class { '::icinga2':
  manage_repo => true,
}

Als nächstes kümmern wir uns um den MySQL-Server und die von uns benötigten Datenbanken für die IDO und das Icinga Web 2. Beide laufen auf dem selben Host wie Icinga 2 und Icinga Web 2.

include ::mysql::server

mysql::db { $ido_db_name:
  user     => $ido_db_user,
  password => $ido_db_pass,
  host     => 'localhost',
  grant    => ['SELECT', 'INSERT', 'UPDATE', 'DELETE', 'DROP', 'CREATE VIEW', 'CREATE', 'ALTER', 'INDEX', 'EXECUTE'],
}

mysql::db { $web_db_name:
  user     => $web_db_user,
  password => $web_db_pass,
  host     => 'localhost',
  grant    => ['ALL'],
}

Nun können wir das IDO-Feature von Icinga 2 konfigurieren und aktivieren. Da es im Zusammenhang der Defined Resources für die Datenbank und das Feature zu einer Abhängigkeit kommt, die nicht via Top-Down-Dependency gelöst werden kann, muss hier mit require gearbeitet werden, damit die Datenbank vorher erzeugt wird.

class { '::icinga2::feature::idomysql':
  database      => $ido_db_name,
  user          => $ido_db_user,
  password      => $ido_db_pass,
  import_schema => true,
  require       => Mysql::Db[$ido_db_name],
}

Da Icinga Web 2 Kommandos mittels API an Icinga 2 senden soll, benötigen wir eine CA sowie die Aktivierung der Features API selbst. Die Certificate Authority soll eine von Icinga verwaltete CA sein. Das erfordert die Deklaration der Klasse icinga2::Pki::ca, die sich um genau dieses kümmert. Das Feature muss dann mit none für den Parameter pki werden, da sonst mit dem Default, die Puppet-Zertifikate verwendet werden und damit nicht mehr zur CA passen würden.

Zusätzlich erzeugen wir in einer Konfigurationsdatei noch einen API-User, der entsprechend eingeschränkte Rechte hat, um dann von Icinga Web 2 verwendet zu werden Kommandos zu übertragen.

class { '::icinga2::feature::api':
  pki => 'none',
}

include ::icinga2::pki::ca

::icinga2::object::apiuser { $api_user:
  ensure      => present,
  password    => $api_pass,
  permissions => [ 'status/query', 'actions/*', 'objects/modify/*', 'objects/query/*' ],
  target      => "/etc/icinga2/conf.d/api-users.conf",
}

Das Icinga-Repository ist schon aktiviert und wir ziehen die Installation der Pakete für Icinga Web 2 aus der Klasse icingaweb2 heraus. Damit profitieren wir davon, dass die abhängigen Pakete für PHP mit FastCGI zu diesem Zeitpunkt schon installiert werden und wir den Dienst rh-php71-php-fpm schon vor der Installation von icinga Web 2 mit allen benötigten PHP-Modulen starten können. Anders herum müsste dafür Sorge getragen werden die Dienst nach icingaweb2 nochmals für einen Neustart zu triggern.

Zusätzlich kommen noch die Standard-Plugins und der Apache aufs System. Bevor der Apache-Service deklariert wird, soll noch die erforderliche Apache-Konfiguration fürs Icinga Web 2 ins Konfigurationsverzeichnis des Webservers abgelegt werden. Dieses Beispiel für FastCGI ist erst im Module ab Version 2.0.1 von puppet-icingaweb2 enthalten.

TIPP: Die hier verwendete File-Resource mit der Quelle auf das Example aus dem offiziellen Modul sollte in Produktion nicht verwendet werden, sondern nur als Beispielvorlage für eine eigene Source dienen.

package { ['icingaweb2', 'icingacli', 'httpd', 'nagios-plugins-all']:
  ensure => installed,
}

file { '/etc/httpd/conf.d/icingaweb2.conf':
  ensure => file,
  source => 'puppet:///modules/icingaweb2/examples/apache2/for-mod_proxy_fcgi.conf',
  notify => Service['httpd'],
}

service { 'httpd':
  ensure => running,
  enable => true,
}

Das in Abhängigkeit vom Paket icingaweb2 installierte PHP mit dem FastCGI-Dienst kann nun konfiguriert und gestartet werden. Die hier verwendete file_line Resource kann bei bedarf durch eine mit Augeas gemanagte ersetzt werden.

file_line { 'php_date_time':
  path  => '/etc/opt/rh/rh-php71/php.ini',
  line  => 'date.timezone = Europe/Berlin',
  match => '^;*date.timezone',
}

~> service { 'rh-php71-php-fpm':
  ensure => running,
  enable => true,
}

Nachdem nun alle Voraussetzungen gegeben sind, kümmern wir uns abschließend um Icinga Web 2. Dies unterteilt sich in zwei Schritte. Icinga Web 2 ist als aller erstes ein Framework für Weboberflächen, die spezifischen Sachen fürs Monitoring ist in einem Modul implementiert. Da es viele weitere zusätzliche Module gibt, folgt auch das Puppet-Modul diesem Schema.

class { 'icingaweb2':
  manage_package => false,
  import_schema  => true,
  db_name        => $web_db_name,
  db_username    => $web_db_user,
  db_password    => $web_db_pass,
  require        => Mysql::Db[$web_db_name],
}

Zuerst wird das Framework mit dem zur Authentifizierung nötigen Datenbankzugriff konfiguriert und erst dann das Monitoring-Modul. Für dieses ist der IDO-Zugriff zwingend erforderlich und der Transportweg für die zusendenden Kommandos wird mittels API konfiguriert.

class { 'icingaweb2::module::monitoring':
  ido_host        => 'localhost',
  ido_db_name     => $ido_db_name,
  ido_db_username => $ido_db_user,
  ido_db_password => $ido_db_pass,
  commandtransports => {
    icinga2 => {
      transport => 'api',
      username  => $api_user,
      password  => $api_pass,
    }
  }
}

Bleibt als letzten allen unseren Bloglesern ein Frohes Neues Jahr zu wünschen!

Lennart Betz

Autor: Lennart Betz

Der diplomierte Mathematiker arbeitet bei NETWAYS im Bereich Consulting und bereichert seine Kunden mit seinem Wissen zu Icinga, Nagios und anderen Open Source Administrationstools. Im Büro erleuchtet Lennart seine Kollegen mit fundierten geschichtlichen Vorträgen die seinesgleichen suchen.

How to use ext4 beyond 16TiB

Using large file systems with several terabytes of data is quite common. Usually system administrators use well-known file systems like ext4, xfs, zfs or newcomers like btrfs. Even ext4, the more or less standard Linux file system, supports up to 10 EiB of data and is marked as stable since Kernel 2.6.28 (release in December 2008). Increasing volumes beyond 16 TiB shouldn’t be a problem.

In the case of ext4 this is only true if the file system was explicitly created with the 64bit feature enabled, which isn’t the default on recent Linux distributions like Ubuntu 16.04. Without 64-bit support your ext4 volumes are limited to 16TiB of data. The 64bit feature is enabled by default since e2fsprogs >= 1.43, but this version isn’t packed for many Linux distributions yet.

 

Fortunately converting a 32-bit ext4 volume to 64-bit is supported since e2fsprogs >= 1.43. A online conversion is not possible.


  1. download and compile e2fsprogs, at least version 1.43
    $ git clone -b v1.43 https://git.kernel.org/pub/scm/fs/ext2/e2fsprogs.git e2fsprogs
    $ cd e2fsprogs
    $ ./configure
    $ make
    $ cd resize2fs
    $ ./resize2fs
    
  2. unmount the file system
  3. run fsck and repair your file system
  4. run resize2fs with the -b flag to enable the 64bit feature
    $ resize2fs -b /dev/my-block-device
    
  5. check if 64bit feature is enabled
    $ tune2fs -l /dev/my-block-device
    

Depending on your number of inodes the file system check and the conversion to 64-bit can took a lot of time. For resizing or running a file system check you should use at least the latest minor release of e2fsprogs of 1.42.x


For a more detailed information, just have a quick look into the Release notes of e2fsprogs and on AskUbuntu.
Achim Ledermueller

Autor: Achim Ledermueller

Der Exil Regensburger kam 2012 zu NETWAYS, nachdem er dort sein Wirtschaftsinformatik Studium beendet hatte. In der Managed Services Abteilung ist unter anderem für die Automatisierung des RZ-Betriebs und der Evaluierung und Einführung neuer Technologien zuständig.

Postfix – SPF, DKIM und DMARC

In der heutigen Zeit werden E-Mails oftmals nicht mehr über einen einzelnen Server verschickt. Wie sollten große Anbieter es sonst schaffen alle E-Mails Ihrer Millionen Nutzer zeitnah abzuhandeln? Spätestens wenn es zu Versand von Newslettern kommt, wird auf mehrere Server zurückgegriffen, damit zum Beispiel E-Mails der Mitarbeiter nicht in einer Warteschlange landen mit 100.000 Newslettern.

Damit diese Server vom Empfänger verifiziert werden können wurden die Mechanismen SPF, sowie DKIM eingeführt. Basierend auf diesen beiden kam später noch DMARC hinzu. Im folgenden möchte ich beschreiben, wie man diese Mechanismen mit Postfix verbindet und entsprechende Informationen publiziert.

 

SPF – Sender Policy Framework

Fangen wir mit SPF an. Bei SPF wird im DNS einer Domain ein TXT-Record hinterlegt. Dort gibt man in einer bestimmten Syntax an, welche Server für diese Domain verifiziert sind. Beispielhaft sieht ein SPF Record in etwa so aus:

v=spf1 ip4:1.2.3.4 ip4:1.2.3.5 a:mx.domain.tld include:other-domain.tld ?all

Dieser sagt aus, dass Mails von der IPv4 Adresse 1.2.3.4 und 1.2.3.5 verschickt werden dürfen, sowie vom Server hinter dem A-Record mx.domain.tld. Zudem sollen die Einstellungen der Domain other-domain.tld included werden und über alle anderen soll keine weiter Aussage getroffen werden mit ?all. Mit “-all” würde man den Versand über alle anderen Mailserver verbieten. Dies kann jedoch zu Problemen führen in Szenarien, wie Beispielsweise bei der Weiterleitung von Mails. Bitte beim include aufpassen, hier gibt man einiges aus der Hand, wenn “other-domain.tld” nicht von einem selbst verwaltet wird.

SPF mit Postfix verbinden

apt-get install postfix-policyd-spf-python

Anschließend öffnen wir die Datei /etc/postfix/master.cf und fügen folgendes hinzu:

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

Und um die policy auch zu verwenden, editieren wir die smtpd_recipient_restrictions in /etc/postfix/main.cf. Bitte beachtet, dass ihr diese unbedingt NACH reject_unauth_destination einfügt.

smtpd_recipient_restrictions = … reject_unauth_destination check_policy_service unix:private/postfix-policyd-spf …

Danach restarten wir postfix. Bei eingehenden Mails sollte nun ein Header enthalten sein, der in etwa wie folgt aussieht:

Received-SPF: Pass (sender SPF authorized) …

Weitere Einstellungen kann man noch unter /etc/postfix-policyd-spf-python/policyd-spf.conf vornehmen.

 

DKIM – DomainKeys Iidentified Mail

DKIM verfolgt ebenfalls das Ziel den Absender zu verifizieren, jedoch mit anderem Ansatz. Dabei werden Headerdaten, die man auch selbst definieren kann mittels eines privaten Schlüssels signiert, während sich der öffentliche Schlüssel im DNS der jeweiligen Domain befindet. Wo dieser genau zu finden ist, bestimmt der Selector – dazu aber gleich noch mehr. Sollte man die Headerdaten, welche signiert werden sollen, selbst definiert, sollte man unbedingt darauf achten, dass es Header sind, die im Verlauf des Versands nicht verändert werden, mehr dazu aber auch im RFC6376 – Abschnitt 5.4.

Beide Verfahren dienen nur dazu den Absender zu verifizieren, es bietet daher keinen Spamschutz im eigentlichen Sinn, wie manche sich vielleicht erhoffen. Sie sind aber relativ schnell eingerichtet und manche Mailserver und Dienste bewerten Mails mit gültigem SPF und DKIM besser, daher ist die Einrichtung kein absolutes “Muss”, aber dennoch ein “Nice-to-have”.

OpenDKIM mit Postfix verbinden

apt-get install opendkim opendkim-tools

Bevor wir nun mit opendkim und postfix weiter machen generieren wir erst einmal Keys, die wir verwenden möchten:

mkdir -p /etc/opendkim/keyfiles/domain1.tld
cd /etc/opendkim/keyfiles/domain1.tld
opendkim-genkey -s mail -d domain1.tld

Damit werden zum einen die Datei mail.private generiert, die den privaten Schlüssel beinhaltet, sowie mail.txt. welche den öffentlichen Schlüssel beinhaltet. Der oben genannte Selector ist “mail”. Den öffentlichen Schlüssel können wir daher schon im DNS der Domain domain1.tld hinterlegen. Dabei handelt es sich um einen Textrecord, der in unserem Beispiel unter mail._domainkey.domain.tld hinterlegt sein muss. Ist dies erledigt geht es weiter in der Konfiguration.

Anschließend ist die Datei /etc/opendkim.conf wichtig, hier wird die zentrale Konfiguration von opendkim vorgenommen. Beispielsweise so kann eine Konfiguration aussehen:

Mode sv
AutoRestart Yes
AutoRestartRate 10/1h
UMask 002
UserID opendkim:opendkim
Syslog yes
KeyTable /etc/opendkim/KeyTable
SigningTable refile:/etc/opendkim/SigningTable
Canonicalization relaxed/relaxed
LogResults yes
LogWhy yes
SyslogSuccess yes
Socket inet:10080@localhost
SignatureAlgorithm rsa-sha256

Wichtig sind hier zum einen der Port, zum anderen aber natürlich die beiden Parameter KeyTable und SigningTable. Weitere Konfigurationsparameter kann man in der Dokumentation der offiziellen Seite von opendkim nachlesen. Gehen wir aber weiter in unserem Beispiel. Ein Keytable kann z.B. wie folgt aussehen:

mail._domainkey.% %:mail:/etc/opendkim/keyfiles/domain.tld/mail.private

Das “%” in diesem Beispiel ist ein Platzhalter für die jeweilige Domain. Es werden daher alle Domains mit dem privaten Schlüssel signiert, welcher unter /etc/opendkim/keyfiles/domain.tld/mail.private liegt. Als selector wird “mail” verwendet. Sollte man für jede Domain einen anderen Key verwenden, was auch im Normalfall so ist, dann kann man einfach folgende Änderungen vornehmen:

mail._domainkey.domain1.tld domain1.tld:mail:/etc/opendkim/keyfiles/domain1.tld/mail.private
mail._domainkey.domain2.tld domain2.tld:mail:/etc/opendkim/keyfiles/domain2.tld/mail.private

Kommen wir zum SigningTable. Hier wird festgelegt, welche Mails mit welchem Eintrag im KeyTable signiert werden.

*@domain1.tld mail._domainkey.domain1.tld
*@domain2.tld mail._domainkey.domain2.tld

Auch hier kann man aber mit Wildcards und Platzhaltern arbeiten und Beispielsweise folgenden Eintrag setzen.

* mail._domainkey.%

Damit wird jede Mail signiert, mit mail._domainkey.<Name der Domain>

Will man nun noch postfix mit opendkim verbinden, ist es relativ einfach. Hier werden einfach entsprechende Einträge in der /etc/postfix/main.cf angehängt:

milter_protocol = 6
milter_default_action = accept
smtpd_milters = inet:localhost:10080
non_smtpd_milters = inet:localhost:10080

Danach einfach noch beide Services restarten und schon werden alle Mails entsprechend signiert.

 

DMARC – Domain-based Message Authentication, Reporting & Conformance

Mit DKIM und SPF haben wir schon zwei Mechanismen, mit denen ich als Absender gewisse Informationen weitergeben kann. Was der Empfänger damit anstellt ist jedoch ihm selbst überlassen. Lehnt Mailserver A eine Mail ab, weil der SPF Check fehlschlägt, lässt Mailserver B die Mail mit höherem Spamscore vielleicht durch. Die Bewertung liegt beim Empfänger, der neben SPF und DKIM noch viele weitere Checks implementiert hat um Spam entsprechend abzuwehren. Die Entscheidung, was nun mit der Mail im besten Fall passieren soll, soll DMARC dem Empfänger erleichtern und dem Sender ein wenig mehr Möglichkeiten geben.

Als Absender hinterlege ich im DNS einen entsprechenden Eintrag. Hier gibt es einige Variablen und zugehörige Optionen, die man setzen kann. Der Empfänger hingegen kann diese Empfehlung, die vom wirklichen Inhaber der Domain kommt nutzen um zu entscheiden was er mit der Mail passieren soll. Der DMARC Eintrag von Google sieht Beispielsweise wie folgt aus:

v=DMARC1; p=quarantine; sp=quarantine; rua=mailto:mailauth-reports@google.com

Dies dient lediglich als Beispiel, wer mehr über die Parameter und Optionen lesen möchte sollte den zugehröigen RFC7489 genauer ansehen

Damit ist auch schon alles getan, was man als Absender machen kann. Wichtig dabei ist der p-Parameter, der auf none (keine Aussage, Entscheidung liegt weiter beim Empfänger), quarantine (Dem Empfänger wird geraten bei einem fehlerhaften Check die Mail als Spam zu betrachten und ggf. in einen Spamordner zu verschieben), oder reject (Die Mail soll auf SMTP Ebene bereits abgelehnt werden) gesetzt werden kann. Es ist schwer hierbei eine Empfehlung oder ähnliches auszusprechen, da es immer auf den Fall an sich ankommt, welche Features man von DMARC im gegebenen Szenario verwenden möchte.

OpenDMARC mit Postfix verbinden

apt-get install opendmarc

Anschließend editieren wir die Datei /etc/default/opendmarc. Hier sind schon einige Beispiele angegeben und sind auch sehr selbsterklärend. Wir tragen folgendes ein:

SOCKET=”inet:12345@localhost”

Nun editieren wir noch die Konfiguration von DMARC, welche unter /etc/opendmarc.conf zu finden ist.

AuthservID mx.domain.tld
PidFile /var/run/opendmarc.pid
RejectFailures false
Syslog true
SyslogFacility mail
TrustedAuthservIDs localhost,mx.domain.tld
IgnoreHosts /etc/opendmarc/ignore.hosts
UMask 002
UserID
FailureReports false
AutoRestart true
HistoryFile /var/log/opendmarc.log
RecordAllMessages true
SoftwareHeader true

Danach editieren wir noch /etc/opendmarc/ignore.hosts

127.0.0.1

Die Option “SoftwareHeader true” ist eher für eure ersten Tests von Vorteil, da ihr in einem weiteren Header die verwendete Version und verarbeitete E-Mail sehen könnt:

DMARC-Filter: OpenDMARC Filter v1.3.1 mx.domain.tld A3DF6FFB75

Anschließend geht es an die Integration von OpenDMARC in Postfix. Da es sich hierbei um einen Mailfilter handelt, wird er an der bereits bekannten Stelle in der main.cf nach unserem DKIM Milter eingetragen.

smtpd_milters = inet:localhost:10080, inet:localhost:12345
non_smtpd_milters = inet:localhost:10080, inet:localhost:12345

Danach starten wir OpenDMARC und restarten Postfix. Nun sollten E-Mails einen Header enthalten, der in etwa so aussieht, falls der DMARC-Check erfolgreich war:

Authentication-Results: mx.domain.tld; dmarc=pass header.from=sender-domain.tld

Angemerkt sei, dass opemdmarc seit Version 1.3 auch selbst SPF Checks ausführen kann, falls es also bei jemandem Probleme geben sollte mit postfix-policyd-spf, kann auch der eigene SPF Check verwendet werden.

Fabian Rothlauf

Autor: Fabian Rothlauf

Fabian kehrte nach seinem fünfjährigen Ausflug nach Weimar zurück in seine Geburtsstadt Nürnberg und hat im September 2016 bei NETWAYS als Systems Engineer im Hosting Support angefangen. Der Mopsliebhaber, der schon seit seinem 16. Lebensjahr ein Faible für Adminaufgaben hat, liebt außerdem Grillen, Metal und Computerspiele. An seinem Beruf reizt ihn vor allem die Abwechslung, gute Weiterentwicklungsmöglichketen und dass es selten mal einen Stillstand gibt. Nachdem er die Berufsschulzeit bereits mit Eric und Georg genießen durfte, freut er sich bei NETWAYS nun auf weitere nette Kollegen, interessante Aufgaben und neue Blickwinkel.