概要

postfix + authは若干敷居が高く、また、「SMTP(25)は受信専用、SMTPS(465)は認証付きの送信専用」 という風に用途を分けたい場合、構築に手間がかかる。

検証用ドメインを外に晒して遊ぶ場合、なるべく手間を省きたい。

そこで「SMTPSをnginxで受けて、認証が通ればlocalの25番に接続させる」という方法ができないか、 実際にnginxのSMTP proxyを用いて実践してみた。

方法

まずはnginxをinstallする。

今回使うのはnginxのluajit/ssl/smtpを用いる為、/etc/portage/make.confに以下のフラグを追記する

USE="luajit ssl ..."
NGINX_MODULES_MAIL="smtp" 

nginxをemergeする。

 # emerge -av nginx
[ebuild N      ] www-servers/nginx-1.7.6  USE="http http-cache ipv6 luajit pcre ssl -aio -debug -libatomic -pcre-jit -rtmp (-selinux) -vim-syntax" NGINX_MODULES_HTTP="access autoindex browser charset echo empty_gif gzip lua map memcached proxy referer rewrite upstream_ip_hash -addition -ajp -auth_basic -auth_pam -auth_request -cache_purge -dav -dav_ext -degradation -fancyindex -fastcgi -flv -geo -geoip -gunzip -gzip_static -headers_more -image_filter -limit_conn -limit_req -metrics -mogilefs -mp4 -naxsi -perl -push_stream -random_index -realip -scgi -secure_link -security -slowfs_cache -spdy -split_clients -ssi -sticky -stub_status -sub -upload_progress -upstream_check -userid -uwsgi -xslt" NGINX_MODULES_MAIL="smtp -imap -pop3" 0 KiB

/etc/nginx/nginx.confにmail moduleの設定を追加する。

mail {
        ssl_certificate      /etc/nginx/hogehoge.crt;
        ssl_certificate_key  /etc/nginx/hogehoge.key;

        smtp_auth         plain;

        server {
                listen   465;
                listen   [::]:465;

                auth_http         127.0.0.1:8080/smtp;

                protocol smtp;
                xclient  off;
                proxy    on;

                ssl on;
        }
}

また、httpモジュール + Luaで認証機構を用意する

http {
        ...

        server {
                listen 127.0.0.1:8080 default_server;
                server_name _;

                keepalive_timeout 0;

                location /smtp {

                        header_filter_by_lua '

                        local method  = "";
                        local user    = "";
                        local passwd  = "";

                        local h = ngx.req.get_headers();

                        for k, v in pairs(h) do

                                k = string.lower(k);

                                if     k == "auth-method" then
                                        method = v;
                                elseif k == "auth-user" then
                                        user   = v;
                                elseif k == "auth-pass" then
                                        passwd = v;
                                end
                        end

                        if method == "plain" and user == "username" and passwd == "password" then
                                ngx.header["Auth-Status"] = "OK"
                                ngx.header["Auth-Server"] = "127.0.0.1"
                                ngx.header["Auth-Port"]   = "25"
                                ngx.header["Auth-User"]   = ""
                                ngx.header["Auth-Pass"]   = ""
                                ngx.header["Auth-Method"]   = "none"
                        else
                                ngx.header["Auth-Status"] = "Invalid login or password"
                                ngx.header["Auth-Wait"]   = "3"
                        end
                        ';

                        content_by_lua '
                                ngx.say("");
                        ';
                }
        }
}

起動

nginxの自動起動登録を行う

 # rc-update add nginx default

nginxを起動する

 # rc-service nginx start

テスト

AUTH PLAIN用の文字列を生成する。

 # echo -ne '\0username\0password' | base64

生成した文字列を用いて、SMTPSのテストを行う。235 2.0.0 OKが帰ってきたら成功。

 # openssl s_client -connect localhost:465 -crlf
 ...
 (中略)
 ...
 ---
 220 localhost ESMTP ready
 EHLO test
 250-localhost
 250 AUTH PLAIN
 AUTH PLAIN AHVzZXJuYW1lAHBhc3N3b3Jk
 235 2.0.0 OK
comments powered by Disqus
カテゴリ
タグ
月別アーカイブ