« 娘ちゃんと NOVA 問題を語らうの巻き | Main | 中止ボタンがしいたけに見えて困る »
先日は CentOS 5.0 に ClamAV をインストールし、ClamdOmitScan を用いた定期スキャン用に設定するとともに clamav-update で自動アップグレードするようにした。
今回は CentOS 5.0 で Postfix を MTA として使用しているときに、amavisd-new を通して SpamAssassin と ClamAV によってスパム判定と感染メールのチェックをする設定について説明する。clamav-update プロジェクトのソフトウェアは clamdsh を使用する。
このドキュメントは次のことを前提としている。
CentOS 5.0 では amavisd-new が rpm で用意されていない。そこでまず最初に amavisd-new をダウンロードし、ダウンロードした中にあるドキュメントに記載されている関連するソフトウェアをインストールする。
URL は http://www.ijs.si/software/amavisd/#download。解凍すると amavisd-new-バージョン というディレクトリができる。
ここではそのディレクトリを /root/etc/amavisd-new/amavisd-new-2.5.2 として説明する。
/root/etc/amavisd-new/amavisd-new-2.5.2/INSTALL に記載してある必須の Perl モジュールを全てインストールする。依存するモジュールも同時にインストールするには cpan コマンドが便利。
INSTALL に記載してあるオプションの Perl モジュールをインストールする。Mail::ClamAV はインストールしなくてよい。clamd を利用する方がメモリ効率も処理効率も高いから。しかし、clamd の未知の脆弱性を突かれて DoS 攻撃されることを懸念するならば使用する選択肢もある。Mail::SpamAssasin は SpamAssassin パッケージに含まれている。
INSTALL に記載してある外部コマンドをなるべく多くインストールしておく。一覧は各コマンドの提供元の URL と一緒にリストされているところを見る。無いものは無いでもよい。pax など rpm で提供されているものくらいはインストールしておく。
amavisd-new のデーモン amavisd は Perl スクリプトなのでビルドは必要なく、動作のための環境作りとファイルのコピーをする。この段階では amavisd 自体の動作環境の設定のみで、それを SpamAssassin や ClamAV と連動させるのは以降のステップである。
groupadd -r amavis
useradd -r -d /var/amavis -g amavis -s /sbin/nologin amavismkdir /var/amaviscd /var/amavismkdir tmp var db home quarantinechown -R amavis:amavis .chmod -R 750 .
cp /root/etc/amavisd-new/amavisd-new-2.5.2/amavisd /usr/local/sbin/chown root /usr/local/sbin/amavisdchmod 755 /usr/local/sbin/amavisd
cp /root/etc/amavisd-new/amavisd-new-2.5.2/amavisd.conf /usr/local/etc/chown root:amavis /usr/local/etc/amavisd.confchmod 640 /usr/local/etc/amavisd.conf
/usr/local/etc/amavisd.conf を次の要領で編集する。
$daemon_user = 'vscan';$daemon_user = 'amavis';$daemon_group = 'vscan';$daemon_group = 'amavis';amavisd は必要に応じてメールを送信するのだが、そのときの送信元のメールアドレスのドメイン名などに使用される。
$mydomain = 'example.com';$mydomain = 'mydomain.co.jp';# $MYHOME = '/var/amavis';$MYHOME = '/var/amavis';$QUARANTINEDIR = '/var/virusmails';$QUARANTINEDIR = '/var/amavis/quarantine';# $db_home = "$MYHOME/db";$db_home = "$MYHOME/db";必要に応じて LAN (というよりも信頼するネットワーク)を設定する。デフォルトではループバックアドレスといわゆる IPv4 のプライベートネットワークが全て、IPv6 のリンクローカルユニキャストアドレスなどが設定されている。実際に設置されるマシンがこれら全てのネットワークに所属するわけではないのでこれを限定しておく。
ここで指定したネットワークからリモートで amavisd に接続できるようになる(と思う)。
@mynetworks = qw( 127.0.0.0/8 [::1] [FE80::]/10 [FEC0::]/10 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16 );@mynetworks = qw( 127.0.0.0/8 192.168.42.0/24 );メールのヘッダなどに amavisd が自分のホスト名を書き込むときに使用される値がある。デフォルトでは uname コマンドで表示されるホスト名になっているのだが、そのホスト名が例えば LAN 上のもので WAN 向けとは異なる場合などに設定する。
# $myhostname = 'host.example.com'; # must be a fully-qualified domain name!$myhostname = 'mail.mydomain.co.jp'; # must be a fully-qualified domain name!編集が終わったら間違いがないかどうかをチェックするために amavisd をデバッグモードで起動する。
/usr/local/sbin/amavisd -c /usr/local/etc/amavisd.conf debug
amavisd が終了することなく稼働しつづけ、全ての amavisd プロセスのインスタンスのオーナが amavis であれば成功である。amavisd は ctrl-c をタイプして終了させる。
ここで amavisd の起動スクリプトを用意しておいたので、これを /etc/rc.d/init.d に置いて実行パーミッションを付けておく。そして次のようにして有効化しておく。
chkconfig --add amavisd
ClamAV を導入したときは定期スキャン用に clamd を設定した。この clamd は利用しない。なぜなら外部から来るメールのスキャンに利用するので、もし clamd の未知の脆弱性が利用されて clamd をクラッシュさせられてしまうと定期スキャンにも影響してしまうからだ。さらに、定期スキャン用の clamd は root 権限で動作している。root 権限で行う必要の無いことはできるだけ root 権限で行わない方が良い。もし clamd に任意のコードを実行させる脆弱性があったら root 権限で任意のコードが実行されてしまうからだ。メールはユーザが承認する前にシステムに入ってくるデータなので特に注意が要る。
そこでここで使用する clamd は次のように設定する。
/usr/local/etc/clamd-amavis.conf/var/amavis/var/clamd.pid/var/amavis/tmp/var/amavis/var/clamd.socketamavisこれら以外はポリシーにしたがって各自で決定すること。
定期スキャン用の clamd.conf をベースとしてコピーする。
cp /usr/local/etc/clamd.conf /usr/local/etc/clamd-amavis.conf
/usr/local/etc/clamd-amavis.conf を編集する。
amavisd 用 clamd 設定ファイル /usr/local/etc/clamd-amavis.conf を次の要領で編集する。
#LogFacility LOG_MAILLogFacility LOG_MAILPidFile /var/run/clamd.pidPidFile /var/amavis/var/clamd.pidTemporaryDirectory /var/clamav/tmpTemporaryDirectory /var/amavis/tmpLocalSocket /var/clamav/clamd.socketLocalSocket /var/amavis/var/clamd.socket#SelfCheck 600SelfCheck 0#User clamavUser amavis設定ファイルが正しく作成できたことを確認するために clamd を実際に起動し動作をチェックする。以下はその様子。
# /usr/local/sbin/clamd -c /usr/local/etc/clamd-amavis.conf # sleep 3 # ps u `cat /var/amavis/var/clamd.pid` USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND amavis 4797 28.4 12.5 34620 31968 ? Ss 18:05 0:07 /usr/local/sbin # /usr/local/bin/clamdsh.pl --clamdConf=/usr/local/etc/clamd-amavis.conf /var/amavis/var/clamd.socket# PING PONG /var/amavis/var/clamd.socket# SHUTDOWN /var/amavis/var/clamd.socket# exit
clamdsh で SHUTDOWN コマンドを clamd に送っているので、起動した clamd は停止している。
freshclam の設定ファイル /usr/local/etc/freshclam.conf を次の要領で編集する。
#OnUpdateExecute commandOnUpdateExecute echo RELOAD | /usr/local/bin/clamdsh.pl --clamdConf=/usr/local/etc/clamd-amavis.conf
amavisd 用 clamd の起動スクリプトを作成しておいた。これを /etc/rc.d/init.d/ にコピーして、実行パーミッションを付ける。そして次のようにして有効にする。
chkconfig --add clamd-amavis
/etc/rc.d/init.d/clamd-amavis start
/etc/rc.d/init.d/freshclam restart
準備した clamd を amavisd が利用するように amavisd の設定ファイル /usr/local/etc/amavisd.conf を編集する。
/usr/local/etc/amavisd.conf の 350 行目付近に“@av_scanners = (”と書いてある行がある。ここからその丸括弧(開き)に対応する丸括弧(閉じ)までが amavisd が利用するウィルススキャナーの定義になっている。この @av_scanners には他にもたくさんのウィルススキャナーの設定がコメントになって載っているが、後半にはコメントになっていないものある。それらを“# ”を付けてコメントにしておく。正規表現 /^ / にマッチする行を“#”に置き換える操作を @av_scanners の内部に施すと便利。
そしてこの中で次のようにコメントになっている clamd の定義を探す。
# ### http://www.clamav.net/
# ['ClamAV-clamd',
# \&ask_daemon, ["CONTSCAN {}\n", "/var/run/clamav/clamd"],
# qr/\bOK$/, qr/\bFOUND$/,
# qr/^.*?: (?!Infected Archive)(.*) FOUND$/ ],
# # NOTE: run clamd under the same user as amavisd, or run it under its own
# # uid such as clamav, add user clamav to the amavis group, and then add
# # AllowSupplementaryGroups to clamd.conf;
# # NOTE: match socket name (LocalSocket) in clamav.conf to the socket name in
# # this entry; when running chrooted one may prefer socket "$MYHOME/clamd".
ここを次のように書き換える。
### http://www.clamav.net/
['ClamAV-clamd',
\&ask_daemon, ["SCAN {}\n", "/var/amavis/var/clamd.socket"],
qr/\bOK$/, qr/\bFOUND$/,
qr/^.*?: (?!Infected Archive)(.*) FOUND$/ ],
# NOTE: run clamd under the same user as amavisd, or run it under its own
# uid such as clamav, add user clamav to the amavis group, and then add
# AllowSupplementaryGroups to clamd.conf;
# NOTE: match socket name (LocalSocket) in clamav.conf to the socket name in
# this entry; when running chrooted one may prefer socket "$MYHOME/clamd".
オリジナルでは clamd の CONTSCAN コマンドを使用しているが、ここでは SCAN コマンドを使用することにする。CONTSCAN は全てのウィルスを見つけようとするが、SCAN コマンドは一つ見つけたらそれでスキャンを終了する。このため感染しているかどうかだけを判定するには SCAN コマンドの方が速いからである。ここでは感染メールあるいはフィッシングメールはドロップする(ユーザに届かせない)方針なので、全てのウィルスを発見する必要は無い。
ここで定義したウィルススキャナー(amavisd 用の clamd)が何らかの理由で使えないときに備えて @av_scanners_backup という設定がある。@av_scanners で列挙したウィルススキャナーが全て使えないときにここに列挙されたものが使用される。これも同じように一旦全てをコメントにした上で ClamAV の設定を有効にする。他のウィルススキャナーが使えるのであればそれも有効にしておく。ClamAV の設定は一旦全てをコメントにした後なら次のようになっている。
# ### http://www.clamav.net/ - backs up clamd or Mail::ClamAV
# ['ClamAV-clamscan', 'clamscan',
# "--stdout --no-summary -r --tempdir=$TEMPBASE {}",
# [0], qr/:.*\sFOUND$/, qr/^.*?: (?!Infected Archive)(.*) FOUND$/ ],
ここのコメントを外して次のようにしておく。
### http://www.clamav.net/ - backs up clamd or Mail::ClamAV
['ClamAV-clamscan', 'clamscan',
"--stdout --no-summary -r --tempdir=$TEMPBASE {}",
[0], qr/:.*\sFOUND$/, qr/^.*?: (?!Infected Archive)(.*) FOUND$/ ],
編集が終わったら間違いがないかどうかをチェックするために amavisd をデバッグモードで起動する。
/usr/local/sbin/amavisd -c /usr/local/etc/amavisd.conf debug
特にエラーがレポートされないことを確認する。amavisd は ctrl-c をタイプして終了させる。
SpamAssasin のスパム判定のルールはシステムワイドのもの(/etc/mail/spamassassin/local.cf)とユーザ定義のもの(~/.spamassassin/user_prefs)があるが、ユーザへの負担を少なくするためにシステムワイドのルールをできるだけ強化しておく。このルールはかなり色々な記述ができる。ということはスパムを効率よく判定させるためにはかなりの構築が必要になる。幸いにも TLEC でよくできたファイルを配布している。これをベースにする。なお、デフォルトではユーザ定義のルールは無効になっている。
このファイルは作者がよく保守をして精度を上げている。その苦労を活かすためにも積極的に更新したい。そこで更新があったら自動でダウンロードし、必要と思われる変更を施す make ファイルを Makefile という名前で次の内容で作成する。作成する場所は /etc/mail/spamassassin である。
SRC_URL = http://tlec.linux.or.jp/docs/user_prefs
local.cf: TLEC.cf
[ -f '$@' ] && mv '$@' '$@.prev'
/bin/sed -e 's/^ok_languages/#ok_languages/' TLEC.cf > '$@'
echo 'report_safe 0' >> '$@'
/etc/rc.d/init.d/spamassassin restart
TLEC.cf::
@if [ -f '$@' ]; then \
echo curl --silent -z '$@' -o '$@' '$(SRC_URL)'; \
curl --silent -z '$@' -o '$@' '$(SRC_URL)'; \
else \
echo curl --silent -z '$@' -o '$@' '$(SRC_URL)'; \
curl --silent -z '$@' -o '$@' '$(SRC_URL)'; \
fi
インデントは TAB で行われていることに注意。ここで clamav-update を利用する手もあるのだが、それだとどんなに節約してもバージョン判定のために毎回 HTTP ヘッダだけは取得することになる。この make ファイルのように新しいものがあるときにだけダウンロードした方がネットワークとサーバに負荷をかけないで済む。
TLEC オリジナルでは日本語と英語のメッセージはスパムとしないとしているが、ここではこれらもスパム判定をするようにした。また、スパムと判定されたメッセージはデフォルトではスパム通知のメッセージの添付ファイルになって届けられるが、メッセージヘッダに“X-Spam-*”フィールドを追加するだけにして、それをどうするかはユーザのメーラーの設定に任せたい。そこで添付ファイルとして届けられるのではなくフィールドを追加するだけに変更するようにした。スパムと断定されたものは“X-Spam-Flag: Yes”が付くようになる。
この TLEK のファイルでは、信用するネットワークを設定する trusted_networks と自分が利用している private_pref というファイルで記述するようになっている。そしてこのファイルを /etc/mail/spamassassin に次の内容で作成する。
trusted_networks 127.0.0.1 設定中のメールサーバが所属する LAN のネットワークアドレス
replace_tag MYMTA (設定中のメールサーバ名にマッチする正規表現)
例えば次のようにする。
trusted_networks 127.0.0.1 192.168.48.0/24
replace_tag MYMTA ((mail|www)\.mydomain\.co\.jp)
そして上で作成した Makefile によって更新のチェックと更新が定期的に行われるようにする。sa-update というファイルを /etc/cron.weekly に次の内容で作成して実行パーミッションを付けておく。
#!/bin/sh
cd /etc/mail/spamassassin
make > /dev/null
spamassasin を rpm でインストールすると /etc/cron.d/sa-update という local.cf をアップデートするためのファイルが入っている。これはデフォルトではコメントだけなので、特に変更していなければ放置で構わない。
以上で spamassasin の設定が終わったのでこれの起動スクリプトを有効化し、起動する。
chkconfig spamassassin on/etc/rc.d/init.d/spamassassin start
ここではスパムメールや感染メールと判定されたメールの取り扱いについて /usr/local/etc/amavisd.conf を設定する。主に検討するべき箇所を列挙する。
次のような箇所である。
$sa_tag_level_deflt = 2.0; # add spam info headers if at, or above that level
$sa_tag2_level_deflt = 6.2; # add 'spam detected' headers at that level
$sa_kill_level_deflt = 6.9; # triggers spam evasive actions (e.g. blocks mail)
$sa_dsn_cutoff_level = 10; # spam level beyond which a DSN is not sent
# $sa_quarantine_cutoff_level = 25; # spam level beyond which quarantine is off
各項目の意味は次のとおり。
$sa_tag_level_defltこの値以上のスパムらしさを持つメッセージのヘッダにスパム判定の情報を付与する。ユーザがメーラのルールによって迷惑メールかもしれないと注意を始めるのがこのレベルである。逆に言うとこの値未満のものは普通のメールとしてユーザは安心して参照する。
$sa_tag2_level_deflt
この値以上のスパムらしさを持つメッセージのヘッダにスパムと断定したときのマークを付ける。ここでは後にこの値以上のメッセージを迷惑メールフォルダに直接配送するように設定する。ユーザが迷惑メールだと思って見もしないかもしれないのがこのレベルである。
$sa_kill_level_deflt
この値以上のスパムらしさを持つメッセージにスパムと断定されたときのアクションを実行する。例えばそのメールをブロックしたりする。
$sa_dsn_cutoff_level
この値以上のスパムらしさを持つメッセージは配送されない。したがってもし隔離するように設定したならば届いているはずの非迷惑メールが届かなかったらユーザからの問い合わせによって隔離ディレクトリから探し出すことになる。
$sa_quarantine_cutoff_level
この値以上のスパムらしさを持つメッセージは隔離すらされない。メッセージが全く残らないのでこれは設定しない方がよいと思う。
筆者の自宅では一年以上 SpamAssassin を運用している。スコア 2.0 未満でスパムらしさが付かなかったが迷惑メールだったものが約 2.1%、スコア 6.31 以上でスパムと断定されたが迷惑メールでなかったものが約 2.8% あった。迷惑メールでなかったもので最も高いスコアは 20.119 だった。つまりスコア 21 以下を $sa_dsn_cutoff_level や $sa_quarantine_cutoff_level に指定すると配送されない非迷惑メールが出てくる。スコアの分布から見て筆者は $sa_tag2_level_deflt は 8 あたりが適切ではないかと考えている。
スパム判定をするためにはメッセージの内容をスキャンすることになるのだが、メッセージが大き過ぎるとその処理コストを無視できなくなってくる。そこでスパム判定をするメッセージのボディの最大長が次のように設定されている。
$sa_mail_body_size_limit = 400*1024; # don't waste time on SA if mail is larger
ユーザが使用しているメーラが必ずしも柔軟な振り分けルールを実装してる訳ではない。そういうときに便利なのがスパムと断定されたメールの件名に付ける文字列を指定する機能だ。件名に目印があればそういうメーラでもユーザが到着メールの一覧を目視して判断できる。これが次のように設定されている。
$sa_spam_subject_tag = '***SPAM*** ';
しかし誤判定されたメールにもこれが付いてしまうと、それの返信をするときにうっかりこの文字列を付けたままにして失礼なことにもなってしまうかもしれない。
ここがポリシー上最も重要なところ。次のように設定されている。
# $final_virus_destiny = D_DISCARD;
# $final_banned_destiny = D_BOUNCE;
# $final_spam_destiny = D_BOUNCE;
# $final_bad_header_destiny = D_PASS;
上の例では全てコメントになっていてデフォルト値が指定されている。それぞれの意味は次のとおり。
$final_virus_destiny感染メールと判定されたメッセージの取り扱い。
$final_banned_destiny禁止メールと判定されたメッセージの取り扱い。
$final_spam_destinyスパムメールと判定されたメッセージの取り扱い。
ここが D_PASS 以外になっていると誤判定されたメールがユーザに届かないことになる。そうする場合はスパムと断定するための閾値をかなり高い値に設定しておくべきだろう。
$final_bad_header_destiny非 ASCII 文字などが含まれているなど不正なヘッダを持つメッセージの取り扱い。
D_BOUNCEそのメッセージは配送しないが、送信者に通知する。
D_REJECT
D_BOUNCE と同様だが、感染メールが大量に来ているときなどは送信者に通知しないらしい。
D_DISCARDそのメッセージは配送しないし、送信者に通知もしない。
D_PASSそのメッセージは配送する。
$banned_filename_re という指定で危険なタイプのファイルが添付されているメールなどが禁止されている。その設定の中で例えば Windows の実行ファイルが次のように設定されている。
qr'^\.(exe-ms|dll)$', # banned file(1) types, rudimentary
qr'.\.(pif|scr)$'i, # banned extensions - rudimentary
qr'^application/x-msdownload$'i, # block these MIME types
qr'^application/x-msdos-program$'i,
qr'^application/hta$'i,
qr'\.[^./]*[A-Za-z][^./]*\.\s*(exe|vbs|pif|scr|bat|cmd|com|cpl|dll)[.\s]*$'i,
qr'.\.(exe|vbs|pif|scr|cpl)$'i, # banned extension - basic
以上で amavisd の設定が一通り終わったので amavisd を起動しておく。
/etc/rc.d/init.d/amavisd start
一通り準備が整ったので MTA の Postfix に amavisd を使用させるための設定を行う。
まず amavisd を利用したサービスの定義を行うために /etc/postfix/master.cf に次の記述を追加する。
#
# Content Filter amavisd
#
smtp-amavis unix - - n - 2 smtp
-o smtp_data_done_timeout=1200
-o smtp_send_xforward_command=yes
-o disable_dns_lookups=yes
127.0.0.1:10025 inet n - n - - smtpd
-o content_filter=
-o local_recipient_maps=
-o relay_recipient_maps=
-o smtpd_restriction_classes=
-o smtpd_client_restrictions=
-o smtpd_helo_restrictions=
-o smtpd_sender_restrictions=
-o smtpd_recipient_restrictions=permit_mynetworks,reject
-o mynetworks=127.0.0.0/8
-o strict_rfc821_envelopes=yes
-o smtpd_error_sleep_time=0
-o smtpd_soft_error_limit=1001
-o smtpd_hard_error_limit=1000
そして今定義したサービスをコンテントフィルターとして使うようために /etc/postfix/main.cf に次の記述を追加する。
content_filter=smtp-amavis:[127.0.0.1]:10024
これで Postfix で amavisd が使われるように設定されたので Postfix を再起動する。
/etc/rc.d/init.d/postfix restart
ここまでで Postfix を通して配送されるメールのスパム判定と感染チェックが行われるようになったのだが、スパムと断定されたメールを受信者に送る設定にしている場合、ローカルユーザにはせめて最初から迷惑メールフォルダに置かれるようにしてきたい。そうすることで、ユーザは迷惑メールに埋もれてメールを見落としてしまうことが減るからである。
まず既存のユーザの迷惑メールフォルダを作る。そのために次の内容でシェルスクリプトを作成して実行する。これはシステムユーザではなく一般ユーザの Maildir がもしなければそれを作成し、その中の迷惑メールフォルダがなければ作成する。そして今後の新しいユーザのためにも、ホームディレクトリのひな形に同じ措置をしておく。ちょっと長いので mkjunkdir として作成しておいた。
#!/bin/sh
for user in `awk -F: '500 <= $3 && $3 < 65534 { print $1; }' /etc/passwd`
do
home=`awk -F: -v "user=$user" '$1 == user { print $6; }' /etc/passwd`
if [ \! -d "$home/Maildir" ]; then
mkdir -p "$home/Maildir/new"
mkdir -p "$home/Maildir/cur"
mkdir -p "$home/Maildir/tmp"
chmod -R 700 "$home/Maildir"
chown -R $user. "$home/Maildir"
fi
if [ \! -d "$home/Maildir/.Junk" ]; then
echo $user
mkdir -p "$home/Maildir/.Junk/new"
mkdir -p "$home/Maildir/.Junk/cur"
mkdir -p "$home/Maildir/.Junk/tmp"
chmod -R 700 "$home/Maildir/.Junk"
chown -R $user. "$home/Maildir/.Junk"
fi
done
if [ \! -d /etc/skel/Maildir ]; then
mkdir -p /etc/skel/Maildir/new
mkdir -p /etc/skel/Maildir/cur
mkdir -p /etc/skel/Maildir/tmp
chmod -R 700 /etc/skel/Maildir
fi
if [ \! -d /etc/skel/Maildir/.Junk ]; then
mkdir -p /etc/skel/Maildir/.Junk/new
mkdir -p /etc/skel/Maildir/.Junk/cur
mkdir -p /etc/skel/Maildir/.Junk/tmp
chmod -R 700 /etc/skel/Maildir/.Junk
fi
次にスパムと断定されたメールが迷惑メールフォルダに直接配送されるようにする。そのために procmail の設定ファイル /etc/procmailrc を作成し(デフォルトでは存在しない)、次の内容を記述する。
SHELL=/bin/bash
PATH=/usr/bin:/bin
DROPPRIVS=yes
MAILDIR=$HOME/Maildir
DEFAULT=$MAILDIR/
JUNK=$MAILDIR/.Junk/
#LOGFILE=$HOME/procmail.log
#VERBOSE=ON
:0
*^X-Spam-Flag: YES
$JUNK