2022/12/25(日)メールサーバの中規模改修と基礎知識(3)~ Dovecot+Pigeonhole,cert-bot

次は、電子メール受信の中核を成す dovecot まわりの構築です。
dovecot は、どうやら「ダブコット」或いは「ダヴコット」と称するようです。
日本人だと、どうしても「どべこっと」と言いたくなるのではないかと思う。。

概要

dovecot は、2022/12/22 に最新版 Ver 2.3.20 がリリースされました。
今回、dovecot で実現する構成は、概ね下記のような、下手くそな手書きで描いたようなものになります。
20221225_dovecot_2022.png

【注:この構成図は電子メール受信処理に特化したイメージ図であり、実際の dovecot 内部構成を示したものではありません。
   むしろ全く無関係です。】


構築するメールサーバの Port 110,143,993,995 で電子メールを受信するアクションを待ち、そのアクションに従ってサーバ上で受信している電子メールメッセージをダウンロードするのが、dovecot の主な任務です。

POP3 も IMAP4 も受信者を認識する個別情報(アカウント名とパスワード) にてユーザ認証をし、受信者固有のメールボックスを特定する処理を行います。そのような情報は、弊社では OpenLDAP のデータベースにて管理しており、そのために、OpenLDAP へアカウント問い合わせを行う Port 389 が使われます。OpenLDAP のSSL/TLS 対応ポートに Port 636 がありますが、OpenLDAP を同じサーバ上で稼働させるため、localhost:389 への接続となり、SSL/TLS は不要です。

また、Postfix から、配送されてくる電子メールメッセージが、LMTP インタフェースを介して流れてきます。
LMTP インタフェースは、unix ソケットで実現します。こうすることで、サーバのリソース消費を大きく増やさずに且つ高速に受信処理が出来るようになります。LMTP でも受信者のメールボックスを特定させるために、OpenLDAP へのアカウント問い合わせを実施します。

dovecotのインストール

ここからは、基本的に root アカウントでの作業となります。
「ソースコードのコンパイルは、root以外の一般ユーザで行うべき」というポリシーを堅持する開発者が居られますが、大抵の場合、上手くいきません。

dovecot をインストールする場合、FreeBSD13 では、下記のモジュールが事前に必要です。(但し、2022/12/24 現在)
これらの多くは、Ports や Package でインストールしても、管理上特段問題にはなりません。
 ・perl5-5.36.0	(Ports から カテゴリ:lang)
 ・autoconf-2.71	(Ports から カテゴリ:devel)
 ・libltdl-2.4.7	(Ports から カテゴリ:devel)
 ・libtool-2.4.7	(Ports から カテゴリ:devel)
 ・pcre2-10.40		(Ports から カテゴリ:devel)
 ・OpenLDAP 2.6.3 以上 (これはソースコードからの構築を強く推奨)
このあたりは、バージョンアップで刻々変わっていくこともあるのですが、管理する以上は、そのような変化を知ることが重要です。
Ports や Package では、このあたりを余計なモジュールまで自動インストールしてしまうことが多々あり、「いざトラブル!」という際に却って対応困難になる原因を作ります。
それが嫌なので、要所なサーバサイドソフトウェアについては、Ports や Package に頼らずに、敢えてソースコードからの構築を行い、技術対応力低下の防止に努力しています。

更に、インストールに先立ち、dovecot のセキュリティポリシーに従うため、ユーザ dovecot・ユーザ dovenull を、vipw や useradd コマンドで追加します:
dovecot::2002:3000::0:0:dovecot MDA:nonexistent:/usr/sbin/nologin
dovenull::2007:3000::0:0:dovecot MRA:nonexistent:/usr/sbin/nologin
vipw でユーザ追加した場合、/etc/group に下記の1行を追加しておきます(あとでこれが重要になってくる):
mailuser:*:3000:
更に vipw でユーザ追加した場合は、つまらないセキュリティホールを作らないために、下記コマンドも一応実行しておきます:
# passwd dovecot
# passwd dovenull
はい。いよいよコンパイル作業です。下記のように順に実施していきます:
# cp dovecot-2.3.19.1.tar.gz /usr/local/src
# cd /usr/local/src
# tar xvzf dovecot-2.3.19.1.tar.gz
# cd dovecot-2.3.19.1
 	 
# setenv CPPFLAGS '-I/usr/local/include -I/usr/include'	(configure が上手くライブラリを探せないため)
# setenv LDFLAGS '-L/usr/local/lib -L/usr/lib'     (configure が上手くライブラリを探せないため)
# setenv LD_LIBRARY_PATH '/usr/local/lib /usr/lib'   (コンパイルが上手くいかないため)

※以下、説明のために改行していますが、 ./configure の部分は、改行せずに、半角スペース区切りで、一気に入力。
# ./configure --sysconfdir=/usr/local/etc (設定ファイル群を格納するディレクトリ)
       --localstatedir=/var     (unix ソケットなどを格納するルートディレクトリ)
       --with-ldap=yes       (LDAP 認証をサポートする)
       --with-ssldir=/usr      (openssl のインストール位置を知らせる)
       --with-zlib         (zlib[gz 形式圧縮] をサポートする)
       --with-libwrap        (TCP Wrapper をサポートする)
       --without-bsdauth      (BSD 認証はサポートしない)
       --without-pam         (pam 認証はサポートしない)
       --without-nss        (nss はサポートしない)
