ユーザ用ツール

サイト用ツール


serverapps:nginx:mailproxy

差分

このページの2つのバージョン間の差分を表示します。

この比較画面へのリンク

両方とも前のリビジョン前のリビジョン
次のリビジョン
前のリビジョン
serverapps:nginx:mailproxy [2017/07/10 07:21] – [install] hayashiserverapps:nginx:mailproxy [2023/08/07 04:14] (現在) – [このページについて] hayashi
行 1: 行 1:
 +====== mail_moduleによるMail Proxy ======
 +===== このページについて =====
 +
 +Nginxのsmtp proxyは送信用としては利用可能ですが、**自ドメイン宛のメール受信には利用できません**。((つか、してはならない))
 +
 +詳しくはQiitaに書いてみました[[http://qiita.com/Toshinori_Hayashi/items/825248e5d4641fb5e8c7|Nginxでsmtp proxyをしてはいけない]]
 +===== install =====
 +
 +[[serverapps:nginx|Nginxのインストールはこちら]]を参照ください
 +
 +なお、以下のオプションをONにしています。
 +
 +  * MAIL_IMAP
 +  * MAIL_POP3
 +  * MAIL_SMTP
 +
 +
 +===== /usr/local/etc/nginx/nginx.conf =====
 +
 +<code>
 +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;
 +
 +  }
 +
 +}
 +</code>
 +
 +===== 認証:auth.php =====
 +<code php>
 +<?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();
 +
 +?>
 +</code>
 +
 +やっていることはシンプルで、Nginxから引き渡されたユーザ名やPasswordを使用してDBのPassと照合、マッチしていれば'Auth-Status: OK'とメールサーバをかえします。
 +ここでは、DBですがLDAPなどでも流れは一緒です。
 +
 +
 +===== メールの受信 =====
 +
 +メールの送信はできましたので、ここで受信側を考えます。\\
 +当然ほかのメールサーバはログインのための情報を持っていませんので、別ポートで認証なしで受信できるよう設定します。\\
 +通常の場合Postfixは認証を経ていなくても、自ドメイン宛のメールについては受け入れるという設定がされています。\\
 +しかしながら、今回のケースではNginx経由での接続が**適切な認証を経たものかをPostfix側で知ることはできません**。
 +
 +よって、前段で書いた通りPostfixはこの別ポートからの接続を**認証を経たものとして無条件に受け入れます**。\\
 +受信用ポートを通して接続された場合、Postfixは認証を経たものとして無条件に受け入れるため、結果として自ドメイン以外宛のメールであっても受け入れてしまいます。
 +
 +**オープンリレー**の出来上がりです。orz\\
 +
 +
 +===== 参考 =====
 +
 +[[https://www.nginx.com/resources/admin-guide/mail-proxy/|CONFIGURING NGINX AS A MAIL PROXY SERVER]]
 +
 +[[http://qiita.com/ma3ki/items/ce458f010a732af00179|nginxでメールサービス(SMTP,POP,IMAP)をproxyする]]
 +
 +[[http://irico.net/memo/articles/20150107-nginx-mail-proxy.html|nginxをSMTP Proxyとして使う - まっしろなめも帳]]