Просмотр исходного кода

Add DKIM/DMARC/SPF setup to tcms mail target

George Baugh 1 год назад
Родитель
Сommit
48d1fba1d1
3 измененных файлов с 150 добавлено и 2 удалено
  1. 21 2
      Installer.mk
  2. 99 0
      mail/mongle_dkim_config
  3. 30 0
      mail/mongle_dmarc_config

+ 21 - 2
Installer.mk

@@ -87,11 +87,12 @@ nginx:
 	[ -n "$$SERVER_PORT" ] || ( echo "Please set the SERVER_PORT environment variable before running (e.g. 5000)" && /bin/false )
 	sed 's/\%SERVER_NAME\%/$(SERVER_NAME)/g' nginx/tcms.conf.tmpl > nginx/tcms.conf.intermediate
 	sed 's/\%SERVER_PORT\%/$(SERVER_PORT)/g' nginx/tcms.conf.intermediate > nginx/tcms.conf
+	sudo apt-get install nginx certbot
 	rm nginx/tcms.conf.intermediate
 	sudo mkdir -p '/var/www/$(SERVER_NAME)'
 	sudo mkdir -p '/var/www/mail.$(SERVER_NAME)'
 	sudo mkdir -p '/etc/letsencrypt/live/$(SERVER_NAME)'
-	[ -e "/etc/nginx/sites-enabled/$$SERVER_NAME.conf" ] && sudo rm "/etc/nginx/sites-enabled/$$SERVER_NAME.conf"
+	[ -e "/etc/nginx/sites-enabled/$$SERVER_NAME.conf" ] && sudo rm "/etc/nginx/sites-enabled/$$SERVER_NAME.conf"; /bin/true
 	sudo ln -sr nginx/tcms.conf '/etc/nginx/sites-enabled/$(SERVER_NAME).conf'
 	# Make a self-signed cert FIRST, because certbot has a chicken/egg problem
 	sudo openssl req -x509 -config etc/openssl.conf -nodes -newkey rsa:4096 -subj '/CN=$(SERVER_NAME)' -addext 'subjectAltName=DNS:www.$(SERVER_NAME),DNS:mail.$(SERVER_NAME)' -keyout '/etc/letsencrypt/live/$(SERVER_NAME)/privkey.pem' -out '/etc/letsencrypt/live/$(SERVER_NAME)/fullchain.pem' -days 365
@@ -113,7 +114,25 @@ mail: nginx
 	sudo sed -i 's/^\(smtpd_tls_key_file\s*=\).*/\1\/etc\/letsencrypt\/live\/$(SERVER_NAME)\/privkey.pem/g' /etc/postfix/main.cf
 	sudo sed -i 's/^\(myhostname\s*=\).*/\1$(SERVER_NAME)/g' /etc/postfix/main.cf
 	sudo echo '$(SERVER_NAME)' > /etc/mailname
-	# TODO everything else
+	# Do NOT bother with mysql crap on opendkim
+	sudo apt-get install opendmarc opendkim opendkim-tools libunbound-dev
+	# OpenDKIM keys & configuration
+	sudo mkdir -p /etc/opendkim/keys
+	sudo opendkim-genkey --directory /etc/opendkim/keys -s mail -d $(SERVER_NAME)
+	sudo openssl rsa -in /etc/opendkim/keys/$(SERVER_NAME)/mail.private -pubout > /etc/opendkim/keys/$(SERVER_NAME)/mail.public
+	sudo chown -R opendkim:opendkim /etc/opendkim
+	# Find the signing table and inject the key in there for our domain
+	sudo mail/mongle_dkim_config $(SERVER_NAME)
+	sudo mail/mongle_dmarc_config $(SERVER_NAME) mail.$(SERVER_NAME)
+	sudo service opendkim enable
+	sudo service opendmarc enable
+	sudo service opendkim start
+	sudo service opendmarc start
+	# Configure postfix to put on its socks and shoes
+	postconf milter_default_action=accept
+	postconf milter_protocol=2
+	postconf smtpd_milters=local:opendkim/opendkim.sock,local:opendmarc/opendmarc.sock
+	postconf non_smtpd_milters=\$smtpd_milters
 
 .PHONY: all
 all: prereq-debian install fail2ban mail

+ 99 - 0
mail/mongle_dkim_config