上記は、dovecot 2.3.19.1 の場合で、バージョンが変わると、この部分も変わります。適宜解釈を。
./configure が成功すると、下記のような情報が出力されます:
Install prefix . : /usr/local
File offsets ... : 64bit
I/O polling .... : kqueue
I/O notifys .... : kqueue
SSL ............ : yes (OpenSSL)
GSSAPI ......... : no
passdbs ........ : static passwd passwd-file checkpassword ldap
CFLAGS ......... : -std=gnu99 -g -O2 -fstack-protector-strong -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 -Wall -W -Wmissing-prototypes -Wmissing-declarations -Wpointer-arith -Wchar-subscripts -Wformat=2 -Wbad-function-cast -Wno-duplicate-decl-specifier -Wstrict-aliasing=2
         : -shadow -pam -bsdauth -sia -vpopmail -sql
userdbs ........ : static prefetch passwd passwd-file checkpassword ldap
         : -vpopmail -sql
SQL drivers .... :
         : -pgsql -mysql -sqlite -cassandra
Full text search : squat
         : -lucene -solr
ここでは、OpenLDAP でユーザ管理をすることを前提にしているため、passdbs 行と userdbs 行に 'ldap' の文字列が存在することを確認します。
# make
# make install
# cd /usr/local/libexec/dovecot
# chmod 4750 dovecot-lda	(setuid でメール配信出来るようにする)
# chgrp mailuser dovecot-lda	(setuid でメール配信出来るようにする)
結構、大きなプログラム群なので、make は、そこそこの時間がかかります。
dovecot-lda は、Courier maildrop に相当する実行モジュールで、setuid を可能にすることで、後述する pignonhole で、メールアカウント毎の動作が可能になります。

次に、
# cd /usr/local/etc/dovecot
として、設定内容をこのディレクトリに記述していきます。dovecot 2.x では、設定ファイルが細かく分かれており、既存Webサイトにおける同種の説明も、教科書的にそれに沿ったものになっていますが、却って管理しにくくなるという我儘から、最低限の設定ファイルを上記ディレクトリに書き込んでいきます。

まずは、 dovecot.conf から〔注:不要な設定があるかもしれません(当方の環境では警告もエラーも出ません)〕:
auth_cache_negative_ttl = 30 mins
auth_cache_size = 10 M
auth_cache_ttl = 30 mins
auth_mechanisms = cram-md5 digest-md5 plain login scram-sha-1 apop
auth_username_chars = abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.-_@
disable_plaintext_auth = no
first_valid_uid = 3000
last_valid_gid = 4000
last_valid_uid = 4999
mail_location = maildir:/var/mail/%h

!include ssl_sni.conf

passdb {
  args = /usr/local/etc/dovecot/dovecot-ldap.conf
  driver = ldap
}
protocols = imap pop3 lmtp

plugin {
  sieve = ~/.dovecot.sieve
  sieve_plugins = sieve_extprograms
  sieve_extensions = +vnd.dovecot.filter
  sieve_filter_bin_dir = /usr/local/etc/dovecot/sieve-filter
}
  unix_listener /var/spool/postfix/private/auth {
    group = postdrop
    mode = 0660
    user = postfix
  }
  user = root
  vsz_limit = 128 M
}
service imap-login {
  chroot =
  executable = /usr/local/libexec/dovecot/imap-login
  inet_listener imap {
    address = *,[::]
    port = 143
  }
  inet_listener imaps {
    address = *,[::]
    port = 993
  }
  user = dovecot
  vsz_limit = 32M
}
service imap {
  executable = /usr/local/libexec/dovecot/imap
}
service imaps {
  executable = /usr/local/libexec/dovecot/imap
}

service pop3-login {
  chroot =
  executable = /usr/local/libexec/dovecot/pop3-login
  inet_listener pop3 {
    address = *,[::]
    port = 110
  }
  inet_listener pop3s {
    address = *,[::]
    port = 995
  }
  user = dovecot
}
service pop3 {
  executable = /usr/local/libexec/dovecot/pop3
}
service pop3s {
  executable = /usr/local/libexec/dovecot/pop3
}

service lmtp {
  unix_listener /var/spool/postfix/private/dovecot-lmtp {
    mode = 0666
    user = postfix
    group = mailuser
  }
}

service stats {
  unix_listener stats-reader {
    user = vmail
    group = mailuser
    mode = 0660
  }
  unix_listener stats-writer {
    user = vmail
    group = mailuser
    mode = 0660
  }
}

userdb {
  args = /usr/local/etc/dovecot/dovecot-ldap.conf
  driver = ldap
}

protocol imap {
  imap_logout_format = bytes=%i/%o
  mail_plugins = $mail_plugins imap_filter_sieve
}
protocol imaps {
  imap_logout_format = bytes=%i/%o
  mail_plugins = $mail_plugins imap_filter_sieve
}

protocol pop3 {
  pop3_uidl_format = %08Xu%08Xv
}
protocol pop3s {
  pop3_uidl_format = %08Xu%08Xv
}

protocol lmtp {
  postmaster_address = postmaster@mx.example.com
  mail_plugins = $mail_plugins sieve
}
protocol lda {
  auth_socket_path = /var/run/dovecot/auth-master
  hostname = mx.example.com
  mail_plugins = sieve
  postmaster_address = postmaster@mx.example.com
  sendmail_path = /usr/sbin/sendmail
}
次に、 dovecot-ldap.conf〔注:構築する OpenLDAP におけるスキーマ設定に合わせた設定に適宜変えてください。〕
hosts = localhost
sasl_bind = no
tls = no
ldap_version = 3
base = dc=%d,dc=control,dc=isp
deref = never
scope = subtree

user_attrs = homeDirectory=home=/var/mail/%$,uidNumber=uid,gidNumber=gid,mail=mail
user_filter = (&(cn=%u)(status=valid))

pass_attrs = uid=cn,userPassword=password,\
homeDirectory=userdb_home,uidNumber=userdb_uid,gidNumber=userdb_gid
pass_filter = (&(cn=%u)(status=valid))

