= CyrusIMAPdとの連携運用 = == 前提条件 == {{attachment:mail-server.svg||align="right",width=33%}} * 動作検証環境 * OS: FreeBSD(12.2/12.3/13.0) * MTA: Sendmail(8.16.1/8.17.1) * メールボックス: CyrusIMAPd(3.2.6/3.2.7/3.2.8) * 認証フレームワーク: CyrusSASL(2.1.27) * 参考設定例として、事前に [[FreeBSD/FreeBSD13-install|OSのインストール]] および [[FreeBSD/FreeBSD13-initial-setup|環境構築]] が済ませてあること。 * CyrusSASLの以下の仕様上の制限からSASLAUTHDを使用しない。 * SASLAUTHDは平文パスワード(LOGINおよびAUTH PLAIN)でしか使えない。 * 暗号パスワード(SCRAM、DIGEST-MD5、CRAM-MD5等)では、auxpropしか参照させることができない(`pwcheck_method` 設定の無視)。 * 以上から認証は全て、auxprop(SASLDB)を直接参照するものとする。 * またSASLDBの参照にあたり、SendmailおよびCyrus IMAPd双方に権限上のミスマッチは存在していない。 * よってSASLAUTHDの導入の動機の一つである、権限分離にともなう、権限ミスマッチを解消する必要性が無い。 * `ports/mail/sendmail` をインストールするが現時点(2021年12月11日)でいくらか不備がある。 * SSL回りの設定方法がいびつなので、これも修正していきたい。 * 現在のSendmailは、SSL証明書の指定方法が極めてよろしくない(説明すると長くなるが、事実上運用できない)。 * ECC暗号/鍵交換の使用がprime256v1のみに限定されている。 * 本問題を解消するために、`Makefile.local` ファイルを作成して対応する。 * milterをインストール(コンパイル)する順番(依存)が存在しているが、見えにくい。 * sendmailをインストール後にmilterをインストールする必要がある。 == 設定目標 == * バーチャルドメインでの運用を前提とし、サーバー側のアカウント情報や各種設定とは独立した運用を目指す。 * 各種ネット情報を読み解くと、この辺りの振る舞いが混在していて暗黙のウチに動作しているケース(エイリアスの適用など)があるが、今回はそれを一切許さない。 * サーバー側はサーバー側で(root宛のメールなど)、バーチャルドメイン側はバーチャルドメイン側で、切り離された環境を構築する。 * その効能の一つとして、CyrusIMAPd側で持つメールボックスの存在確認をリアルタイムで行うようにする。 * メールボックスが存在しない宛先への受信拒否が即座に行える効果が得られる。 * 従来の、一旦受信してからメールボックスの存在可否を確認して受信拒否という流れになるが、その場合の対応がバウンスメールの発行となる不都合の改善。 * これはスパムメールに対するバウンスメールの送信は無意味なので、その分、キューイングや再送といった負荷が無くなる。 なお、200x年代からこの運用をしてきたが、だましだまし運用してたのを、サーバーリプレースする際に、徹底的に見直した。 見直した[[https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=254495|成果]]はフィードバック済み。 = インストール = == /etc/make.conf == 以下の内容を追記する。 {{{#!highlight makefile numbers=disable # for sendmail mail_sendmail_SET= LA NIS SEM TLS DANE SASL SHMEM MILTER SMTPUTF8 mail_sendmail_SET+= SOCKETMAP BLACKLISTD CYRUSLOOKUP PICKY_HELO_CHECK mail_sendmail_UNSET= BDB LDAP SASLAUTHD # for cyrus-imapd32 mail_cyrus-imapd32_SET= SRS IDLED SQUAT SQLITE XAPIAN AUTOCREATE READLINE_PERL mail_cyrus-imapd32_UNSET= HTTP LDAP NNTP SNMP MYSQL PGSQL BACKUP mail_cyrus-imapd32_UNSET+= CLAMAV MURDER REPLICATION READLINE_GNU # for cyrus-sasl2 security_cyrus-sasl2_SET= OTP CRAM LMDB NTLM DIGEST LOGIN PLAIN SCRAM security_cyrus-sasl2_UNSET= BDB BDB1 ANONYMOUS ALWAYSTRUE AUTHDAEMOND security_cyrus-sasl2_UNSET+= KEEP_DB_OPEN OBSOLETE_CRAM_ATTR OBSOLETE_DIGEST_ATTR }}} * `SOCKETMAP`: CyrusIMAPdのアカウント情報をリアルタイムで参照するための仕組みの有効化 * `CYRUSLOOKUP`: CyrusIMAPd関連の判定、送信に関する情報の定義の有効化 == /usr/ports/mail/sendmail/Makefile.local == 以下の内容でファイルを作成する(「先頭の空白」は全てタブで置き換えること)。 {{{#!highlight makefile numbers=disable post-configure: ${ECHO_CMD} 'APPENDDEF(`conf_sendmail_ENVDEF'\'', `-D_FFR_TLS_USE_CERTIFICATE_CHAIN_FILE'\'')' >> ${WCONF}/site.config.m4 ${ECHO_CMD} 'APPENDDEF(`conf_sendmail_ENVDEF'\'', `-D_FFR_MTA_STS'\'')' >> ${WCONF}/site.config.m4 ${ECHO_CMD} 'APPENDDEF(`conf_sendmail_ENVDEF'\'', `-D_FFR_TLS_ALTNAMES'\'')' >> ${WCONF}/site.config.m4 ${ECHO_CMD} 'APPENDDEF(`conf_sendmail_ENVDEF'\'', `-D_FFR_VRFY_TRUSTED_FIRST'\'')' >> ${WCONF}/site.config.m4 ${ECHO_CMD} 'APPENDDEF(`conf_sendmail_ENVDEF'\'', `-D_FFR_QUEUE_GROUP_SORTORDER'\'')' >> ${WCONF}/site.config.m4 ${ECHO_CMD} 'APPENDDEF(`conf_sendmail_ENVDEF'\'', `-UTLS_EC -DTLS_EC=2'\'')' >> ${WCONF}/site.config.m4 }}} * `_FFR_TLS_USE_CERTIFICATE_CHAIN_FILE`: いわゆる一般的なTLSサーバーと同じ指定(フルチェイン)の仕方にする * `_FFR_MTA_STS`: MTA STSサポート(期待した通り動作しないので検証中・8.17以降の機能) * `_FFR_TLS_ALTNAMES`: コモンネームだけでなくSANsも評価する(現在証明書で要求される機能) * `_FFR_VRFY_TRUSTED_FIRST`: ルート証明書のどれかが生きていれば検証済とする設定 * `_FFR_QUEUE_GROUP_SORTORDER`: キューグループ単位でソート順を指定可能にする(本運用では取り上げない) * `TLS_EC=2`: ECC暗号サポート/ECC暗号(特にキー交換の)指定無し(OpenSSLデフォルトに準拠) * (参考)`TLS_EC=1`: ECC暗号サポート/ECC暗号(特にキー交換は)prime256v1のみ指定(変更不可) なお `_FFR_TLS_USE_CERTIFICATE_CHAIN_FILE` の指定が無い場合は、証明書・中間証明書・秘密鍵の3つが別れて指定される、という意味では無く、もっとおぞましい振る舞いをする。 話を聞くとサーバーサイドとクライアントサイドの振る舞い(特に中間証明書の取り扱い)が分離されていないなど、極めて初期の実装が残っているとのこと。 == インストール == {{{#!highlight shell numbers=disable cd /usr/ports/security/cyrus-sasl2 && make install cd /usr/ports/mail/sendmail && make install cd /usr/ports/mail/cyrus-imapd32 && make install }}} = セットアップ = == /usr/local/lib/sasl2/Sendmail.conf == 以下の内容のファイルを作成する。 {{{ pwcheck_method: auxprop auxprop_plugin: sasldb }}} * SendmailのSASLサポートコードにはSASL関連の設定に関するコードが含まれておらず、SASLライブラリがケアしてる設定ファイルにて設定を行う必要がある。 * 平文パスワードでは `pwcheck_method` 設定が参照されるが、暗号パスワードでは直接 `auxprop_plugin` 設定が参照される。 * これが意味するところは、事実上 `pwcheck_method: auxprop` として強制的に解釈されることを意味する。 * `pwcheck_method: saslauthd` と設定しても、上記振る舞いから、意図した動作をしないため、設定しないこと。 本条件において適用可能なオプションとしては、下記の物があるが、CyrusIMAPd側の設定との調整を考えるとデフォルトのままとする。 ||<#FFFF00> 設定名 ||<#FFFF00> デフォルト値 ||<#FFFF00> 意味 || || `sasldb_path` || `/usr/local/etc/sasldb2` || SASLDBファイル(本件ではLMDB)のパス || || `sasldb_mapsize` || `1048576` バイト || (LMDB固有)全ユーザーをオンメモリにマッピングするためのサイズ || || `sasldb_maxreaders` || `126` || (LMDB固有)SASLDBファイルを同時アクセス可能な最大セッション(プロセス)数 || * 特に `sasldb_mapsize` と `sasldb_maxreaders` の設定はユーザー数が多くなってきたときに調整が必要となる。 * ※IMAPサーバー側で同時アクセス数のリークを確認。再起動で改善する(2022年01月現在、問題を確認済み)。 {{{#!wiki note SASLクライアントが参照すべき設定ファイル名は sasl_server_init() 関数に引き渡される appname 引数により決定される。 SASLフレームワーク的にはマニュアルに明記されていることではあるが、 フレームワークを使用する側(Sendmailなど)ではマニュアルに記載(※)されておらず、 その振る舞いの調査が必要な場合は参考までに。 https://www.cyrusimap.org/sasl/sasl/reference/manpages/library/sasl_server_init.html }}} ※厳密には、フレームワーク使用側の、外のドキュメント(フレームワーク側)で明記されているが、その根拠が明記されていない。 == /etc/mail/Makefile.local == 以下のファイルを作成する。 {{{#!highlight makefile numbers=disable SENDMAIL_CF_DIR=/usr/local/share/sendmail/cf }}} == /etc/mail/ホスト名.mc == いわゆるsendmail.cf作成準備 {{{#!highlight shell numbers=disable ln -s freebsd.submit.mc /etc/mail/$(hostname).submit.mc cd /etc/mail && make }}} == 切り替え == {{{#!highlight shell numbers=disable cd /usr/ports/mail/sendmail && make mailer.conf }}} なお切り戻しは下記のように実行する。 {{{#!highlight shell numbers=disable rm -f /etc/mail/Makefile.local cd /etc/mail && rm -f ホスト名*.cf && make cd /usr/ports/mail/sendmail && make mailer.base }}} = /etc/mail/ホスト名.mc のカスタムポイント = == TLS関連設定 == === 変更箇所 === * `confSERVER_CERT` * `confSERVER_KEY` * `confCLIENT_CERT` * `confCLIENT_KEY` * `confCACERT` * `confCACERT_PATH` `conf*_CERT` にて中間書証明書を含むSSL証明書(いわゆるフルチェイン証明書)のファイル名を、`conf*_KEY` にて秘密鍵の ファイル名を指定する。 複数の証明書(ECC証明書とRSA証明書といった組み合わせ)を指定したい場合は、順番に「`,`」でつなげる。下記のように1個目、2個目の証明書がそれぞれ対応するように指定する。また3個以上の証明書は指定できない(指定できる証明書の数は1個か2個)。 {{{ define(`confSERVER_CERT', `ECCフルチェイン証明書,RSAフルチェイン証明書')dnl define(`confSERVER_KEY', `ECC秘密鍵,RSA秘密鍵')dnl }}} `confCACERT` は特に指定しなくてもよいが、`confCACERT_PATH` には `/etc/ssl/certs` を指定する。これは特にFreeBSD12.2以降では必須とも言える対応になる。 それ以前のバージョンでは、この設定に指定するディレクトリの工夫が必要であった(もう必要無いので説明しない)。 === 追加設定 === * `confSERVER_SSL_OPTIONS` ※OpenSSLのオプション(`,` でつなげて指定する) * `SSL_OP_NO_SSLv2`: SSLv2の無効化 * `SSL_OP_NO_SSLv3`: SSLv3の無効化 →TLS1.0以降に対応する * `SSL_OP_NO_RENEGOTIATION`: リネゴシエーション機能の無効化 * `SSL_OP_PRIORITIZE_CHACHA`: AES暗号とChaCha暗号の同一優先度 * `SSL_OP_CIPHER_SERVER_PREFERENCE`: 暗号スイートをサーバー指定を優先する * `confCIPHER_LIST` ※暗号スイートの指定(`:` でつなげて指定する) * `TLS_AES_256_GCM_SHA384` * `TLS_CHACHA20_POLY1305_SHA256` * `TLS_AES_128_GCM_SHA256` * `ECDHE-ECDSA-AES256-GCM-SHA384` * `ECDHE-ECDSA-CHACHA20-POLY1305` * `ECDHE-ECDSA-AES128-GCM-SHA256` * `ECDHE-RSA-AES256-GCM-SHA384` * `ECDHE-RSA-CHACHA20-POLY1305` * `ECDHE-RSA-AES128-GCM-SHA256` * `DHE-RSA-AES256-SHA` * `DHE-RSA-AES128-SHA` * `AES256-SHA` * `AES128-SHA` * `confTLS_FALLBACK_TO_CLEAR` ※送信時にSTARTTLSに失敗した場合、STARTTLSしないで送信しようとするかどうかのオプション {{{ define(`confSERVER_SSL_OPTIONS', `SSL_OP_NO_SSLv2,SSL_OP_NO_SSLv3,SSL_OP_NO_RENEGOTIATION,SSL_OP_PRIORITIZE_CHACHA,SSL_OP_CIPHER_SERVER_PREFERENCE')dnl define(`confCIPHER_LIST', `TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:AES256-SHA:AES128-SHA')dnl define(`confTLS_FALLBACK_TO_CLEAR', `True')dnl }}} == 認証関連の設定 == * `confAUTH_MECHANISMS` * `SCRAM-SHA-256` * `SCRAM-SHA-1` * `CRAM-MD5` * `PLAIN` {{{ define(`confAUTH_MECHANISMS', 'SCRAM-SHA-256 SCRAM-SHA-1 CRAM-MD5 PLAIN') }}} == CyrusIMAPd関連設定 == {{{ FEATURE(mrs) FEATURE(mrs_cyrus) MAILER(cyrusv2) }}} `MAILER` 行は他の `MAILER` 行の周辺に置くこと。`FEATURE` 行は `MAILER` 行の前にあればどこでもよい。 == バーチャルホスト関連設定 == {{{ define(`ALIAS_FILE', `/etc/mail/virtaliases,/etc/mail/aliases')dnl VIRTUSER_DOMAIN_FILE(`-o /etc/mail/virtdomains') }}} = バーチャルホスト連携 = == /etc/mail/virtdomains == {{{ example.jp }}} == /etc/mail/mailertable == {{{ example.jp mrs_cyrus_mailertable: }}} ※ドメインの後の「空白」は「タブ」に置き換えること。`:` の後ろに指定は無いが、`:` の存在は必須である。 == /etc/mail/virtaliases == {{{ }}} とりあえず空で。 = よくある質問とその答え = == Q.下記のように confLOCAL_MAILER で設定すればいいぢゃん、なんでしないの? == {{{ define(`confLOCAL_MAILER', `cyrusv2')dnl }}} A.sendmailが取り扱う全てのメールをローカルメーラーとして、CyrusIMAPdに送るということはできますが、以下のデメリットが嫌でそうしていません。 * CyrusIMAPd側にシステムと同じアカウントが必要。もちろんエイリアスである程度集約させることは可能。 * 当然SASLアカウント設定も(ある程度)同じ設定が要求される。 * そのアカウントはローカルパートのみの指定となり、マルチドメイン運用はできない(混在させることは可能)。 * MUAに設定する内容(アカウント情報)は、全てローカルパートベースとなって、マルチドメイン運用できない。 * マルチドメインで運用するなら結局それなりのセットアップが要求される。 * それならシステムメールは従来通り `/var/mail` で受けてもらって、サービスメールと分離させてしまうのが素直である。 ※なおsendmailで受信して、CyrusIMAPdのメールボックスに送るだけなら、SASLアカウントの設定は不要。 == Q.この手の設定を他で見ると下記のように /etc/mail/access ファイルで設定してるぢゃん、何か違いは? == {{{ example.jp: RELAY }}} A.sendmailのバーチャルドメイン機構を最大限生かすための設定です。 上記設定だけで、`/etc/mail/mailertable` や `confLOCAL_MAILER` の設定を忘れると、容易にサードパーティリレイできてしまいます。 `VIRTUSER_DOMAIN_FILE` を設定すれば、メールボックスの存在が必須になるため、存在しない場合にエラーになります。 == Q.ports/pkgで入れないと駄目なんですか? == A.ベースシステムにSASLライブラリが無いのでいかんともしがたいです。 ベースシステムに、ports/pkgでインストールされたSASLライブラリ付でビルドすることもできないでもないですが、 OSのバージョンアップ時のメンテナンスがめんどくさくなるのでオススメしません。 == Q.pkgで入れられないのですか? == A.CyrusIMAPd関連の設定(アカウント情報をリアルタイムに参照する設定と転送するための設定)がpkgには無いので、portsでないとダメです。 == Q.以下のエラーが出てメールの送信ができません == {{{ AUTH failure (XXXXXXXX): generic failure (-1) SASL(-1): generic failure: Unable to open MDB transaction, user=... }}} A.極シンプルにCyrusIMAPdサーバーの再起動で一時しのぎします。 {{{#!highlight console numbers=disable service imapd restart }}} A.以下のコマンドを実行して、LMDBファイルに接続しているセッション数およびプロセスIDを確認する。 {{{#!highlight console numbers=disable # mdb_stat -ne /usr/local/etc/sasldb2 Environment Info : Max readers: 126 Number of readers used: 101 Status of Main DB : }}} 上記の例の場合、最大126セッション中101セッション使用していることが分かる。 {{{#!highlight console numbers=disable # mdb_stat -nr /usr/local/etc/sasldb2 Reader Table Status pid thread txnid 15223 801e12000 - 15229 801612000 - : }}} 上記のように、具体的にLMDBファイルをつかんでるPIDのリストが取得できる。 {{{#!highlight console numbers=disable # pgrep -lf -F <(mdb_stat -nr /usr/local/etc/sasldb2 | awk '/[0-9]/ { print $1 }') 15223 imapd: imaps: XXXXXX.XXXXXXXXXX.XXX [XXX.XXX.XXX.XXX] nork@ninth-nine.com ninth-nine.com!user.nork Idle }}} ※ZSH/BASH拡張を使用しているので、SH等では実行できない点に注意。 ここで表示されるPIDのプロセスに対して終了を促すことになるが、とどつまりCyrusIMAPdサーバーの再起動という結論で。 本サーバーがSASLDBライブラリに接続リークを起こすことを確認。 === Q.なんでLMDB使う?デフォルトのBDB1でええやん。 === A.LMDBと言えばなうでヤングなインメモリデータベースやん。スケーラビリティとか諸々安心という点が売り。 === Q.SASLAUTHD、SASLAUTHDと色々うるさいが、SASLAUTHDに恨みでもあるのですか? === A.ありまぁす! `pwcheck_method` の設定の有効性が、認証方法に依存するなんて、この手の設定の解説を見たことありません! 無条件にインストールしてる例を見ますが、実際には必要かどうか全く検証してないことがわかりました! オリジナルのドキュメントにも[[https://www.cyrusimap.org/sasl/sasl/sysadmin.html#the-plain-mechanism-sasl-checkpass-and-plaintext-passwords|一応書いてある]]のですが、こっそり過ぎてわかりません! = 参考文献 = * [[https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=254495|254495 - mail/sendmail: overhaul cyruslookup.patch]] * [[https://www.cyrusimap.org/sasl/sasl/options.html|Cyrus SASL documentation — Options]] * [[https://www.cyrusimap.org/sasl/sasl/reference/manpages/library/sasl_server_init.html|sasl_server_init - SASL server authentication initialization]] * [[http://jmaimon.com/sendmail/anfi.homeunix.net/sendmail/rtcyrus2.html|Real Time Cyrus Integration Version 2 (sendmail,cyrus)]] * [[http://jmaimon.com/sendmail/anfi.homeunix.net/sendmail/mrs.html|Mailertable Rule Sets (sendmail)]] * [[http://jmaimon.com/sendmail/anfi.homeunix.net/sendmail/cyrusv2.html|cyrusv2 mailer - release B (sendmail)]]