@@ -0,0 +1,99 @@
+#!/usr/bin/env perl
+
+use strict;
+use warnings;
+
+no warnings qw{experimental};
+use feature qw{state signatures};
+
+use List::Util qw{uniq};
+use Config::Simple;
+use File::Copy;
+use File::Touch;
+use DNS::Unbound;
+use Net::DNS::Packet;
+
+my @domains2add = @ARGV;
+
+my $dkim_config_file   = "/etc/opendkim.conf";
+my $trusted_hosts_file = '/etc/opendkim/TrustedHosts';
+my $keytable_file      = '/etc/opendkim/KeyTable';
+my $signing_table_file = '/etc/opendkim/SigningTable';
+
+DKIM_CONFIG: {
+    my $cfg = Config::Simple->new($dkim_config_file);
+    die "Can't open opendkim config file" unless $cfg;
+
+    $cfg->param('KeyTable',           $keytable_file );
+    $cfg->param('SigningTable',       $signing_table_file);
+    $cfg->param('ExternalIgnoreList', $trusted_hosts_file);
+    $cfg->param('InternalHosts',      $trusted_hosts_file);
+
+    # This way we support signing more than one domain
+    $cfg->delete('Domain');
+    $cfg->delete('KeyFile');
+    $cfg->delete('Selector');
+
+    File::Copy::copy($dkim_config_file, "$dkim_config_file.bak") or die "Could not back up old dkim config";
+    $cfg->save();
+
+    print "OpenDKIM config file ($dkim_config_file) changed.\n";
+}
+
+TRUSTED_HOSTS: {
+    my @hosts = read_lines( $trusted_hosts_file );
+
+    my @ips2add = grep { defined $_ } map {
+        ( domain2ips( $_, "A" ),
+        domain2ips( $_, "AAAA" ) )
+    } @domains2add;
+
+    push(@hosts, "127.0.0.1", "localhost", "::1", @domains2add, @ips2add);
+    @hosts = uniq @hosts;
+
+    backup_and_emit( $trusted_hosts_file, @hosts);
+}
+
+KEY_TABLE: {
+    my @lines = read_lines( $keytable_file );
+
+    push(@lines, (map { "mail._domainkey.$_ $_:mail:/etc/opendkim/keys/$_/mail.private" } @domains2add ) );
+    @lines = uniq @lines;
+
+    backup_and_emit($keytable_file, @lines);
+}
+
+SIGNING_TABLE: {
+    my @lines = read_lines( $signing_table_file );
+
+    push(@lines, (map { "$_ mail._domainkey.$_" } @domains2add ) );
+    @lines = uniq @lines;
+
+    backup_and_emit($signing_table_file, @lines);
+}
+
+sub read_lines( $file ) {
+    File::Touch::touch($file);
+    open(my $fh, '<', $file);
+    my @lines = map { chomp $_; $_ } readline $fh;
+    close $fh;
+    return @lines;
+}
+
+sub backup_and_emit($file, @lines) {
+    File::Copy::copy($file, "$file.bak") or die "Could not back up $file";
+    open(my $wh, '>', $file);
+    foreach my $line (@lines) {
+        print $wh "$line\n";
+    }
+    close $wh;
+    print "$file changed.\n";
+}
+
+sub domain2ips( $domain, $type ) {
+    state $resolver = DNS::Unbound->new();
+
+    my $p = $resolver->resolve( $domain, $type )->answer_packet();
+    my @rrs = Net::DNS::Packet->new( \$p )->answer;
+    return map { $_->address } @rrs;
+}

+ 30 - 0
mail/mongle_dmarc_config

@@ -0,0 +1,30 @@
+#!/usr/bin/env perl
+
+use strict;
+use warnings;
+
+use List::Util qw{uniq};
+use Config::Simple;
+use File::Copy;
+
+my @domains2add = @ARGV;
+
+my $dmarc_config_file = "/etc/opendmarc.conf";
+
+my $cfg = Config::Simple->new($dmarc_config_file);
+die "Can't open opendmarc config file" unless $cfg;
+
+$cfg->param('IgnoreAuthenticatedClients', 'true');
+$cfg->param('RequiredHeaders',            'true');
+$cfg->param('SPFSelfValidate',            'true');
+
+my @authserv = $cfg->param('TrustedAuthservIDs');
+push(@authserv, @domains2add);
+@authserv = uniq @authserv;
+
+$cfg->param('TrustedAuthservIDs', \@authserv);
+
+File::Copy::copy($dmarc_config_file, "$dmarc_config_file.bak") or die "Could not back up old dmarc config";
+$cfg->save();
+
+print "OpenDMARC config file ($dmarc_config_file) changed.\n";