これまで私が仕事で扱うメールサーバ環境はqmail+vpopmailによるヴァーチャルドメイン環境がほとんどでした。
 接続元をほぼ制限できることが多いのでIP単位での制限を実行。代わりにSMTP認証等は用いず、必要に応じてPOP before SMTPで対応、といったどっちかつーと古めの環境です。利点と言えばqmailのセキュリティ性及びMaildir管理、vpopmailによるOSのアカウントによらないドメイン&ユーザ管理。時折IMAPが必要な場合にこれらと相性のよいCourier-IMAPを組み合わせてました。

 ですがまあ世の中的にもう古いですよね、そして上記利点は既に他の環境でも実現可能っぽい。
 最近サーバの置き場をクラウドに移行する話が出たため、ここらでプラットフォームを最新に置き換えるのもアリかなと、Redhat系ディストリで標準と化したPostfix+Dovecotに移行できないかと検討をしてみました。

 ただ、ここで前提条件として2件。
 1つは「vpopmailで管理していたユーザアカウントは全て無変更で移行したい」。メールアカウントは当然の事として一度パスワードをリセットして再設定したもらう、などとゆー手間も省きたい。ユーザは、少なくともメーラーのサーバ設定をFQDNで設定していれば、若干のダウンタイムのみで後はほぼそのまま使えるようにしたい。
 そしてもう1つは「qmail、vpopmailは(最終環境では)インストールしない」。Courier-IMAPと連携させてたときもそうだったのですがユーザ、メールの管理はvpopmailが行い、認証系とアクセスをCourierに任せるとゆー動きをしてました。ただコレだと「新しいプラットフォームに置き換えたい」とゆー要望を満足しない。データはvpopmail等のをそのまま利用するのはアリとしても、ソフトウェアとしてqmail、vpopmailをインストールはしない方向で。

 あちこち調べてみるとPostfix+Dovecotのみでヴァーチャルドメイン環境を実現することは可能。またDovecotとvpopmailを連携させることも可能。でも後者はvpopmail(果てはqmail)のインストールが必須。試しに一度Dovecotのvpopmailオプション付きリビルドを試みましたが、リビルド時にvpopmailのライブラリ・ヘッダ情報の読み込みが必須だったので断念。まあ他の環境からライブラリとかだけコピーする、インストール後に削除するとかの手も可能だったかもしれないけど、以後のメンテナンス性を考えると多分あんまり意味ないだろうなぁということで断念。
 次にvpopmailの、いわゆる「vpasswd」をDovecotの管理形式にコンバートする手法はないのかなと探したものの、そんなマイナーな事をしたがる人はいないためか情報無し(苦笑)。

 じゃあ、何かしらvpopmailとDovecot間でユーザ情報の中継をする手法は無いものか。…こう考えれば「データベースを経由すればいいんじゃね」とゆー案にたどり着きます。cdbとかで独自管理してる各ツール独自のユーザアカウント情報にはイマイチてを出しづらいけど、汎用DBに書かれてしまえば検索側の設定、もしくはデータコンバートもSQLでできるんじゃないか。
 PostfixやらDovecotやらはさすがに割りと新しい?ものだけあってDB連携の手法が数多く見つかります。そして「そういやvpopmailもPostgreSQL連携手法があったよな、やったこと無いけど」。

 上記をまとめて、

 1.「仮環境」としてPostgreSQLオプション付きvpopmail環境を構築する。
 2.上記「仮環境」に移行対象のvpopmail管理情報を複製→DB化。
 3.「仮環境」のユーザデータをエクスポート→「新環境」にインポート。

 することで、Postfix、Dovecotがその情報を閲覧することはできないかなぁと。
 てことで試しました。
 なお下記の各手順はある程度記憶の元に書かれているのでテキトーに端折られてる恐れがあります。PostgreSQLのユーザ設定周りとか。その辺他のサイトさんなんかも参照にして下さい。

 まず「1.」のように新規サーバに「--with-pgsql」オプション付きのqmail+vpopmail環境を構築します。…この辺別に新規環境である必要はなく、そもそもpgsqlオプション付きで使ってれば、更に言えば既にvpopmailの頃からpgsql経由で使ってれば別途新規に作成する必要はありません。
 私の場合pgsqlオプション付きのメールサーバは一台も無かった・ユーザが利用中などなどから新規に作った方が安全かつ手っ取り早かったとゆーだけです。

 次に「2.」の環境移行。
 その前に新規でサーバ作った場合、移行対象となるヴァーチャルドメインは仮環境のvpop系コマンドで作成します。既存環境のコピーだけだと足りない情報があるような気がするし、そもそもqmail側の情報が更新されないので。
 ドメインを作ったら、既存環境の「~domains/[移行対象ドメイン]」を丸々複製。
 次にPostgreSQLの調整…なんですか新規テーブル作成とかは必要なく、pg_hba.conf等でローカルかrなお接続だけtrustにしておきます。
 ここまで済んだらvpasswd→PostgreSQL移行コマンド「vconvert」を実行。

 例:vconvert -c -m [移行対象ドメイン]

 「-c」はvpaswd.dbから、「-m」はSQLに、を意味します。また全ドメインを移行対象とする場合は移行対象ドメインの指定は不要なようです。
 コマンドが正常に成功するとPostgreSQL上にDB「vpopmail」が作成されます。中のテーブルはこんな感じ。

