実験:OpenSMTPDでメールサーバ構築(CentOS7,Ubuntu Server(20.04.1 LTS)で最新設定仕様のファイルもあります。)
2019年12月19日Linux Tips, テクニカル, トピックス, ノウハウ
ちょっとメールサーバ(MTA)としては、レアなサーバを使って見ました。OpenSMTPDというBSD系UNIXでは知られているSMTPサーバらしい。ネットで調べてみると日本では情報が極めて少ないどんなもんかなーと思い構築してみました。メールは普段IMAPしか使いませんがちょっとレトロなPOPサーバでも入れて見ようかと懐かしいQpopperと組み合わせて見ようと思います。脆弱性とか色々あるけれどセキュリティツールでいくらでも抑え込めるので気にしない。 使ってみた感触は悪くないですね。設計の思想がまた他のMTAと全く異なるのでそこは面白い。postfixには無いこともできそうに思います。このMTAは受信ネットワークインターフェイス単位で制御を細かくできる点が素晴らしいです。本当はfilter文が使えるなら色々試せたのですが必要最低限セキュリティを担保して作ってみました。細かいヘッダやボディチェックはprocmailに任せ、DNSBLとベイジアンフィルターでスパム撃退を行っています。実際の25,587のフロントはfuというDNSBL smtpプロキシーで受信チェックしてそれから後ろにあるopensmtpdへ渡しています。
インストール
ソースでコンパイルしてもよかったが、依存ライブラリーを入れるのが面倒くさいのでパッケージインストールをすることに。epelがインストール済みなら問題無し。 後で調査してみたがopensmtpd-extras*はどうもopensmtpd起動時にロードできないようだ。バグかな。debianの過去issueで同じようなロードできないバグが見つかったので同類の問題か。。。 OpenSMTPDはOS環境によって出来具合いが違うという記述を見たので移植仕切ってなかった可能性はある。ソースでコンパイルするといけるかもしれ無いけども、まあしょうがない。
CentOS7の場合
1 |
# yum install opensmtpd opensmtpd-extras* |
Ubuntu Server
1 |
# apt install opensmtpd opensmtpd-extras |
設定ファイルの作成
細かい解説は省く。インストールすると/etc/opensmtpディレクトリが生成されその配下にopensmtpd.confが出来ているのでそのファイルを編集します。受信箱に入る前にベイジアンフィルターbsfilterを使用しているため内部的にprocmailを使っています。その箇所は割愛します。opensmtpdは前述の通りDNSBLプロキシーから受け取った受信を後ろで待ち受けるためListenはローカルアドレスで受け取るようにしています。ubuntu serverでは、/etcの直下にsmtpd.confが生成されます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
# vi opensmtpd.conf # This is the smtpd server system-wide configuration file. # See smtpd.conf(5) for more information. myname = "devil-test.net" # To accept external mail, replace with: listen on all #listen on 0.0.0.0 port 25 table vdomains { devil-test.mobi, heaven-test.net } table vusers file:/etc/opensmtpd/vusers table upass file:/etc/opensmtpd/creds pki devil-test.net certificate "/etc/opensmtpd/tls/smtp-cert.pem" pki devil-test.net key "/etc/opensmtpd/tls/smtp-key.pem" #incomming mail listen on lo port 1025 tls pki devil-test.net auth-optional #DKIM sign forward to dkimproxy listen on lo port 10028 tag DKIM #outgoing mail listen on enp0s7 port submission tls-require pki devil-test.net auth <upass> hostname devil-test.net max-message-size 10000000 limit session max-mails 10 limit session max-rcpt 10 expire 10h #mta max-deferred 20 bounce-warn 1h, 6h, 2d #mynetwork = "192.168.0.0/24" # If you edit the file, you have to run "smtpctl update table aliases" table aliases db:/etc/opensmtpd/aliases.db # Uncomment the following to accept external mail for domain "example.org" accept from any for domain <vdomains> virtual <vusers> deliver to mda "/usr/bin/procmail -f -" accept from any for domain "devil-test.net" alias <aliases> deliver to mda "/usr/bin/procmail -f -" accept for local alias <aliases> deliver to mda "/usr/bin/procmail -f -" accept tagged DKIM for any relay accept from any authenticated for any relay via smtp://127.0.0.1:10027 |
上記の設定はCentOS7のバージョンなので現状は古い設定となっています。下記はUbuntu Serverの最新版 20.04.1 LTSで検証したものです。ディレクティブが所々微妙に違いがあります。DKIMとリレーのあたりの記述は結構苦戦しました。ほとんど資料がなくて当てずっぽうで書いてみた実験の末、ようやく動きました。約5時間程試行錯誤したかもしれません。Ubuntu Serverではデフォルトの設定パスが/etcの直下になります。設定ファイルは/etc/smtpd.conf
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
# This is the smtpd server system-wide configuration file. # See smtpd.conf(5) for more information. myname = "devil-test.net" # To accept external mail, replace with: listen on all table vdomains { devil-test.mobi, heaven-test.net } table vusers file:/etc/vusers table upass file:/etc/creds pki proto-srv.red cert "/etc/tls/smtp-cert.pem" pki proto-srv.red key "/etc/tls/smtp-key.pem" #incomming mail listen on lo port 1025 tls pki devil-test.net auth-optional #DKIM sign foward to dkimproxy listen on lo port 10028 tag DKIM #outgoing mail listen on enp6s0 port submission tls-require pki devil-test.net <upass> hostname devil-test.net smtp max-message-size 20M smtp limit max-mails 10 smtp limit max-rcpt 10 queue ttl 24h bounce warn-interval 1h, 6h, 2d # If you edit the file, you have to run "smtpctl update table aliases" table aliases db:/etc/aliases.db # Uncomment the following to accept external mail for domain "example.org" action mda_procmail mda "/usr/bin/procmail -f -" virtual <vusers> action mda_alias mda "/usr/bin/procmail -f -" alias <aliases> action relayout relay helo devil-test.net action dkimproxy relay host smtp://127.0.0.1:10027 match from any for domain <vdomains> action mda_procmail match from any for domain "devil-test.net" action mda_alias match from local for local reject match from any tag DKIM for any action relayout match from any auth for any action dkimproxy match from rdns regex 0^ for any reject |
ユーザ登録関連ファイルの作成
サポートドメイン毎のユーザ登録
1 2 3 4 5 |
# vi /etc/opensmtpd/vusers johnny@devil-test.net john crawford@heaven-test.net craw # makemap /etc/etc/opensmtpd/vusers |
パスワードの作成と格納
1 2 3 4 5 6 7 8 |
# smtpctl encrypt admin1212123321 < ----第2引数がパスワード $6$kbUSLLm2KkvHdQNz$Uuao2kwJ8IE9RcvNaCHlMltS5Hy6qvT5C8jeVji6f2gK1FkLPFwBW4SLEIbOpVJK3yZ/5znn8afh.cfM3glq01 表示されたコードをコピーして次のようにする。 # vi /etc/opensmtpd/creds johnny $6$kbUSLLm2KkvHdQNz$Uuao2kwJ8IE9RcvNaCHlMltS5Hy6qvT5C8jeVji6f2gK1FkLPFwBW4SLEIbOpVJK3yZ/5znn8afh.cfM3glq01 crawford $6$LXP29fwv2l/93FDG$x5rWi3zxZ/cL4TB26OEOWkGHtSIH4vr.yX3FnnfbHh8GNlexRRmtSF2UvvPnUztinsvNIYeveDTvGu6oT18ES. |
メーラ側ではSMTP認証のタイプはプレーン認証(暗号化なし)を選ぶことになるが上記の通り内部では暗号化しているのでサーバに侵入されて盗まれたところで実害は無いと思います。接続タイプがSTARTTLS/SSLならまあ概ね安全じゃないでしょうか。
filter機能が使えないので、fuを経由してDNSBLをする。
extraパッケージが機能しないのでfilter文が無視される。しょうがないのでDNSBLをproxy仕様で対応することにした。尚、Ubuntu serverではfilter文が動作するか試しておりません。しかしfu自体はUbuntu Serverでも同様に利用できました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
コードがpython2.7x必要。 # git clone https://github.com/waawal/fu.git # cd fu # python2.7 setup.py install # vi fu.yml settings: loglevel: notice predicate: 2 threshhold: 1.0 bind: 202.177.230.xxx: 25 <---- FU proxyのアドレス(外部から待ち受けするグローバルアドレス) upstream: - 127.0.0.1: 1025 <---- 実際の受信するローカルSMTPサーバ(OpenSmtpd) providers: bl.spamcop.net: {weight: 0.3} ix.dnsbl.manitu.net: {weight: 1.0} rhsbl.ahbl.org: {weight: 0.3} truncate.gbudb.net: {weight: 1.0} zen.spamhaus.org: {weight: 0.5} |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
# vi fu.py 下記のメソッドがpredicateが未定義とエラーが出るので追記してあげます。 1ヶ所目の修正 def resolve(zone): """ Checks if the name resolves and if the last part of the reply is >= the predicate. :param zone: A valid zone for lookup ex: '234.52.218.89.ix.dnsbl.manitu.net.' :type zone: string :rtype: integer """ predicate = 2 <----追記が必要。 try: reply = socket.gethostbyname(zone) result = int(reply.split('.')[-1]) logging.debug('DNSBL reply: {0}'.format(result)) return result >= predicate except (socket.error, ValueError): logging.debug('Negative response from {0}'.format(zone)) return False 2ヶ所目の修正:140-144行目のあたり #configuration = yaml.load(stream) <----- deprecateした記述とされている。 configuration = yaml.load(stream,Loader=yaml.SafeLoader) <----現在の記述方法 |
DNSBL proxy fuの起動
Python2.7とするかpythonとするかはセッティング次第なので環境に合わせてください。
1 |
# nohup python2.7 fu.py -c ./fu.yml 2> debug.log & |
DKIM Proxyの設定
postfixでおなじみのOpenDKIMは使えないという噂なので、 DKIM Proxyを使用します。dkimproxy用のユーザ作成は必要です。dkimユーザを予め作っておいてください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
# wget http://downloads.sourceforge.net/dkimproxy/dkimproxy-1.4.1.tar.gz # tar xvfz dkimproxy-1.4.1.tar.gz # cd dkimproxy-1.4.1 # ./configure --prefix=/usr # make install # cd scripts # cp dkimproxy_in.conf.example /usr/etc/dkimproxy_in.conf # cp dkimproxy_out.conf.example /usr/etc/dkimproxy_out.conf # vi /usr/etc/dkimproxy_out.conf listen 127.0.0.1:10027 # specify what address/port DKIMproxy forwards mail to relay 127.0.0.1:10028 # specify what domains DKIMproxy can sign for (comma-separated, no spaces) domain devil-test.net # specify what signatures to add signature dkim(c=relaxed) signature domainkeys(c=nofws) # specify location of the private key keyfile /etc/opensmtpd/keys/dkim.key # specify the selector (i.e. the name of the key record put in DNS) selector foxmail # control how many processes DKIMproxy uses # - more information on these options (and others) can be found by # running `perldoc Net::Server::PreFork'. min_servers 3 min_spare_servers 2 鍵の作成 # openssl genrsa -out private.key 1024 # openssl rsa -in private.key -pubout -out dkim.key # cp dkim.key /etc/opensmtpd/keys/ |
DKIM Proxyのサービス登録
DKIM用のDNSレコード設定は他のSMTPサーバと同様なので割愛します。
1 2 3 4 5 6 7 8 9 10 11 |
# vi /etc/systemd/system/dkimproxy-out.service [Unit] Description=Run DKIMproxy service [Service] ExecStart=/usr/bin/dkimproxy.out --conf_file=/usr/etc/dkimproxy_out.conf Restart=always User=dkim [Install] WantedBy=multi-user.target |
DKIM proxy起動
1 2 |
# systemctl daemon-reload <----新サービス登録時1回は行う # systemctl start dkimproxy-out |
qpopperのインストール
1 2 3 4 5 6 |
# wget https://fossies.org/linux/misc/old/qpopper4.1.0.tar.gz # tar xvfz qpopper4.1.0.tar.gz # cd qpopper4.1.0 # ./configure --enable-specialauth --mandir=/usr/share/man --with-openssl=/usr/lib64/openssl # make # make install |
Qpopper設定ファイル
/etc/qpopper995.cfgファイルの編集
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
# cd qpopper4.1.0 # cd samples # cp qpopper.config /etc/qpopper995.cfg # vi /etc/qpopper995.cfg 変更箇所 set temp-dir = /var/mail set shy = true set log facility = local1 set trim-domain = true set tls-support = alternate-port set tls-private-key-file = /etc/opensmtpd/tls/smtp-key.pem set tls-server-cert-file = /etc/opensmtpd/tls/smtp-cert.pem set clear-text-password = never set statistics = true |
xinetdのインストール
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
# yum install xinetd # cd /usr/local/src/qpopper4.1.0 # cd samples # cp qpopper.xinetd /etc/xinetd.d/qpopper # vi /etc/xinetd.d/qpopper service pop3s { flags = REUSE NAMEINARGS socket_type = stream wait = no user = root server = /usr/local/sbin/popper server_args = popper -s -f /etc/qpopper995.cfg -l 2 instances = 50 port = 995 disable = no per_source = 10 } # service xinetd start |
ログローテーションの設定
1 2 3 4 5 6 7 8 9 10 11 12 |
# cd /etc/logrotate.d # vi popper /var/log/popper { weekly compress postrotate /bin/kill -HUP `cat /var/run/syslogd.pid 2> /dev/null` 2> /dev/null || true endscript } # /usr/sbin/logrotate /etc/logrotate.conf |
APOPのユーザ登録
APOP仕様にするとメールソフトの設定でパスワードの暗号化(CRAM-MD5)が選択できます。
1 2 3 4 5 6 7 |
# useradd -g root pop # cd /usr/local/sbin # chown pop popauth # chmod u+s popauth # popauth -init # popauth -user johnny # popauth -user craw |
Firewalldで必要なポートをオープンします。
ポート番号、25,587,995をオープンします。
1 2 3 4 |
# firewall-cmd --permanent --zone=public --add-service=smtp # firewall-cmd --permanent --zone=public --add-service=smtp-submission # firewall-cmd --permanent --zone=public --add-service=pop3s # firewall-cmd --reload |
Ubuntu serverの場合ufwでFirewallオープンします。
1 2 3 4 |
$ sudo ufw allow 25/tcp $ sudo ufw allow 587/tcp $ sudo ufw allow 995/tcp $ sudo ufw reload |
Ubuntu serverではpopsにdovecotを使う
qpopperのコンパイルがgccのバージョン関連の仕様相違があり、コンパイルできませんでした。ソースコードを改変するのもかったるいのでdovecotでいきました。
1 2 3 4 5 6 |
# cd /etc/dovecot # vi dovecot.conf 以下の2箇所を修正 protocols = pop3s listen = *, :: |
pop認証の編集
1 2 3 4 5 6 7 8 9 10 |
# vi 10-master.conf service pop3-login { inet_listener pop3 { port = 110 } inet_listener pop3s { port = 995 ssl = yes } } |
メールボックスの形式設定
1 2 |
# vi /etc/dovecot/conf.d/10-mail.conf mail_location = mbox:~/mail:INBOX=/var/mail/%u |
SSLの設定
1 2 3 4 |
# vi 10-ssl.conf ssl = yes ssl_cert = </etc/tls/smtp-cert.pem ssl_key = </etc/tls/smtp-key.pem |
ユーザ認証の認証タイプを設定
1 2 3 4 5 |
# vi 10-auth.conf auth_mechanisms = plain login cram-md5 !include auth-system.conf.ext !include auth-passwdfile.conf.ext |
ユーザ認証形式とDBの所在を設定
1 2 3 4 5 6 7 8 9 10 |
# vi /etc/dovecot/conf.d/auth-passwdfile.conf.ext passdb { driver = passwd-file args = /etc/dovecot/passwd } userdb { driver = passwd-file args = /etc/dovecot/passwd } |
ユーザパスワードの書式設定
1 2 3 4 5 6 |
# vi /etc/dovecot/conf.d/auth-system.conf.ext passdb { driver = passwd-file args = scheme=CRYPT username_format=%u /etc/dovecot/passwd } |
ユーザのパスワードファイル設定
「doveadm pw」で実行した内容と/etc/passwdを合成して/etc/dovecot/passwdを生成してください。以下のような形式です。
1 |
oreoreuser:{HMAC-MD5}a129d1c51cc07a303f...........02fb8145:1002:1002::/home/oreoreuser:/bin/sh |
dovecotの起動
1 2 |
# systemctl start dovecot # systemctl enable dovecot |