default_pass_scheme = PLAIN
最後に、ssl_sni.conf〔注:実ホスト名と、収容する仮想ドメインのホスト名を設定・記述します。〕
最初の2行は、実ホスト名に対応するサーバ証明書の設定、local_name のブロックは、実ホスト名と収容する仮想ドメインのホスト名を記述します。
ここで、「収容する仮想ドメインのホスト名」は、メールサーバ利用者が設定する「受信メールサーバ名」にそのまま対応します。
ssl_cert = </usr/local/etc/letsencrypt/live/mx.example.com/fullchain.pem
ssl_key = </usr/local/etc/letsencrypt/live/mx.example.com/privkey.pem

local_name mx.example.com {
  ssl_cert = </usr/local/etc/letsencrypt/live/mx.example.com/fullchain.pem
  ssl_key = </usr/local/etc/letsencrypt/live/mx.example.com/privkey.pem
}

local_name mx.example2.net {
  ssl_cert = </usr/local/etc/letsencrypt/live/mx.example2.net/fullchain.pem
  ssl_key = </usr/local/etc/letsencrypt/live/mx.example2.net/privkey.pem
}
以上で、dovecot の設定は終わりですが、環境が整っていないため、まだ稼動させることが出来ません。
なので、次の項目へ進みます。

Pigeonhole のインストール

2022/12/22 に、最新版 0.5.20 がリリースされました。
Pigeonhole(ピゲオンホール?)は、本来は、受信メールの振り分けを行うものですが、ここでは spam判定・コンピュータウィルス判定されたメールの隔離を行う機能を実現するために使用します。
Pigeonhole では、振り分け条件を記述するスクリプト言語に「sieve(シーヴ)」というものを採用しています。投稿日現在、RFC 9042 で規定されており、技術規格的な標準化が試みられています。

標準仕様の sieve には、Courier maildrop にあるような外部プログラムを呼び出して、メッセージフィルタのような機能がありません。しかしながら、Pigeonhole には、Ver 0.2 で、拡張機能という形で該当機能が実装され、Ver 0.3で 「Extprograms Plugin」という名称に変わって機能強化され、Ver 0.4 以降は標準機能として提供されていることを知り、これで、maildrop に代わる手段が sieve スクリプトで実現できるようになります。

Pigeonhole をインストールする場合、FreeBSD13 では、下記のモジュールが事前に必要です。(但し、2022/12/24 現在)
これらの多くは、Ports や Package でインストールしても、管理上特段問題にはなりません。
また、先述の dovecot における必要モジュールと重複しているものが多いですが、確認の意味で敢えて掲載しており、再インストールの必要はありません。
 ・perl5-5.36.0 	 (Ports から カテゴリ:lang)
 ・autoconf-2.71	 (Ports から カテゴリ:devel)
 ・libltdl-2.4.7	 (Ports から カテゴリ:devel)
 ・libtool-2.4.7	 (Ports から カテゴリ:devel)
 ・pcre-8.45		 (Ports から カテゴリ:devel)
 ・pcre2-10.40		 (Ports から カテゴリ:devel)
 ・OpenLDAP 2.6.3 以上	 (これはソースコードからの構築を強く推奨)
 ・dovecot 2.3.19.1 以上(前項でソースコードからの構築)
Pigeonhole は、dovecot 本体への付加機能的な形でインストールされていきます。
下記の手順で、コンパイル・構築していきます:
# cp dovecot-2.3-pigeonhole-0.5.19.tar.gz /usr/local/src	 
# cd /usr/local/src	 
# tar xvzf dovecot-2.3-pigeonhole-0.5.19.tar.gz	 
# cd dovecot-2.3-pigeonhole-0.5.19	 
 	 
# setenv CPPFLAGS '-I/usr/local/include -I/usr/include'	(configure が上手くライブラリを探せないため)
# setenv LDFLAGS '-L/usr/local/lib -L/usr/lib'		(configure が上手くライブラリを探せないため)
# setenv LD_LIBRARY_PATH '/usr/local/lib /usr/lib' 	(コンパイルが上手くいかないため)
# ./configure --with-dovecot=/usr/local/lib/dovecot 	(dovecot の構築環境を参照して構築)
# make
# make install
上記は、pigeonhole 0.5.19 の場合で、バージョンが変わると、この部分も変わります。適宜解釈を。

このモジュールは、これでインストール完了です。

certbot を使って、Let's Encrypt のサーバ証明書を活用する

無償利用が可能なサーバ証明書を取得・管理するのに不可欠です。 現行のdovecot と postfix は SSL/TLS のSNI に対応しているのと、いわゆる「オレオレ証明書」を、昨今のアンチウィルスソフトは受け付けなくなってきているので「やむを得ず」といったところです。有効期間が90日と短いのがネックですが、自動更新を確実に行わせることで、このデメリットの補完を試みます。

certbot は、Python で記述されているため、FreeBSD13 では、下記のモジュールが事前に必要です。(但し、2022/12/24 現在)
Ports や Package でインストールしても、管理上特段問題にはなりません。
既にインストールされている場合、再インストールの必要はありません。
 ・python39-3.9.16 	 (Ports から カテゴリ:lang)
また、このモジュールは、FreeBSD においては、Ports からのインストールでも管理上の問題はありません。
以下の手順で、不足している依存モジュールを自動検出しつつ、インストールを実行します:
# cd /usr/ports/security/py-certbot
# make install
# make clean
# cd
# rehash
インストールしたら、早速、必要なサーバ証明書を取得します。
稼動サーバ上で Apache や nginx などの Webサーバが稼動している場合は、一旦停止します。