vpopmail=# \d
            List of relations
 Schema |    Name     | Type  |  Owner  
--------+-------------+-------+----------
 public | dir_control | table | postgres
 public | vpopmail    | table | postgres

 vpopmail=# \d dir_control
            Table "public.dir_control"
    Column    |          Type          | Modifiers
--------------+------------------------+-----------
 domain       | character varying(96)  | not null
 cur_users    | integer                |
 level_cur    | integer                |
 level_max    | integer                |
 level_start0 | integer                |
 level_start1 | integer                |
 level_start2 | integer                |
 level_end0   | integer                |
 level_end1   | integer                |
 level_end2   | integer                |
 level_mod0   | integer                |
 level_mod1   | integer                |
 level_mod2   | integer                |
 level_index0 | integer                |
 level_index1 | integer                |
 level_index2 | integer                |
 the_dir      | character varying(160) |
Indexes:
    "dir_control_pkey" PRIMARY KEY, btree ("domain")

vpopmail=# \d vpopmail;
               Table "public.vpopmail"
     Column      |          Type          | Modifiers
-----------------+------------------------+-----------
 pw_name         | character varying(32)  | not null
 pw_domain       | character varying(96)  | not null
 pw_passwd       | character varying(40)  |
 pw_uid          | integer                |
 pw_gid          | integer                |
 pw_gecos        | character varying(48)  |
 pw_dir          | character varying(160) |
 pw_shell        | character varying(20)  |
 pw_clear_passwd | character varying(16)  |
Indexes:
    "vpopmail_pkey" PRIMARY KEY, btree (pw_domain, pw_name)


 このうち、テーブル「vpopmail」に各ユーザアカウント情報が保存されます。このデータをPostfix、Dovecotが読めるかがポイント。
 DBの内容をまとめてダンプします。

 pg_dump vpopmail > vpopmail.dmp
 
 ダンプデータを移行対象の新環境に複製します。
 で、その前に新環境ではPostfix+Dovecot+PostgreSQLの環境がそれぞれ整ってる必要があります。その辺は詳しいサイトさんが他にいるので割愛しますが、とりあえずCentOS5系列の場合標準のPostfixだとDB未対応版なのでちょっと手を入れる必要が発生します。
 さて新環境のPostgreSQLに上記ダンプデータをインポートします。

 createdb vpopmail
 psql vpopmail < vpopmail.dmp


 ちなみに今更ですがPostgreSQL上のユーザはスーパーユーザであるところのpostgresでやってます。ホントはReadWriteとか厳密に考えて作るべきでしょうが、今は検証段階とゆーことで割愛します。

 また、新環境におけるドメイン、Maildirの保存環境は従来のvpopmailと同様「/usr/local/vpopmail/domains」の下とします。別にこれは変更しても構いませんが、DBの値も合わせて書き換える必要があるので好みに応じて。
 で、既存メールサーバのdomains配下を新規環境下にコピーします。とりあえず属性維持コピーを行なって、uid:8001、gid:8000とします。

 さてここまで整えばPostfix、Dovecotからデータが読めるか検証できます。
 まずPostfix。とりあえずヴァーチャル系の設定を一通り行った事を前提とした上で、メールボックス系の情報をPostgreSQLから読めるように変更します。
 ざっと変更したのはmain.cfの以下の所。

virtual_mailbox_maps = pgsql:/etc/postfix/pgsql_vmailbox.cf
virtual_mailbox_domains = pgsql:/etc/postfix/pgsql_virtualdomain_pa.cf
#virtual_alias_maps = pgsql:/etc/postfix/pgsql_virtual.cf
local_recipient_maps = pgsql:/etc/postfix/pgsql_vmailbox.cf
virtual_mailbox_limit_maps = pgsql:/etc/postfix/pgsql_vquota.cf


 このうち「virtual_alias_maps」がコメントになってる理由は後述します。
 とりあえず普段は「hash:~」とかで自前DBで管理してるところをpgsqlを読むように変更した上で、それぞれの設定を別ファイルで編集します。
 例えばユーザアカウントそのもの系であるところの「pgsql_vmailbox.cf」の場合、

