Nginxのsmtp proxyは送信用としては利用可能ですが、自ドメイン宛のメール受信には利用できません。1)
詳しくはQiitaに書いてみましたNginxでsmtp proxyをしてはいけない
mail { auth_http authserver/mailauth/auth.php ; proxy on; proxy_pass_error_message on; #ssl_certificate /usr/local/etc/acme/SSL/fullchain.pem; #ssl_certificate_key /usr/local/etc/acme/SSL/privkey.pem; #ssl_protocols TLSv1.2; #ssl_session_cache shared:MAIL:10m; smtp_capabilities PIPELINING 8BITMIME "SIZE 20480000" DSN; #pop3_capabilities TOP USER UIDL; #imap_capabilities IMAP4rev1 LITERAL+ SASL-IR LOGIN-REFERRALS ID ENABLE IDLE AUTH=LOGIN; smtp_auth plain login; # SMTP server { listen 25; protocol smtp; xclient off; auth_http_header PORT 25; error_log /var/log/nginx/mail-error.log; } }
<?php // set $env from nginx $env['user'] = getenv('HTTP_AUTH_USER'); $env['passwd'] = getenv('HTTP_AUTH_PASS'); $env['salt'] = getenv('HTTP_AUTH_SALT'); $env['proto'] = getenv('HTTP_AUTH_PROTOCOL'); $env['method'] = getenv('HTTP_AUTH_METHOD'); $env['attempt'] = getenv('HTTP_AUTH_ATTEMPT'); $env['client'] = getenv('HTTP_CLIENT_IP'); $env['host'] = getenv('HTTP_CLIENT_HOST'); $env['port'] = getenv('HTTP_PORT'); // proxy port map $portmap = array( "smtp" => 587, "pop3" => 110, "imap" => 143, ); // protocol map $protomap = array( "995" => "pops", "993" => "imaps", "110" => "pop", "143" => "imap", "587" => "smtp", "465" => "smtps", ); // MySQL DB $dbhost = "DBHOST"; $dbname = "postfix"; $dbuser = "postfix"; $dbpass = "DBPASSW0RD"; $dsn = "mysql:host=$dbhost;dbname=$dbname;charset=utf8"; $user = rtrim($env['user']) ; $passwd = rtrim($env['passwd']) ; $proxyhost = getenv('SERVER_ADDR'); $myaddr = getenv('SERVER_ADDR'); $proxyport = $portmap[$env['proto']]; // DB Access try { $pdo = new PDO($DSN, $dbuser, $dbpass,array(PDO::ATTR_EMULATE_PREPARES => false)); } catch (PDOException $e) { $log = 'Dadabase connection failure. '.$e->getMessage(); openlog("nginx-proxy-auth", LOG_PID , LOG_MAIL); syslog(LOG_INFO,"$log"); closelog(); exit($log); } $sql="SELECT password FROM mailbox WHERE username = '$user' AND active=1;"; $stmt = $pdo->query($sql); $row = $stmt -> fetch(); $hashpass = $row["password"]; $cmd = "/usr/local/bin/doveadm pw -p '$passwd' -t '$hashpass' | /usr/bin/sed -r 's/.*(verified))$/\\1/'"; $result = rtrim(shell_exec($cmd)); $log = sprintf('user=%s, client=%s, proto=%s', $user, $env['client'], $env['proto']); if ( $result === 'verified' ) { $log = sprintf('proxy=successful, %s, connect=%s:%s', $log, $proxyhost, $proxyport); header('Content-type: text/html'); header('Auth-Status: OK') ; header("Auth-Server: $myaddr") ; header("Auth-Port: $proxyport") ; } else { $log = sprintf('proxy=failure, %s, passwd=%s', $log, $passwd); header('Content-type: text/html'); header('Auth-Status: Invalid login') ; } // write syslog openlog("nginx-proxy-auth", LOG_PID , LOG_MAIL); syslog(LOG_INFO,"$log"); closelog(); ?>
やっていることはシンプルで、Nginxから引き渡されたユーザ名やPasswordを使用してDBのPassと照合、マッチしていれば'Auth-Status: OK'とメールサーバをかえします。
ここでは、DBですがLDAPなどでも流れは一緒です。
メールの送信はできましたので、ここで受信側を考えます。
当然ほかのメールサーバはログインのための情報を持っていませんので、別ポートで認証なしで受信できるよう設定します。
通常の場合Postfixは認証を経ていなくても、自ドメイン宛のメールについては受け入れるという設定がされています。
しかしながら、今回のケースではNginx経由での接続が適切な認証を経たものかをPostfix側で知ることはできません。
よって、前段で書いた通りPostfixはこの別ポートからの接続を認証を経たものとして無条件に受け入れます。
受信用ポートを通して接続された場合、Postfixは認証を経たものとして無条件に受け入れるため、結果として自ドメイン以外宛のメールであっても受け入れてしまいます。
オープンリレーの出来上がりです。orz