また、外部からのアクセスを制限している場合は、それらを一旦解除します。(Let's Encrypt の認証局サーバが非公開のため)
参考までに、当方の開発環境では、Apache を動作させ、加えてサーバ攻撃のためにアクセス制限を、サーバ本体で水際対策で行っているため、それを含めて以下の手順となります:
# /usr/local/etc/rc.d/apache2 stop
# /sbin/pfctl -d
# /usr/local/bin/certbot certonly --standalone --agree-tos -m user@example.com -d mx.example.jp
# /usr/local/bin/certbot certonly --standalone --agree-tos -m user@example.com -d mx.example2.net
−m の後ろに指定するメールアドレスは、有効期限が近づいてきたり、何かあった際の連絡先として登録するメールアドレスを指定します。了承なく他人のメールアドレスにしたり、存在しないメールアドレスを指定したりしないようにしましょう。

サーバ証明書の取得に成功すると、/usr/local/etc/letsencrypt/live 配下にサーバ証明書等が作成されているはずです。

取得が成功したら、環境を元に戻します。
# /sbin/pfctl -e
# /usr/local/etc/rc.d/apache2 start
肝心の自動更新ですが、週に一度実行する形で cron 設定するとよいでしょう。
まずは、定期的に実行する sh スクリプトを下記のように /usr/local/etc/letsencrypt_renew.sh に作成しました:
#!/bin/sh

/usr/local/etc/rc.d/apache2 stop
/sbin/pfctl -d
/usr/local/bin/certbot renew -m user@example.com
/sbin/pfctl -e
/usr/local/sbin/postfix reload
/usr/local/sbin/dovecot reload
/usr/local/etc/rc.d/apache2 start
この sh スプリプトは、cron にて root で実行させ、実行権限を与えるのを忘れないようにしてください。
/usr/local/bin/certbot renew で、有効期限が30日未満の証明書のみを更新します。

この際、証明書を生成した環境で更新をしようとするので、証明書を生成した時と同じ環境に仕立てる必要があります。

2022/12/24(土)メールサーバの中規模改修と基礎知識(2)~ SpamAssassin

SpamAssassin は、定番となっている spam 検出ソフトウェアで、サーバサイドでもクライアントサイドでも使用できる汎用性があります。2022/12/14(アナウンスは 2022/12/17) に Ver 4.0.0 がリリースされました。

具体的には、電子メールヘッダを含めた電子メールメッセージ全体を与え、各種のテストを行い、その結果を spam 度合値として、判定値を提示するような動作になります。

概念図(電子メールメッセージは、① → ② のルートで流れる)

                         ①         ①
spamc《チェック対象の電子メールメッセージ全体》===> socket通信 ===> spamd(SpamAssassin 本体)
   《チェック結果を含む電子メールメッセージ》<=== socket通信 <===
                          ②         ②
上図のように、サーバサイドでは、spamd をデーモン形式で稼働させておき、spamc というクライアントプログラムにて、受信した電子メールメッセージ全体を、spamd に垂れ流し、メッセージの電子メールヘッダ先頭にその判定値が付加されたものが与えたメッセージ全体と共に出力される挙動になります。

spamc から見ると、標準入力(stdin) に電子メールメッセージを流し込み、標準出力(stdout)に結果が出てくるような挙動になります。

SpamAssassinは、下図のように X-Spam-Checker-Version・X-Spam-Level・X-Spam-Status という3つのメールヘッダを処理結果として付加します。
20221224_mailserver_2022enhance.png

このうち、X-Spam-Status というメールヘッダ行が重要で、例示では、「score=-0.6」が spam 度合判定値、「required=4.0」が、spam と見做すしきい値で、この値は別途個別設定出来ます。
電子メール配送の最終段階で、このメールヘッダ部分を参照して、spam メール隔離か通常配送かを決定し、処理する仕組みになります。
「autolearn=ham」というのは、『spam ではないと自動的にパターン学習した』という意味で、spam として見做されると、ここは「autolearn=spam」という表示になります。
「autolearn_force=no」は、SpamAssassin の自動学習機能の如何に関わらず、強制的に「spam である」と学習させる判定値で、この例では「required=4.0」以上の場合に強制的に SpamAssassin に spam メールパターンの学習をさせる挙動になります。

インストール

インストール作業は、必ず root アカウントで行います。
また、SpamAssassin は、Perl 上で動作するため、事前に Perl 5.26 以降が必要です。
FreeBSD,NetBSD 他のUnix系OS、Linux系OSにおいては、Perl をパッケージでインストールしても問題はないです。
お勧めは、現時点(2022/12/24 現在)で最新バージョンの Perl 5.36。

FreeBSD だと、Ports で以下の手順でインストールするのが確実。(依存パッケージが先に自動的にインストールされる)
# cd /usr/ports/lang/perl5.36
# make install
# make clean

また、インストールに2つの方法がありますが、現状では後者の方法(方法その2)しかまともに出来ないみたいです。(当方の環境にて)

○ 方法その1(動作に必要な依存モジュールは自動的に探してインストールされる):
# perl -MCPAN -e shell
cpan> install Mail::SpamAssassin
この方法だと、test 段階で、'spamd が見つからない' とメッセージが出て test自体がなかなか終わらない。
3.4系ではこの問題は出ません。なので、次に示す方法が有効:

○ 方法その2
・まず SpamAssassin の公式ダウンロードページ(https://spamassassin.apache.org/downloads.cgi)から、
 Mail-SpamAssassin-4.0.0.tar.gz または、Mail-SpamAssassin-4.0.0.tar.bz2 をダウンロードし、インストール機器上にアップロードする。
・この方法の場合、CPAN で予め、下記モジュールをインストールしておいた方がよい:
# perl -MCPAN -e shell	 
 cpan> install NetAddr::IP	 
 cpan> install HTML::Parser	 
 cpan> install Digest::SHA1	 
 cpan> install IP::Country	 
 cpan> install IP::Country::DB_File	 
 cpan> install Net::Ident	 
 cpan> install IO::Socket::SSL	 
 cpan> install LWP::UserAgent	 
 cpan> install BSD::Resource	 
 cpan> install Mail::SPF	 
 cpan> install Mail::DKIM	 
 cpan> exit
・次に、下記コマンドを順に実行する。
# cp Mail-SpamAssassin-4.0.0.bz2 /usr/locall/src
# cd /usr/local/src
# tar xvzf Mail-SpamAssassin-4.0.0.bz2
# cd Mail-SpamAssassin-4.0.0
# perl Makefile.PL
# make
# make install 
インストール完了後、方法その1・方法その2の何れであっても、必ず以下のコマンドを実行しておきます。
# rehash
# sa-update --no-gpg
また、運用時は、SpamAssassin 自体が意図しているセキュリティポリシーに合わせるため、ここで専用のユーザを予めvipw や useradd コマンドで作っておきます。
vipw の場合は、編集画面で、下記の行を追加しておきます:
spamd::783:783::0:0:SpamAssassin Daemon:/nonexistent:/usr/sbin/nologin
vipw でユーザ追加した場合は、/etc/group ファイルに下記の行を追加しておきます:
spamd:*:783:
ユーザID、グループIDは、783 にこだわる必要はありませんが、当然のことながら、ユーザID・グループIDが他と重複しないように注意です。
更に vipw でユーザ追加した場合は、つまらないセキュリティホールを作らないために、下記コマンドも一応実行しておきます:
# passwd spamd
vipw,passwd,useradd コマンドは、どれも必ずroot ユーザ上で行います。

起動・停止スクリプトの設置(FreeBSD に特化している項目)

このスクリプトは一度作っておくと、バージョンアップの際に再作成の必要はありません。

○ spamd の起動スクリプト
/usr/local/etc/rc.d ディレクトリ配下に、sa-spamd のファイル名で下記内容を作成します。
1行目から6行目( KEYWORD までの行 ) は、一見するとコメント行そのものですが、意味を持っているため削除しないようにしてください。/usr/local/etc/rc.d ディレクトリ配下のスクリプトは、全てこの挙動になります。

また、実行権限を与えることを忘れないようにしてください:
#!/bin/sh

# PROVIDE: spamd
# REQUIRE: LOGIN
# BEFORE: mail
# KEYWORD: shutdown

#
# Add the following line to /etc/rc.conf to enable spamd:
#
#   spamd_enable="YES"
#
# You can pass flags to spamd with spamd_flags="..."
# To change the user that spamd runs as, use
#
#    spamd_flags="-u USER [-H /path/to/home... we suggest /var/spool/spamd]"
#
# To keep your user-config in a SQL database, use
#
#        spamd_flags="-Q"
#
# and remove -c (auto-create user preference files).
#

. /etc/rc.subr

name=spamd
rcvar=${name}_enable

extra_commands="reload"
load_rc_config $name

start_precmd="precmd"
restart_precmd="precmd"
stop_cmd="spamd_stop"
pidfile=${spamd_pidfile:-"/var/run/${name}/${name}.pid"}

# Set defaults
: ${spamd_enable:="NO"}
: ${spamd_flags:="-c -u spamd -r ${pidfile} -x --virtual-config-dir=/var/mail/%d/%l/spamassassin/spamd"}

command=/usr/local/bin/${name}
command_args="-d -r ${pidfile}"
command_interpreter="/usr/local/bin/perl"
required_dirs="/usr/local/share/spamassassin"

precmd()
{
        if [ ! -d /var/run/${name} ]; then
                mkdir -p /var/run/${name}
                chown spamd:spamd /var/run/${name}
        fi
}

spamd_stop()
{
  kill -INT `cat /var/run/spamd/spamd.pid`
  echo ' Stop sa-spamd 4.0.0 '
}
run_rc_command "$1"
あとは、簡単な設定作業が残っていますが、メールサーバ構築作業全体の最後のほうで行います。
なので、とりあえずこのフェーズは完了です。

2022/12/23(金)メールサーバの中規模改修と基礎知識(1)

背景や前提条件など

このシリーズは、8回に分けて記事を起こした時点における、今どきのメールサーバ運営管理上のインストール手順や参考情報を掲載します。Portsやバイナリパッケージに頼らず、ソースコードから自力で構築する手順から紹介しています。
『時代錯誤だ!』と嘲笑されようが、これを経験することが基礎知識を維持し、育むにはとても重要なのです。

OSは FreeBSD13 ですが、他のLinux 系OSにおいても参考になる部分が多いと思います。
また、ここでは OpenLDAP のインストールや設定を終えており、LDAP 検索にて、電子メールアドレスまたはSASLユーザ名を検索条件として与えると、
 ・SASL パスワード
 ・UID
 ・GID
 ・homeDirectory
 ・status〔有効にしている(valid)か、無効にしている(invalid)か〕
の情報が得られる仕組みが出来ていることを前提にしています。

実は、約2年前に計画していた改修ですが、
別の企業にて壊れたオンラインシステムの復旧作業・改修作業を事実上一手に引き受けた状態になり、
そちらを優先して、自社システムの細かな不具合がないがしろになっていた状態でした。

当初技術的に先行していた(と自負できる)メールサーバの構成が15年以上経過して色あせてきたことと、
昨今のOutlookやアンチウィルスソフトとの相性が悪くなっているため、中規模改修を行ってこの細かな不具合を出来るだけ解消しようと、やっとのことで実施に移しています。

一口に『メールサーバ』と言っても、知っている人は知っているのですが、構成は複雑です。
サーバ運営・管理的には難易度が高い部類になるかと思います。
20221223_mailserver_2022enhance.jpg


上図に(丁寧に作っている暇がないので)手書きで示した構成図を見ても、実に8種類のサーバサイドソフトウェアを使って1つのメールサーバを実現しています。しかも、これは基本的構成に過ぎません。

実際は、このほかにも動作させるために、Perl,ruby,Python といったスクリプト言語や、rust などの新しい言語のライブラリ、各種の補助的ツールを必要とし、メーリングリストの実現なんかは更に、上図で図示していない別のサーバソフトウェアを必要とします。
また、SSL/TLS といった暗号化通信のためには、サーバ証明書の取得・管理だけではなく、OpenSSL,GnuTLS といった暗号化ライブラリが別途必須になります。

こういう構成図(設計図?)を描ける若手エンジニアを昨今では見ませんね。
「クラウド」「クラウド」と、もてはやすおかげで、自力でこのようなものを構築する機会を奪っているから。
ハッキリ言って、この状況では日本のICT技術水準は、自ら周回遅れの状況を作ってしまっています。

ということで、技術継承的な危機感を感じていますが、憂いでも何も変わらないので、せめて構成例の一例として参考にして欲しいということで、自分メモも兼ねて記録に残しています。(つか、こっちがメインかも)

抑えておきたいポート番号とSSL/TLS の対応

皆さまが使う、電子メール送受信ソフトウェア(Outlook,Thunderbird など)にて、サーバの設定におけるポート番号と暗号化通信形式の組み合わせは、一般的に下記の表のようになります。
時々「メール送受信が上手く出来ない」という問合わせ受けますが、単純ではないものの、下記の対応が滅茶苦茶になっている設定が案外散見されます。参考にどうぞ。
表1 送信側
ポート番号非暗号STARTTLSSSL/TLS説明
25(SMTP)×現在はメールサーバ間の通信に使用。
昨今はOP25 対策で、メール送信元で使えない場合が殆ど。
587(submission)×メール送信元にて、メール発信の際に使う。
OP25環境では、メールサーバ間の通信にも使用。
465(SMTPS)××メール送信元にて、暗号通信を行う際に使用する。
有名どころでは OCN なんかがこれを標準にしているが、
おかげで従来の制御機器が使えなくなるケースも実在する。
表2 受信側
ポート番号非暗号STARTTLSSSL/TLS説明
110(POP3)×メール受信者が、メールサーバから電子メールを取り寄せる時に使用。
143(IMAP4)×POP3 と役割は同じだが、メールサーバ上にメールを一定期間残す挙動が標準。
993(IMAP4S)××IMAP4 を暗号化通信専用にしたようなもの。その他は IMAP4 と同じ。
995(POP3S)××POP3 を暗号化通信専用したようなもの。その他は POP3 と同じ。
有名どころでは OCN なんかがこれを標準にしているが、
おかげで従来の制御機器が使えなくなるケースも実在する。
STARTTLS というのは、一般的に「暗号通信するぞ」という宣言を接続元で行うという手順を踏んで暗号化通信を行う仕組みを指します。
SSL/TLS は、SSL(Secure Sockets Layer) の後継規格が TLS(Transport Layer Security) というもので、SSL は既に旧規格です。ですが、役割は同じなので、同列に語られます。
SSL は当初、Netscape社が開発したものですが、IETF というインターネット技術の国際標準化組織に引き継ぐ際に名称が変わりました。

と、いうことで次からメールサーバ構築の流れを自分メモ的に記していきます。

2022/06/11(土)実験・開発用サーバにSSDを入れてみた

2022/06/11 6:59 サーバ運営・管理
書き込み回数に事実上の制限があるため、サーバ用途にはSSDとか、まともに使えないと思ってはいますが、
プログラム・ライブラリは、読み込みが圧倒的なので、OSとアプリケーションだけをSSDに入れるようにすることで、実用に供するかも? と思い、試験的に採用してみました。

20220611.JPG


「KIOXIA」(キオクシア)というのは、東芝メモリ株式会社の現在の企業名のようです。
つまり、東芝の半導体メモリ部門が社名変更したようなものですね。
東芝の半導体メモリ部門以外の半導体製品群は「東芝デバイス&ストレ―ジ株式会社」となっており、こちらは、従来通り「東芝」を名乗っているようです。

税込み 5,000円未満で入手出来る安物ですが、評判は悪くないので、どの程度の期間使用できるかの確認といった感じで試用中です。

書き込みが頻繁に起きる /var 配下や、ユーザディレクトリ、SWAP をSSDではなく、通常のHDDにパーティションを割り振って、書き込みを最小限に抑えるようにしています。

当然、zfs ファイルシステムは使っていません。ufs なファイルシステムで構成しています。

2022/06/11(土)FreeBSD 13.1R + Perl 5.36.0 の環境で adiaryの更新時エラー

暫定的な場当たり対処なので、とりあえず記事の形で・・・。

提起の通り、FreeBSD 13.1R 上で Perl 5.36.0 の環境で、adiary 3.40c を稼働させて、
おもむろに記事作成や更新を行うと、
[AutoLoader] Can't modify undef operator in scalar assignment at lib/SatsukiApp/adiary_4.pm line 925, near "undef
}"
Compilation failed in require at lib/Satsuki/AutoLoader.pm line 42.
といったエラーが出るようになりました。FreeBSD 13.0R + Perl 5.32 の環境までは発生しない。
OSもPerlも同時に更新したため、
Perl のバージョンアップで挙動が変わったのか、OSで何かあるのかが判らない状態です。

但し、更新そのものは出来ている模様。

これは、lib/SatsukiApp/adiary_4.pm の 913行目~
sub void_plugin_images {
        my $self = shift;
        my $h    = shift;
        my $form = shift;
        foreach(keys(%$form)) {
                if ($_ !~ /^(\w+)_void$/) { next; }
                if (! $form->{$_}) { next; }
                my $n = $1;
                $h->{$n} = undef
                $h->{"${n}_w"} = undef
                $h->{"${n}_h"} = undef
        }
}
と、なっているところを
sub void_plugin_images {
        my $self = shift;
        my $h    = shift;
        my $form = shift;
        foreach(keys(%$form)) {
                if ($_ !~ /^(\w+)_void$/) { next; }
                if (! $form->{$_}) { next; }
                my $n = $1;
                $h->{$n} = undef ;
                $h->{"${n}_w"} = undef ;
                $h->{"${n}_h"} = undef ;
        }
}
とすると、回避出来ました。これが正しいのかどうかは判りません。

2022/04/02(土)フィッシングメール・アホメール(?)その4

2022/04/02 4:16 はんかくさい
今回は、雰囲気をご理解いただくために、画像で掲載します:
20220402.png


見るからに日本で使われるフォントではないし、Amazon のメールアドレスではない。
しかも「このメールは次のアドレス宛に送信されました:」の部分で表示するメールアドレスは、全く身覚えが無い他人のメールアドレス。
これは、フィッシングメールであることが、すぐ判りますね。こんなのが時折すり抜けて来るんです。。
だからといって、「メールアドレスが違う!」とか、*絶対に*返信してはいけません。
↑ これ重要です。返信しただけで、更なる数のフィッシングメールが送りつけられる可能性の方が高くなります。
  「返信しないでください」と書いてあるが、実際は返信出来てしまうのがフィッシングメールのアドレスなのです。

当然、その度に spam メールであることを、メールサーバに教え込む作業をしていますが、ウィルスのように変異するので、効果が現れるにはちょっと数をこなす必要があるかもです。

2022/04/02(土)フィッシングメール・アホメール(?)その3

2022/04/02 3:55 はんかくさい
Amazon を騙るフィッシングメールは昔から多いです。
以前は、それでも本物か偽者か識別はなんとか出来たんですが、これはちょっと難しい・・・

差出人:Amazon <no-reply@amazon.co.jp>
件名 :Amazon.co.jp にご登録のアカウント(名前、パスワード、その他個人情報)
Amazonアカウントのエラーまたは不完全なプロファイルにより、システムは残念ながら高リスクのアカウントに設定されており、アカウントと対応する機能の権限が部分的にロックされています。
Amazonアカウントのロック解除にご協力ください。以下のリンクを使用して、Amazon Webサイトにアクセスし、情報を更新してください。


支払い情報を更新する
登録
※ 24時間経過してもこのメッセージに返信しない場合、アカウントのステータスは1週間後に放棄され、完全に削除されるように設定されます。


お客様のアカウントのセキュリティを強化するため、2段階認証を有効にすることをお勧めします。 Amazon.co.jp では、個人情報を細心の注意を払って慎重に取り扱い、利用および共有させていただいています。本プライバシー規約(以下「本規約」といいます)は、本規約を参照するAmazonのウェブサイト、端末、製品、サービス、オンラインストア及び実店舗(以下「Amazonサービス」といいます。)を通じたAmazon(Amazon.com, Inc.を含め、Amazon.com Services LLC及びその国内外の関連会社をいいます。)による個人情報の取得及び取扱いに関する方針を説明するものです。Amazonサービスをご利用いただいた場合、本規約に同意していただいたものとみなされます。
こんな場合は、電子メールの生ソースを見て判断するのが確実だが、知識が要ります:
(悪用されないように、一部本物のメールアドレス部分は変更しています)
From - Fri Apr 1 04:47:30 2022
X-Account-Key: account1
X-UIDL: 000239e94a73fe99
X-Mozilla-Status: 0001
X-Mozilla-Status2: 00000000
X-Mozilla-Keys:
Return-Path: <arnazon-update@zimmed.shop>
X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on mx1.example.com
X-Spam-Level: ***
X-Spam-Status: No, score=3.3 required=4.0 tests=AMAZON_IMG_NOT_RCVD_AMZN,
BAYES_00,DKIM_ADSP_DISCARD,HEADER_FROM_DIFFERENT_DOMAINS,HTML_MESSAGE,
SPF_HELO_PASS,SPF_PASS,URIBL_DBL_PHISH,URIBL_PH_SURBL autolearn=no
autolearn_force=no version=3.4.6
Delivered-To: noname@example.com
Received: from zimmed.shop (zimmed.shop [113.31.112.72])
by pmx1.admin-plus.net (Postfix) with ESMTP id 08A0528F2AA6
for <noname@example.com>; Fri, 1 Apr 2022 04:46:55 +0900 (JST)
Received: from zc (unknown [43.249.207.181])
by zimmed.shop (Postfix) with ESMTPA id 7AAB632002B9
for <noname@example.com>; Fri, 1 Apr 2022 03:46:45 +0800 (CST)
DKIM-Filter: OpenDKIM Filter v2.11.0 zimmed.shop 7AAB632002B9
Sender: arnazon-update@zimmed.shop
Message-ID: <20220401034714546202@zimmed.shop>
From: "Amazon" <no-reply@amazon.co.jp>
To: <noname@example.com>
Subject: =?utf-8?B?QW1hem9uLmNvLmpwIOOBq+OBlOeZu+mMsuOBruOCouOCqw==?=
=?utf-8?B?44Km44Oz44OI77yI5ZCN5YmN44CB44OR44K544Ov44O844OJ44CB44Gd44Gu5LuW5YCL5Lq65oOF5aCx?=
=?utf-8?B?77yJIA==?=
Date: Fri, 1 Apr 2022 03:47:01 +0800
MIME-Version: 1.0
Content-Type: multipart/alternative;
boundary="----=_NextPart_000_0209_01EC2A56.1A560F00"
X-mailer: Hyajcpyad 2
X-Virus-Scanned: clamav-milter 0.104.1 at mx1.basekernel.ne.jp
X-Virus-Status: Clean
X-Antivirus: Avast (VPS 220331-10, 2022/3/31), Inbound message
X-Antivirus-Status: Clean
上記で、赤字の部分が amazon.co.jp でないため、詐称の可能性が高い。
実は、電子メールは、構造的に封書なので、ちょっと細工すると差し出し元を詐称出来てしまうのです。

封書は「封筒」の中に「信書」を入れますね。電子メールもこれと全く同じ構造なのです。
なので From が2つあるのです。
「封筒」は「エンベロープ」と言います。電子メールの世界でも「エンベロープ」があります。
メールサーバは、発信については「エンベローブ」の内容だけを見て、配送します。
一方で、普段お使いの電子メール送受信ソフトウェア(一般的にMUAと称す)は、受信処理の際、エンベローブではなく、本文の初めの方にくっついてくる情報(ヘッダと称す)を参照して表示します。
(そして、エンベローブの大部分は表示されない)

つまり、エンベローブの From は配送さえ出来ればなんでもよく、故に本文ヘッダの From: は、詐称出来てしまうのです。
ですが、本文ヘッダの一部はメールサーバが付加していくので、基本的に中継サーバや受信端で魔改造でもしない限り、メールサーバが付加する項目の詐称は困難です。ここに辛うじて判断材料が残っている形です。

2022/04/02(土)フィッシングメール・アホメール(?)その2

2022/04/02 3:17 はんかくさい
差出人:ETC利用照会サービス <etc-meisai@mmananes.com>
件名 :【ETCサービスは】【通知書】番号:E06283625089
ETCサービスは無効になりました。
当社からクレジットカード会社に問い合わせたところ、
弊社にご登録されているご情報と、カード会社が保有しております情報が相違しており
ご注文者様ご本人名義のカードであることの確認が取れませんでした。

弊社では不正利用防止の観点から、相違が認められご本人様名義のカードであることの確認が取れないまま
カード払いでご注文の継続を行うことができません。

→ご認証はこちらから

ご不便とご心配をおかけしまして誠に申し訳ございませんが、
何とぞご理解賜りたくお願い申しあげます。

※このメールは送信専用です。
 このアドレスに送信いただいても返信いたしかねますので、あらかじめご了承願います。
※本メールに心当たりがない場合は、速やかに削除お願いいたします。

なお、ご不明な点につきましては、お手数ですが、
ETC利用照会サービス事務局にお問い合わせください。

■ETC利用照会サービス事務局
 年中無休 9:00~18:00
 ナビダイヤル 0570-001069
 (ナビダイヤルがご利用いただけないお客さま 045-477-1262)
電話番号は本物。ドメインは見るからに違っている。 .cn な場合もある。
そして、本物の「ETC利用照会サービス事務局」から、注意喚起がなされています。
https://www.etc-meisai.jp/caution/caution_phishing.html (ページリンクは、2022/04/02 現在)

2022/04/02(土)フィッシングメール・アホメール(?)その1

2022/04/02 3:03 はんかくさい
弊社のメールサーバには、メールアドレス毎に個別機能する spam メールフィルタなるものを実装しているが、
最近、フィルタをすり抜けてくる spam な電子メールが散見され、中には本物と見分けがつきにくいものもある。

また、時々アホなメールや新しい型の変なメールなんかも来るようになったので、
注意喚起も兼ねて、内容を晒していこうと思います。このシリーズで紹介するのと同じような電子メールには、
決して対応しないようにしてください。

また、安全対策のため、HTML 形式ではなく、テキスト形式で表示します。予めご了承ください。

差出人:MyJCOM <JCOM-net-account@xaepebk.cn>
件名 :【J:COMカード】重要なお知らせ
32px
ご請求書が未払いの状態です

お支払い期日を過ぎています。

お支払いが遅れると、サービス停止の可能性。お早めにお支払いください。

支払い方法は無効だ

現在、お支払い方法が無効のため、サービスを一時停止する可能性がございます。チェックしてください

お支払い期限

2022年04月2日

支払い方法を追加する <https://www.jcom.nzrtjvc.cn/>


アプリをお持ちでない方は、
こちら <https://www.jcom.nzrtjvc.cn/>からお支払いください。

help-icon
お困りの方はヘルプ <https://www.jcom.nzrtjvc.cn/>をご確認ください

※このメールはお知らせ専用のアドレスより配信しております。このメールに直接返信し
てのお問い合わせにはご対応いたしかねますのでご了承ください。

© J:COM Inc.
.cn は、中華国のドメイン。この手の半分は、メールアドレスの最後が .cn だったりします。
事業する側にとっては安全対策上、常識の範疇ですが、ご存じでなかった方は、事業者の負担軽減ということで、無視して削除するなどの対応をしていただけると有難いです。

2022/03/31(木)postgresql にて、任意の select 文を csv 出力する

自分メモその2。ざっくりと、こんな感じ。
# psql -h サーバFQDN DB名 -U ユーザ名 -c "《任意のselect 文》;" -A -F , > output.csv
サーバFQDN は、ホスト名のほか、IPアドレスでも可能です。自ホストの場合は localhost と指定します。
DB名・ユーザ名は、そのままですね。
任意のselect文は、全体をダブルクォーテーションで括ります。終端には必ずセミコロン「;」を付けます。
select 文中に括弧やダブルクォーテーションが入る場合、エスケープが必要かもしれません。

 -A は、「桁揃えなしのテーブル出力」で、これを指定しないと、CSV 出力の際に余計なスペース等が入ってしまいます。
 -F は、「桁揃えなし出力時のフィールド区切り文字」で、デフォルトの区切り文字は "|" なので、CSV 出力の場合は、必ずカンマ「,」を指定します。

あとは、リダイレクトで出力ファイル名の指定。
文字コードは、DBの文字コードが適用されます。