hosts = localhost
user = postgres
password =
dbname = vpopmail
query = SELECT substr(pw_dir,length('/usr/local/vpopmail/'))||'/Maildir/' as maildir FROM vpopmail WHERE pw_name = '%u' and pw_domain = '%d'


 てな感じにすればテーブル「vpopmail」のユーザアカウント情報を元にヴァーチャルメールボックスを検索してくれます。
 上記を見れば分かりますがmain.cfの「virtual_mailbox_maps」が期待する戻り値は指定されたメールアドレスに対する保存先フォルダです。ただここでちと面倒な話がありまして、テーブル「vpopmail」中のメール保存フォルダを指定するカラム「pw_dir」は「/」からのフルパスで書いてあります。しかしPostfixでヴァーチャルドメインを指定する場合、その更に上位フォルダを指定するパラメータ「virtual_mailbox_base」が必須項目となっているようで無視できません。つまりSQLは「virtual_mailbox_base」を取り除いたパスを取得する必要があり、そのためわざわざ取得文字列の左側と取り除き、且つvpopmailに指定されたパスでは足りない「/Maildir/」をプラスしています。
 面倒ですが逆の見方をすればこの辺の制御を自由にできるので各ソフト間の連携が容易であるとも言えるわけです。一度設定してしまえばそこまでですし。
 他の検索系の設定ファイルも似たような手法で調整します。ここでは長くなるので割愛します。

 次にDovecotです。Dovecotもある意味似たような感じです。
 まずはdovecot.confを編集します。今回は検証のために認証プロトコルを

 protocols = pop3

 に限定します。しなくてもいいとは思いますが。
 次に認証方法を編集します。
 まず今回はSQL認証に限定するので標準で開いている「passdb pam」をコメントアウトします。ここの閉じかっこがちょっと離れた位置にあるのでそちらのコメント化も忘れないように。
 そして逆に「passdb sql」のコメントアウトを外し、SQL用設定ファイルを指定します。

  passdb sql {
    # Path for SQL configuration file, see doc/dovecot-sql-example.conf
    args = /etc/dovecot-sql.conf
  }


 似たような感じでuserdbの値も変更します。

  userdb sql {
    # Path for SQL configuration file, see doc/dovecot-sql-example.conf
    args = /etc/dovecot-sql.conf
  } 


 さて次に肝心の「dovecot-sql.conf」を作成するわけですが、上記コメントにもあるようにサーバ内を探すとサンプルファイル「dovecot-sql-example.conf」がありますのでそちらをベースに編集します。
 まず接続するDBを指定します。

driver = pgsql

 次に接続条件。下記には環境によっては「password=xxxx」を追加する必要があるでしょう。

connect = dbname=vpopmail user=postgres

 次にメールアカウントパスワード検証時の方式を指定します。
 vpopmailの場合、バージョンによってパスワードの暗号化形式が若干異なるのですが、とりあえず私の環境では混在してても下記のみで対応できておりました。

default_pass_scheme = CRYPT


 次にパスワード用クエリ。ここではユーザIDとそのパスワードを取得するようになっています。またこの場合のユーザIDは基本的にメールアドレス「user@domain」形式になりますので、vpopmail形式の場合文字列連結を行う必要があります。

password_query = SELECT pw_user||'@'||pw_domain as user, pw_passwd as password FROM mailbox WHERE pw_name = '%n' and pw_domain = '%d'

 次に各ユーザの保存環境クエリ。ここでは保存先フォルダの他、各ファイル・フォルダを制御するuid、gidを指定します。各ユーザをバラバラにすることもできますが、今回の場合vpopmailの元設定であるところの8001:8000を指定します。

