{"id":486,"date":"2017-01-22T03:42:33","date_gmt":"2017-01-22T02:42:33","guid":{"rendered":"https:\/\/blog.unetresgrossebite.com\/?p=486"},"modified":"2017-01-22T06:44:42","modified_gmt":"2017-01-22T05:44:42","slug":"bluemind-migration","status":"publish","type":"post","link":"https:\/\/blog.unetresgrossebite.com\/?p=486","title":{"rendered":"BlueMind Best Practices"},"content":{"rendered":"<p>Following up on a <a href=\"https:\/\/blog.unetresgrossebite.com\/?p=42\">previous post introducing BlueMind<\/a>, today we&#8217;ll focus on good practices (OpenDKIM, SPF, DMARC, ADSP, Spamassassin, firewalling) setting up their last available release (3.5.2) &#8211; and mail servers in general &#8211; while migrating my former setup (3.14).<\/p>\n<p>A first requirement to ease up creating mailboxes, and manipulating passwords during the migration process, would be for your user accounts and mailing lists to be imported from some LDAP backend.<br \/>\nAssuming you do have a LDAP server, then you will need to create some service account in there,\u00a0so BlueMind can bind. That account should have read access to your <em>userPassword<\/em>, <em>pwdAccountLockedTime<\/em>, <em>entryUUID<\/em>, <em>entryDN<\/em>, <em>createTimestamp<\/em>, <em>modifyTimestamp<\/em> and <em>shadowLastChange<\/em>\u00a0attributes (assuming these do exist on your schema).<br \/>\nIf you also want to configure distribution lists from LDAP groups, then you may want to load the <em>dyngroup<\/em> schema.<\/p>\n<p>Another key to migrating your mail server would be to duplicate messages from one backend to another. Granted that your mailboxes already exist on both side, that some IMAP service is running on both sides, and that you can temporarily force your users password: then a tool you should consider is <a href=\"https:\/\/imapsync.lamiral.info\/\">ImapSync<\/a>. ImapSync can run for days, duplicate billions of mails, in thousands of folders, &#8230; Its simplicity is its strength.<br \/>\nIdeally, we would setup our new mail server without moving our MXs yet. The first ImapSync run could take days to complete. From there, next runs would only duplicate new messages and should go way faster: you may consider re-routing new messages to your new servers, continuing to run ImapSync until your former server stops receiving messages.<\/p>\n<p>To give you an idea, my current setup involves less than 20 users, a little under 1.500.000 messages in about 400 folders, using around\u00a030G of disk space. The initial ImapSync job ran for about 48 hours, the 3 next passes ran for less than one hour each.<br \/>\nA few years back, I did something similar involving a lot more mailboxes: in such cases, having some frontal postfix, routing messages to either one of your former and newer backend\u00a0depending on the mailbox you&#8217;re reaching could be a big help in progressively migrating users from one to the other.<\/p>\n<p>&nbsp;<\/p>\n<p>Now let&#8217;s dive into BlueMind configuration. We won&#8217;t cover the setup tasks as you&#8217;ll find these in <a href=\"https:\/\/forge.bluemind.net\/confluence\/display\/BM35\/Configuration+post-installation\">BlueMind documentation<\/a>.<\/p>\n<p>Assuming you managed to\u00a0install BlueMind, and that your users base is stored in some LDAP, make sure to install BlueMind LDAP import plugin:<\/p>\n<blockquote><p>apt-get install\u00a0bm-plugin-admin-console-ldap-import bm-plugin-core-ldap-import<\/p><\/blockquote>\n<p>Note that if you were used to previous BlueMind releases, you will now need to grant each user with their accesses to your BlueMind services, including the webmail. By default, a newly created user account may only access its settings.<br \/>\nThe management\u00a0console\u00a0would allow you to grant such permissions, there&#8217;s a lot of new stuff in this new release: multiple calendars per user, external calendars support, large files handling detached from webmail, &#8230;<\/p>\n<p>&nbsp;<\/p>\n<p>The first\u00a0thing we will configure is some firewall.<br \/>\nNote that Blue-Mind recommend to setup their service behind some kind of router, avoid exposing your instance directly to the Internet. Which is a good practice hosting pretty much everything anyway. Even though, you may want to setup some firewall.<br \/>\nNote that having your firewall up and running may lead to BlueMind installation script failing to complete: make sure to keep it down until you&#8217;re done with BlueMind installer.<\/p>\n<p>On\u00a0Debian, you may find the <a href=\"https:\/\/firehol.org\/\">Firehol<\/a> package to provide with an easy-to-configure firewall.<br \/>\nThe service you would need to open for public access being smtp (TCP:25), http (TCP:80), imap (TCP:143), https (TCP:443), smtps (TCP:465), submission (TCP:587)\u00a0and\u00a0imaps (TCP:993).<br \/>\nAssuming firehol, your configuration would look like this:<\/p>\n<blockquote><p>mgt_ips=&#8221;1.2.3.4\/32 2.3.4.5\/32&#8243;<br \/>\ninterface eth0 WAN<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;protection strong<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;server smtp accept<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;server http accept<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;server imap accept<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;server https accept<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;server smtps accept<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;server submission accept<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;server imaps accept<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;server custom openssh &#8220;tcp\/1234&#8221; default accept src &#8220;$mgt_ips&#8221;<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;server custom munin &#8220;tcp\/4949&#8221; default accept src &#8220;$mgt_ips&#8221;<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;server custom nrpe &#8220;tcp\/5666&#8221; default accept src &#8220;$mgt_ips&#8221;<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;client all accept<\/p><\/blockquote>\n<p>You may then restart your firewall. To be safe, you could restart BlueMind as well.<\/p>\n<p>Optionally, you may want to use something like <a href=\"http:\/\/www.fail2ban.org\/wiki\/index.php\/Main_Page\">Fail2ban<\/a>, also available on Debian.\u00a0You may not be able to track all abusive accesses, although you could lock out SMTP authentication brute-forces at the very least, which is still relevant.<\/p>\n<p>Note that BlueMind also provides with a plugin you could install from the packages cache extracted during BlueMind installation:<\/p>\n<blockquote><p>apt-get install bm-plugin-core-password-bruteforce<\/p><\/blockquote>\n<p>&nbsp;<\/p>\n<p>The second\u00a0thing we would do is to install some valid certificate. \u00a0These days, services like <a href=\"https:\/\/letsencrypt.org\/\">LetsEncrypt<\/a> would issue free x509 certificates.<br \/>\nStill assuming Debian, a LetsEncrypt client is available in jessie-backports: certbot. This client would either need access to some directory served by your webserver, or would need to bind on your TCP port 443, so that LetsEncrypt may validate the common name you are requesting actually routes back to the server issuing this request. In the later case, we would do something like this:<\/p>\n<blockquote><p># certbot certonly &#8211;standalone &#8211;text &#8211;email me@example.com &#8211;agree-tos &#8211;domain mail.example.com &#8211;renew-by-default<\/p><\/blockquote>\n<p>Having figured out how you&#8217;ll generate your certificate, we will now want to configure BlueMind services loading it in place of the self-signed one generated during installation:<\/p>\n<blockquote><p># cp -p \/etc\/ssl\/certs\/bm_cert.pem \/root\/bm_cert.pem.orig<br \/>\n# cat\u00a0\/etc\/letsencrypt\/live\/$CN\/privkey.pem \/etc\/letsencrypt\/live\/$CN\/fullchain.pem &gt;\/etc\/ssl\/certs\/bm_cert.pem<\/p><\/blockquote>\n<p>Additionally, you will want to edit postfix configuration using LetsEncrypt certificate chain. In <em>\/etc\/postfix\/main.cf<\/em>, look for\u00a0<em>smtpd_tls_CAfile<\/em> and set it to <em>\/etc\/letsencrypt\/live\/$CN\/chain.pem<\/em>.<\/p>\n<p>You may now reload or restart postfix (smtps) and bm-nginx (both https &amp; imaps).<\/p>\n<p>Note that LetsEncrypt certificates are valid for 3 months. You&#8217;ll probably want to install some cron job renewing your certificate, updating\u00a0<em>\/etc\/ssl\/certs\/bm_cert.pem<\/em> then reloading postfix and bm-nginx.<\/p>\n<p>&nbsp;<\/p>\n<p>The next thing we would configure is OpenDKIM signing our outbound messages and validating signatures\u00a0of inbound messages.<br \/>\nDebian has some <em>opendkim<\/em> package embedding everything you&#8217;ll need on a mail relay. Generating keys, you will also need to install <em>opendkim-tools<\/em>.<\/p>\n<p>Create some directory layout and your keys:<\/p>\n<blockquote><p># cd \/etc<br \/>\n# mkdir dkim.d<br \/>\n# cd dkim.d<br \/>\n# mkdir keys keys\/example1.com keys\/example2.com keys\/exampleN.com<br \/>\n# for d in example1 example2 exampleN; do \\<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;( cd keys\/$d.com;\u00a0opendkim-genkey -r -d $d.com ); done<br \/>\n# chmod 0640 *\/default.private<br \/>\n# chown root:opendkim *\/default.private<\/p><\/blockquote>\n<p>In each of <em>\/etc\/dkim.d\/keys<\/em> subdir, you will find a <em>default.txt<\/em> file that contains the DNS record you should add to the corresponding zone. Its content would look like the following:<\/p>\n<blockquote><p>default._domainkey IN TXT &#8220;v=DKIM1; k=rsa; p=PUBLICKEYDATA&#8221;<\/p><\/blockquote>\n<p>You should have these DNS records ready prior to having\u00a0configured Postfix signing your messages.<br \/>\nHaving generated our keys, we still need to configure OpenDKIM signing messages. On Debian, the main configuration is <em>\/etc\/opendkim.conf<\/em>, and should contain something like this:<\/p>\n<blockquote><p>Syslog yes<br \/>\nUMask 002<br \/>\nOversignHeaders From<br \/>\nKeyTable \/etc\/dkim.d\/KeyTable<br \/>\nSigningTable \/etc\/dkim.d\/SigningTable<br \/>\nExternalIgnoreList \/etc\/dkim.d\/TrustedHosts<br \/>\nInternalHosts \/etc\/dkim.d\/TrustedHosts<\/p><\/blockquote>\n<p>You would need to create the 3 files we&#8217;re referring to in there, the first one being <em>\/etc\/dkim.d\/KeyTable<\/em>:<\/p>\n<blockquote><p>default._domainkey.example1.com\u00a0example1.com:default:\/etc\/dkim.d\/keys\/example1.com\/default.private<br \/>\ndefault._domainkey.example2.com\u00a0example2.com:default:\/etc\/dkim.d\/keys\/example2.com\/default.private<br \/>\ndefault._domainkey.exampleN.com\u00a0exampleN.com:default:\/etc\/dkim.d\/keys\/exampleN.com\/default.private<\/p><\/blockquote>\n<p>The second one is <em>\/etc\/dkim.d\/SigningTable<\/em> and would contain something like this:<\/p>\n<blockquote><p>example1.com\u00a0default._domainkey.example1.com<br \/>\nexample2.com\u00a0default._domainkey.example2.com<br \/>\nexampleN.com\u00a0default._domainkey.exampleN.com<\/p><\/blockquote>\n<p>And the last one, <em>\/etc\/dkim.d\/TrustedHosts<\/em> would contain a list of the subnets we should sign messages for, such as<\/p>\n<blockquote><p>1.2.3.4\/32<br \/>\n2.3.4.5\/32<br \/>\n127.0.0.1<br \/>\nlocalhost<\/p><\/blockquote>\n<p>Now, let&#8217;s ensure OpenDKIM would start on boot, editing\u00a0<em>\/etc\/default\/opendkim<\/em>\u00a0with following:<\/p>\n<blockquote><p>DAEMON_OPTS=<br \/>\nSOCKET=&#8221;inet:12345@localhost&#8221;<\/p><\/blockquote>\n<p>Having started OpenDKIM and made sure the service is properly listening on TCP:12345, you may now configure Postfix relaying its messages to OpenDKIM. Edit your <em>\/etc\/postfix\/main.cf<\/em> adding the following:<\/p>\n<blockquote><p>milter_default_action = accept<br \/>\nsmtpd_milters = inet:localhost:12345<br \/>\nnon_smtpd_milters = inet:localhost:12345<\/p><\/blockquote>\n<p>Restart Postfix, make sure mail delivery works. Assuming you can already send outbound messages, make sure\u00a0your DKIM signature appears to be valid for other mail providers (an obvious one being gmail).<\/p>\n<p>&nbsp;<\/p>\n<p>Next, we&#8217;ll configure SPF validation of inbound messages.<br \/>\nOn Debian, you would need to install\u00a0<em>postfix-policyd-spf-perl.<\/em><\/p>\n<p>Let&#8217;s edit <em>\/etc\/postfix\/master.cf<\/em>, adding a service validating inbound messages matches sender&#8217;s domain SPF policy:<\/p>\n<blockquote><p>spfcheck unix &#8211; n n &#8211; 0 spawn<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;user=policyd-spf argv=\/usr\/sbin\/postfix-policyd-spf-perl<\/p><\/blockquote>\n<p>Next, edit <em>\/etc\/postfix\/main.cf<\/em>, look for <em>smtpd_recipient_restrictions<\/em>. The last directive should be a <em>reject_unauth_destination<\/em>, and should precede the policy check we want to add:<\/p>\n<blockquote><p>smtpd_recipient_restrictions=permit_sasl_authenticated,<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;permit_mynetworks,reject_unauth_destination,<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;check_policy_service unix:private\/policyd-spf<\/p><\/blockquote>\n<p>Restart Postfix, make sure you can still properly receive messages. Checked messages should now include some <em>Received-SPF<\/em> header.<\/p>\n<p>&nbsp;<\/p>\n<p>Finally, we&#8217;ll configure SPAM checks and <a href=\"http:\/\/spamassassin.apache.org\/\">Spamassassin<\/a> database training.<br \/>\nOn Debian, you&#8217;ll need to install <em>spamassassin<\/em>.<\/p>\n<p>Let&#8217;s edit <em>\/etc\/spamassassin\/local.cf<\/em> defining a couple trusted IPs, and configuring Spamassassin to rewrite the subject for messages detected as SPAM:<\/p>\n<blockquote><p>rewrite_header Subject [ SPAM _SCORE_ ]<br \/>\ntrusted_networks\u00a01.2.3.4\/32 2.3.4.5\/32<br \/>\nscore ALL_TRUSTED -5<br \/>\nrequired_score 2.0<br \/>\nuse_bayes 1<br \/>\nbayes_auto_learn 1<br \/>\nbayes_path \/root\/.spamassassin\/bayes<br \/>\nbayes_ignore_header X-Spam-Status<br \/>\nbayes_ignore_header X-Spam-Flag<br \/>\nifplugin Mail::SpamAssassin::Plugin::Shortcircuit<br \/>\nshortcircuit ALL_TRUSTED on<br \/>\nshortcircuit BAYES_99 spam<br \/>\nshortcircuit BAYES_00 ham<br \/>\nendif<\/p><\/blockquote>\n<p>Configure Spamassassin service defaults in <em>\/etc\/default\/spamassassin<\/em>:<\/p>\n<blockquote><p>CRON=1<br \/>\nENABLED=1<br \/>\nNICE=&#8221;&#8211;nicelevel 15&#8243;<br \/>\nOPTIONS=&#8221;&#8211;create-prefs &#8211;max-children 5 -H \/var\/log\/spamassassin -s \/var\/log\/spamassassin\/spamd.log&#8221;<br \/>\nPIDFILE=\/var\/run\/spamd.pid<\/p><\/blockquote>\n<p>Make sure <em>\/root\/.spamassassin<\/em> and <em>\/var\/log\/spamassassin<\/em> both exist.<\/p>\n<p>Now let&#8217;s configure Spamassassin to lear from BlueMind SPAM folders content, create or edit\u00a0<em>\/etc\/spamassassin\/sa-learn-cyrus.con<\/em>f with the following content:<\/p>\n<blockquote><p>[global]<br \/>\ntmp_dir = \/tmp<br \/>\nlock_file = \/var\/lock\/sa-learn-cyrus.lock<br \/>\nverbose = 1<br \/>\nsimulate = no<br \/>\nlog_with_tag = yes<\/p>\n<p>[mailbox]<br \/>\ninclude_list = &#8221;<br \/>\ninclude_regexp = &#8216;.*&#8217;<br \/>\nexclude_list = &#8221;<br \/>\nexclude_regexp = &#8221;<br \/>\nspam_folder = &#8216;Junk&#8217;<br \/>\nham_folder = &#8216;Inbox&#8217;<br \/>\nremove_spam = yes<br \/>\nremove_ham = no<\/p>\n<p>[sa]<br \/>\ndebug = no<br \/>\nsite_config_path = \/etc\/spamassassin<br \/>\nlearn_cmd = \/usr\/bin\/sa-learn<br \/>\nbayes_storage = berkely<br \/>\nprefs_file = \/etc\/spamassassin\/local.cf<br \/>\nfix_db_permissions = yes<br \/>\nuser = mail<br \/>\ngroup = mail<br \/>\nsync_once = yes<br \/>\nvirtual_config_dir = &#8221;<\/p>\n<p>[imap]<br \/>\nbase_dir = \/var\/spool\/cyrus\/example_com\/domain\/e\/example.com\/<br \/>\ninitial_letter = yes<br \/>\ndomains = &#8221;<br \/>\nunixhierarchysep = no<br \/>\npurge_cmd = \/usr\/lib\/cyrus\/bin\/ipurge<br \/>\nuser = cyrus<\/p><\/blockquote>\n<p>Look out for <a href=\"https:\/\/github.com\/dtouzeau\/artica-1.5\/blob\/master\/bin\/sa-learn-cyrus\">sa-learn-cyrus script<\/a>. Note that Debian provides with a package with that name, that would pull cyrus as a dependency &#8211; which is definitely something you want on a BlueMind server.<br \/>\nRun this script to train Spamassassin from the messages in your Inboxes and Junk folders. Eventually, you could want to install some cron job.<\/p>\n<p>Start or restart Spamassassin service. Now, let&#8217;s configure Postfix piping its messages to Spamassassin. Edit <em>\/etc\/postfix\/master.cf<\/em>, add the following service:<\/p>\n<blockquote><p>spamassassin unix &#8211; n n &#8211; &#8211; pipe<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;user=debian-spamd argv=\/usr\/bin\/spamc -f -e<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;\/usr\/sbin\/sendmail -oi -f ${sender} ${recipient}<\/p><\/blockquote>\n<p>Still in \/etc\/postfix\/master.cf, locate the smtp service, and add a <em>content_filter<\/em> option pointing to our spamassassin service:<\/p>\n<blockquote><p>smtp \u00a0 \u00a0 \u00a0inet \u00a0n \u00a0 \u00a0 \u00a0 &#8211; \u00a0 \u00a0 \u00a0 n \u00a0 \u00a0 \u00a0 &#8211; \u00a0 \u00a0 \u00a0 &#8211; \u00a0 \u00a0 \u00a0 smtpd<br \/>\n&nbsp;&nbsp;&nbsp;&nbsp;-o content_filter=spamassassin<\/p><\/blockquote>\n<p>Restart Postfix. Sending or receiving messages, you should read about spamd in <em>\/var\/log\/mail.log<\/em>. Moreover, a\u00a0<em>X-Spam-Checker-Version<\/em> header should show in your messages.<\/p>\n<p>&nbsp;<\/p>\n<p>Prior to migrating your messages, make sure to mount <em>\/var\/spool\/cyrus<\/em> on a separate device, and <em>\/var\/backups\/bluemind<\/em> on some NFS share, LUN device, sshfs, &#8230;. something remote, ideally.<br \/>\nYour <em>\/tmp<\/em> may be mounted from <em>tmpfs<\/em>, and could use the <em>nosuid<\/em> and <em>nodev<\/em> options &#8211; although you can not set <em>noexec<\/em>.<\/p>\n<p>Assuming you have some monitoring system running: make sure to keep an eye on mail queues, smtp service availability or disk space among others, &#8230;<\/p>\n<p>&nbsp;<\/p>\n<p>Being done migrating your setup, the last touch would be to set proper SPF, ADSP and DMARC policies (DNS records).<\/p>\n<p>Your SPF record defines which IPs may issue mail on behalf of your domain. Usually, you just want to allow your MXs (<em>mx<\/em>). Maybe you&#8217;ll want to trust some additional record, &#8230; And deny everyone else (<em>-all<\/em>). Final record could look like this:<\/p>\n<blockquote><p>@ IN TXT &#8220;v=spf1 mx a:non-mx-sender.example.com -all&#8221;<\/p><\/blockquote>\n<p>Having defined your SPF policy, and assuming you properly configured DKIM signing, while corresponding\u00a0public key is published in your DNS, then you may consider defining some DMARC policy as well.<\/p>\n<blockquote><p>@ IN TXT v=DMARC1; p=quarantine; pct=100; rua=mailto:postmaster@example.com<\/p><\/blockquote>\n<p>And ADSP:<\/p>\n<blockquote><p>_adsp._domainkey IN TXT &#8220;dkim=all;&#8221;<\/p><\/blockquote>\n<p>&#8230; and that&#8217;s pretty much it. The rest&#8217;s up to you, and would probably be doable from BlueMind administration console.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Following up on a previous post introducing BlueMind, today we&#8217;ll focus on good practices (OpenDKIM, SPF, DMARC, ADSP, Spamassassin, firewalling) setting up their last available release (3.5.2) &#8211; and mail servers in general &#8211; while migrating my former setup (3.14). A first requirement to ease up creating mailboxes, and manipulating passwords during the migration process, [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[8,10,2],"tags":[],"_links":{"self":[{"href":"https:\/\/blog.unetresgrossebite.com\/index.php?rest_route=\/wp\/v2\/posts\/486"}],"collection":[{"href":"https:\/\/blog.unetresgrossebite.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.unetresgrossebite.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.unetresgrossebite.com\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.unetresgrossebite.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=486"}],"version-history":[{"count":21,"href":"https:\/\/blog.unetresgrossebite.com\/index.php?rest_route=\/wp\/v2\/posts\/486\/revisions"}],"predecessor-version":[{"id":507,"href":"https:\/\/blog.unetresgrossebite.com\/index.php?rest_route=\/wp\/v2\/posts\/486\/revisions\/507"}],"wp:attachment":[{"href":"https:\/\/blog.unetresgrossebite.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=486"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.unetresgrossebite.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=486"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.unetresgrossebite.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=486"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}