能書き
私的サーバー構築日誌:仕切り直しからの自宅サーバー構築の続きです。
今、メールサーバー(MTA)を立てるのは大変なんですね。迷惑メール対策でガッチガチに固められて、気を使わなきゃいけない点が増えてます。技術的にかなり面倒な感じ。そしてGoogleとかの世界的大手メールサービスがそれを強要してます。やって出来ない事はないけれど、とても大変です。
そんな面倒臭いだけのレガシーなメールサーバーを今立てようとする理由は、GitLabです。この後でGitLabサーバーを立てたいと考えていますが、そこでメールサーバーとの連携が必要になります。これが今のモチベーションになっています。
以前はDovecotを3回に分けて設定しましたが、今回は一気に全部やります。
なお、今回もLXDコンテナに設定します。その意味ですが。
- 受信メールをコンテナ内に蓄積できます。Dockerコンテナではコンテナ内へのデータ蓄積は不向きです。ホスト側のディレクトリに保存させる手段もありますけども、LXDコンテナならそのままコンテナ内に蓄積できます。
- 蓄積したメールのバックアップコピーを作ろうとした場合、LXDコンテナ内にメールがあれば、コンテナをエクスポートする事でDovecotの設定ごとバックアップできます。
- 将来はDRBDも入れて、リアルタイムでミラーリングして「絶対に喪失しないメールシステム」を実現したい。こういった複数ソフトのインストールにはDockerは不向きでしょう。
そういう訳で、常時起動のLXDコンテナを立てて、その中にMDAとしてDovecotをインストールします。MTAは、志を低くした形で次回立てます。
目標
- LXDコンテナにSSSDを設定してLDAPと連携
- そのコンテナにDovecotをインストールしてIMAPSとLMTPを設定
- cloud-initを利用して自動化可能な部分は自動化する
POP3は使いません。どうせ私専用のメールサーバーですので、私自身が使わない以上、選択肢として用意しておく必要もありません。
そして IMAP over SSL/TLS、通称 IMAPS にします。ただのIMAPは使えないように潰しておきます。
参考文献
Dovecot関連。
SSSDについて。
証明書関係。
LXDコンテナの初期化処理を自動化するcloud-initについて。
LXDコンテナの用意
Dovecot(及びメール蓄積)の為のLXDコンテナを作成します。
コンテナ名とそのIPアドレス、ポート番号などは何度か参照するので、環境変数に設定しておきます。異なる設定を使いたい場合は、ここを修正して下さい。
CONTAINER=dovecot1
IPADDRESS=192.168.0.201
IMAPS_PORT=993
LMTP_PORT=24
HOST_IPADDR=172.16.1.2
LXDコンテナを初期設定します。今回は/etc
のSubversion管理は設定しません。煩雑なだけで役に立ちそうにないので。
lxc init images:ubuntu/jammy/cloud $CONTAINER --device eth0,ipv4.address=$IPADDRESS
lxc config set $CONTAINER cloud-init.user-data="$(cat <<___
#cloud-config
timezone: Asia/Tokyo
locale: ja_JP.utf8
package_upgrade: true
packages:
- sssd-ldap
- sssd-tools
- dovecot-lmtpd
- dovecot-imapd
___
)"
lxc start $CONTAINER
lxc exec $CONTAINER -- cloud-init status --wait
証明書の用意
以前用意したオレオレ認証局と証明書のパスは下記の通りです。
認証局:
- 秘密鍵
/home/cert/demoCA/pki/private/ca.key
- 公開鍵
/home/cert/demoCA/pki/ca.crt
サーバーマシンprimary.homeの証明書:
- 秘密鍵
/home/cert/demoCA/pki/private/primary.home.key
- 公開鍵
/home/cert/demoCA/pki/issued/primary.home.crt
Dovecot
認証局と証明書
Dovecot-IMAPで必要な証明書は、書き方が他とはちょっと違うようです。証明書と認証局の鍵を結合したpemファイルを作成します。
mkdir /tmp/dovecotIMAP
cd /tmp/dovecotIMAP
sudo -u cert cat /home/cert/demoCA/pki/private/primary.home.key >dovecot_primary.pem
sudo -u cert openssl x509 -outform pem -in /home/cert/demoCA/pki/issued/primary.home.crt >>dovecot_primary.pem
sudo -u cert cat /home/cert/demoCA/pki/ca.crt >>dovecot_primary.pem
このpemファイルをLXDコンテナ内の所定の場所に置きます。
lxc file push /tmp/dovecotIMAP/dovecot_primary.pem $CONTAINER/etc/dovecot/private/dovecot_primary.pem
終わったら、ホスト側のファイルは不要なので削除します。
cd ..
rm -r dovecotIMAP
Dovecotの設定
LMTPとIMAPSを一緒に設定します。
まずは作業場所を確保。
mkdir /tmp/dovecotPatch
cd /tmp/dovecotPatch
次にパッチを用意します。
cat >dovecot.patch <<___
Index: /etc/dovecot/conf.d/10-auth.conf
===================================================================
--- /etc/dovecot/conf.d/10-auth.conf
+++ /etc/dovecot/conf.d/10-auth.conf
@@ -48,7 +48,7 @@
# the standard variables here, eg. %Lu would lowercase the username, %n would
# drop away the domain if it was given, or "%n-AT-%d" would change the '@' into
# "-AT-". This translation is done after auth_username_translation changes.
-#auth_username_format = %Lu
+auth_username_format = %Ln
# If you want to allow master users to log in by specifying the master
# username within the normal username string (ie. not using SASL mechanism's
Index: /etc/dovecot/conf.d/10-logging.conf
===================================================================
--- /etc/dovecot/conf.d/10-logging.conf
+++ /etc/dovecot/conf.d/10-logging.conf
@@ -4,7 +4,7 @@
# Log file to use for error messages. "syslog" logs to syslog,
# /dev/stderr logs to stderr.
-#log_path = syslog
+log_path = syslog
# Log file to use for informational messages. Defaults to log_path.
#info_log_path =
@@ -14,7 +14,7 @@
# Syslog facility to use if you're logging to syslog. Usually if you don't
# want to use "mail", you'll use local0..local7. Also other standard
# facilities are supported.
-#syslog_facility = mail
+syslog_facility = mail
##
## Logging verbosity and debugging.
Index: /etc/dovecot/conf.d/10-mail.conf
===================================================================
--- /etc/dovecot/conf.d/10-mail.conf
+++ /etc/dovecot/conf.d/10-mail.conf
@@ -27,7 +27,7 @@
#
# <doc/wiki/MailLocation.txt>
#
-mail_location = mbox:~/mail:INBOX=/var/mail/%u
+mail_location = maildir:~/Maildir
# If you need to set multiple mailbox locations or want to change default
# namespace settings, you can do it by defining namespace sections.
Index: /etc/dovecot/conf.d/10-master.conf
===================================================================
--- /etc/dovecot/conf.d/10-master.conf (revision 3)
+++ /etc/dovecot/conf.d/10-master.conf (working copy)
@@ -52,16 +52,16 @@
}
service lmtp {
- unix_listener lmtp {
+ #unix_listener lmtp {
#mode = 0666
- }
+ #}
# Create inet listener only if you can't use the above UNIX socket
- #inet_listener lmtp {
+ inet_listener lmtp {
# Avoid making LMTP visible for the entire internet
#address =
- #port =
- #}
+ port = $LMTP_PORT
+ }
}
service imap {
Index: /etc/dovecot/conf.d/10-ssl.conf
===================================================================
--- /etc/dovecot/conf.d/10-ssl.conf
+++ /etc/dovecot/conf.d/10-ssl.conf
@@ -9,8 +9,8 @@
# dropping root privileges, so keep the key file unreadable by anyone but
# root. Included doc/mkcert.sh can be used to easily generate self-signed
# certificate, just make sure to update the domains in dovecot-openssl.cnf
-ssl_cert = </etc/dovecot/private/dovecot.pem
-ssl_key = </etc/dovecot/private/dovecot.key
+ssl_cert = </etc/dovecot/private/dovecot_primary.pem
+ssl_key = </etc/dovecot/private/dovecot_primary.pem
# If key file is password protected, give the password here. Alternatively
# give it when starting dovecot with -p parameter. Since this file is often
___
必要な設定ファイルを取り出します。
mkdir etc
lxc file pull $CONTAINER/etc/dovecot/conf.d/{10-auth.conf,10-logging.conf,10-mail.conf,10-master.conf,10-ssl.conf} etc
そうしたらpatch
コマンドで一気に適用!
タブ文字の関係などでエラーが発生する可能性があるので、--ignore-whitespace
オプションを付けて実行します。
patch --ignore-whitespace -d etc <dovecot.patch
エラーが表示されなければ成功です。
$ patch --ignore-whitespace -d etc <dovecot.patch
patching file 10-auth.conf
patching file 10-logging.conf
patching file 10-mail.conf
patching file 10-master.conf
patching file 10-ssl.conf
パッチを当てた設定ファイルをコンテナに戻します。
lxc file push etc/* $CONTAINER/etc/dovecot/conf.d/
Dovecotに設定を読み込ませます。
lxc exec $CONTAINER systemctl reload dovecot
不要になったファイル達は削除しましょう。
cd ..
rm -r dovecotPatch
LXDコンテナのネットワークの設定
現在のネットワークの状態を確認してみましょう。
lxc network list-leases lxdbr0
今の状態ならこんな風に表示されるでしょう。コンテナを既に色々弄っていたら、違う表示になるかも知れません。
$ lxc network list-leases lxdbr0
+-----------+-------------------+---------------+---------+
| HOSTNAME | MAC ADDRESS | IP ADDRESS | TYPE |
+-----------+-------------------+---------------+---------+
| dovecot1 | 00:16:3e:fb:bf:ed | 192.168.0.201 | STATIC |
+-----------+-------------------+---------------+---------+
| lxdbr0.gw | | 192.168.0.1 | GATEWAY |
+-----------+-------------------+---------------+---------+
コンテナのNATを設定します。
lxc network forward create lxdbr0 $HOST_IPADDR
lxc network forward port add lxdbr0 $HOST_IPADDR tcp $LMTP_PORT $IPADDRESS $LMTP_PORT
lxc network forward port add lxdbr0 $HOST_IPADDR tcp $IMAPS_PORT $IPADDRESS $IMAPS_PORT
SSSD
認証局
まずは認証局の公開鍵を用意します。
sudo -u cert cp -p /home/cert/demoCA/pki/ca.crt /tmp/demoCA.crt
sudo chown $USER: /tmp/demoCA.crt
chmod 644 /tmp/demoCA.crt
lxc exec $CONTAINER mkdir /usr/share/ca-certificates/demoCA
lxc file push /tmp/demoCA.crt $CONTAINER/usr/share/ca-certificates/demoCA/demoCA.crt
rm /tmp/demoCA.crt
次に認証局を信頼します。
lxc shell $CONTAINER
echo demoCA/demoCA.crt >>/etc/ca-certificates.conf
update-ca-certificates
SSSDの設定
引き続きコンテナ内で操作します。
cat <<___ >/etc/sssd/sssd.conf
[sssd]
config_file_version = 2
domains = home
[domain/home]
id_provider = ldap
auth_provider = ldap
ldap_uri = ldaps://primary.home
cache_credentials = True
ldap_search_base = dc=home
ldap_default_bind_dn = cn=readonly,dc=home
___
chmod 600 /etc/sssd/sssd.conf
sss_obfuscate -d home
ここで要求に従いパスワードを入力します。
パスワードを入力したら、SSSDサービスを開始します。
systemctl start sssd
ホームディレクトリの自動作成を有効にします。
pam-auth-update --enable mkhomedir
これでコンテナ内の操作は終了です。
exit
動作確認1・未ログインユーザーにメールが届いた場合
ホームディレクトリが無いユーザーにメールが届いたらどうなるか、ですね。Internal error が発生します。実験してみましょう。
以前の設定の通りならば、LDAPにはユーザー名taro
が登録されています。そして今の段階ではまだログインしていません。
LMTPコマンドを手で入力して、反応を1つずつ確認してみます。
nc -C $HOST_IPADDR $LMTP_PORT
lhlo primary.home
mail from:<test@sender.home>
rcpt to:<taro@home>
data
From: test@sender.home
To: $USERNAME@primary.home
Subject: test
hello, world
.
下記のような結果になります。
$ nc -C $HOST_IPADDR $LMTP_PORT
220 dovecot1 Dovecot (Ubuntu) ready.
lhlo primary.home
250-dovecot1
250-8BITMIME
250-CHUNKING
250-ENHANCEDSTATUSCODES
250-PIPELINING
250 STARTTLS
mail from:<test@sender.home>
250 2.1.0 OK
rcpt to:<taro@home>
250 2.1.5 OK
data
From: test@sender.home
To354 OK
: $USERNAME@primary.home
Subject: test
hello, world
.
451 4.2.0 <taro@home> Internal error occurred. Refer to server log for more information. [2023-11-15 13:23:58]
つまり、メール本文の入力が終わった時点で Internal error ですね。
この時のエラーログを見てみましょう。
lxc exec $CONTAINER cat /var/log/mail.err
下記のような感じで、/home/taro/Maildir
ディレクトリを作ろうとして権限不足で失敗しています。うむ、想定内ですな。
$ lxc exec $CONTAINER cat /var/log/mail.err
Nov 15 04:23:58 dovecot1 dovecot: lmtp(taro)<8235><tsplGMBHVGUrIAAA9sUnBg>: Error: lmtp-server: conn 172.16.1.2:60146 [1]: rcpt taro@home: mkdir(/home/taro/Maildir) failed: Permission denied (euid=10000(taro) egid=10000(taro) missing +w perm: /home, dir owned by 0:0 mode=0755)
Nov 15 04:23:58 dovecot1 dovecot: lmtp(taro)<8235><tsplGMBHVGUrIAAA9sUnBg>: Error: lmtp-server: conn 172.16.1.2:60146 [1]: rcpt taro@home: mkdir(/home/taro/Maildir) failed: Permission denied (euid=10000(taro) egid=10000(taro) missing +w perm: /home, dir owned by 0:0 mode=0755)
Nov 15 04:23:58 dovecot1 dovecot: lmtp(taro)<8235><tsplGMBHVGUrIAAA9sUnBg>: Error: lmtp-server: conn 172.16.1.2:60146 [1]: rcpt taro@home: Mailbox INBOX: Failed to autocreate mailbox: Internal error occurred. Refer to server log for more information. [2023-11-15 13:23:58]
LDAPユーザーでログイン
上述のエラーを踏まえ、コンテナのコンソールに接続して一度ログインします。ログインする事によってホームディレクトリも作られます。
USERNAME=taro
下記のコマンドならばtaro
のパスワード入力は省略できます。
lxc exec $CONTAINER -- login -f $USERNAME
特にする事も無いので、確認できたらexitしましょう。
残念ながらloginコマンドはコンソールからの入出力しか受け付けないようです。exitは手で入力しなければなりません。
exit
動作確認2・ログイン済ユーザーにメールお届け
LDAPユーザーtaro
のホームディレクトリが作成されたら、dovecotでメール配送できる筈
です。
taro
宛にメールを送信します。成功する事を期待して、LMTPコマンドを一気に流します。
nc -C $HOST_IPADDR $LMTP_PORT <<___
lhlo primary.home
mail from:<test@sender.home>
rcpt to:<$USERNAME@home>
data
From: test@sender.home
To: $USERNAME@home
Subject: test
hello, world
.
quit
___
メールが正しく届いていれば、LDAPユーザーtaro
に対してIMAPSで確認できる筈です。
openssl s_client -connect $HOST_IPADDR:$IMAPS_PORT
1 login taro Ma9H%6jg
2 list "" *
3 select INBOX
4 fetch 1 body[]
5 logout
動作確認3・存在しないユーザーにメールが届いた場合
登録されていないユーザーとして、例えばhanako
宛のメールが届いた場合の挙動です。
今回もまたLMTPコマンドを手で入力して、反応を1つずつ確認してみます。
nc -C $HOST_IPADDR $LMTP_PORT
lhlo primary.home
mail from:<test@sender.home>
rcpt to:<hanako@home>
今回はrcpt to
の段階でエラーが発生します。
$ nc -C $HOST_IPADDR $LMTP_PORT
220 dovecot1 Dovecot (Ubuntu) ready.
lhlo primary.home
250-dovecot1
250-8BITMIME
250-CHUNKING
250-ENHANCEDSTATUSCODES
250-PIPELINING
250 STARTTLS
mail from:<test@sender.home>
250 2.1.0 OK
rcpt to:<hanako@home>
550 5.1.1 <hanako@home> User doesn't exist: hanako@home
仕舞い
メールサーバーの内MDAとしてDovecotを立て、SSSDと連携させました。そして少々詳しく動作確認しました。