user_query = SELECT pw_dir as home, 8001 as uid, 8000 as gid FROM vpopmail WHERE pw_name = '%n' and pw_domain = '%d'

 ここまで設定してPostfix、Dovecotをそれぞれ再起動すればメールの受信やPOPによる取得が可能になってる…ハズです。ダメだったらmaillogを参照にレッツデバッグ。


 さて。
 ここまでは「PostgreSQL中のvpopmail環境をそのまま移行してPostfixとかDovecotから使えるか」の検証でした。より正確に言えば「vpopmailの挙動で作られたテーブル情報をSQLとかの設定をいじることでPostfix、Dovecotからそのまま検索することができるか」の実験でした。
 つまるところ必要な情報さえ揃っていればテーブルの構造は問わないとゆーことです。

 そしてこのままだとぶちゃけ実用的ではありません。
 ユーザの追加変更削除、ドメインの追加変更削除を行うのにいちいちSQLを発行する必要があるからです。まあPostfixとDovecotを別々に管理する手間に比べれば一発で済んで楽と言えば楽なんですけどね。
 でもここでもう1段楽にするためにPostfixの定番管理ツール「postfixadomin」を使うことにします。
 ご存知の通りpostfixadminはmysql経由でPostfixのアカウント管理を行うPHPのセットですが、DBはPostgreSQLを参照することもできます。
 ただ、postfixadminは自前のテーブル構造を前提としており、先にやったようにある特定のテーブル構造に合わせるような事はできません。まあソースいじればできるでしょうけど当然面倒なんでやりません。
 であればむしろDB「vpopmail」の内容を「postfixadmin」の構造に置き換えてしまえば良いわけです。

 まずpostfixadminをインストール&初期設定します。ここんとこ面倒なんで割愛(笑)。他のサイトさんを参考にして下さい。
 さあpostfixadminが入りましたw
 まずドメイン設定をGUI経由で行なって下さい。その方が後腐れが無いと思われます。
 次に初期設定まで無事済んでいればPostgreSQL上にDB「postfix」ができているハズ。ここに先のダンプデータをインポートします。

 psql postfix < vpopmail.dmp

 DB「postfix」内にテーブル「dir_control」と「vpopmail」ができます。
 さて、postfixadminがユーザ管理に必要とするテーブルは「alias」と「mailbox」。aliasはその名の通りエイリアスを入れるものなハズですが、どうもローカル配送用に自分自身の記述も必要としている様子。mailboxはユーザアカウントやパスワード、保存フォルダを設定しておく核となるテーブルです。
 テーブル「vpopmail」の内容を上記2テーブルにそれぞれカラムを合わせつつ、且つ形式を合わせつつコピーします。とは言え基本的には以下のSQLで大丈夫かと。

○mailbox移行用
insert into mailbox select (pw_name||'@'||pw_domain),pw_passwd,pw_name,substr(pw_dir,length('/usr/local/vpopmail/domains/')+1)||'/',cast(pw_shell as int),NULL,NULL,true,pw_domain,pw_name from vpopmail

○alias移行用
insert into aliase select (pw_name||'@'||pw_domain),(pw_name||'@'||pw_domain),pw_domain,NULL,NULL,true from vpopmail

 ユーザアカウントは「user@domain」型に連結。登録時間とか持ってないデータはNULLで問題なし。でも一部not NULLがあるので適当に代入。一方でquota情報は型変換でint型に、といった感じ。

 次にPostfix、Dovecotの各Pgsql参照設定をpostfixadmin用に変更。

例:pgsql_vmailbox.cf
query = SELECT ('domains/'||maildir||'Maildir/') as maildir FROM mailbox WHERE username = '%s'

例:dovecot-sql.conf
password_query = SELECT username as user, password FROM mailbox WHERE username = '%u'
user_query = SELECT '/usr/local/vpopmail/domains/'||maildir as home, 8001 as uid, 8000 as gid FROM mailbox WHERE username = '%u'


 またPostfixは上の方でコメント化していた「virtual_alias_maps」をpostfixadminのテーブル形式に合わせて作成する必要があります。vpopmailテーブル形式だとエイリアスに関する情報が無かったので手が出せなかったのですがこれ以降は管理できます。
 Postfix&Dovecot再起動。
 以上でvpopmailのMaildir環境のまま、Postfix&Dovecotを利用し、且つユーザ制御をpostfixadminで行えるようになります。新規ユーザ作成も可能。


 なお実際の所上述したユーザアカウント以外の所にも手を入れなきゃいけないところがあります。
 まずPOP before SMTP。古い発想のためかPostfix+Dovecot単体では実現できないようです。私は「DRAC」を経由することにしましたが、実の所せっかくDBでPostfix+Dovecot間の連携が出来てるんだから今更他のツール、DB使わなくても接続IP情報とかもDB経由で処理できるんじゃねーかとか思わなくもありません。これは後の検討課題。
 そしてもうひとつエイリアス。vpopmailの場合各ユーザ毎のエイリアスは「.qmail-[ユーザ名]」で管理されています。これは何かしら自前でコンバートするしか無い。postfixadominでがりがり書いてくのもアリですが、CSVファイルかなんかにまとめて、テーブル「alias」に叩き込んだ方が安全かつ早いと思われます。
 他にも旧来tcpserver.dで管理していた接続許可元設定なんかもDB化できますので必要に応じて手を加えると良いでしょう。

 まーこんなマネは過渡期の一時的なものなのでしばらくすれば不要な手順になるわけですけどね。 基本的にはpostfixadminのテーブル構造さえ押さえておけばなんでもできるんじゃないでしょうか。


2012-06-11 [技術]