それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

Postfixが ssh ログインして、メールをリレー配送する設定を入れる。

動機: ssh 経由でsendmail を使えると気づいたので応用してみた。

Dockerや仮想マシンを起動でメール設定が億劫だし、postfixのsmartリレーを設定が面倒。Gmail送信するとgoogle アカウントの規制が多い。何度もパスワードを保存設定をするのが面倒だった。sendmailssh 経由で使えることに気づいたとき、メール送信テストで、メールサーバーをいくつ起動しようが、ssh ログインでどっかのPostfixに集約したらいいじゃないかと気づいた。

ローカル postfixsshさせ、SSHで別サーバーからメール送信させたい。

得られるメリット

メール送信は格段に便利になる。

1つのPostfixSSH経由で使い回す。

VPS として使ってるサーバーはpotfix導入済みですね。この vps をポート開放やリレー設定をせずに使いたい。テストサーバーのPostfixのメール送信は、SSH経由でVPSPostfixを利用すればいい。 VPSはポート25から手軽にメールを送信できるのだから、新規でインストールするPostfixVPSSSH sendmail でメールを送信すればいいじゃないか。

root@vps:~# apt list postfix* --installed
Listing... Done
postfix/focal-updates,now 3.4.13-0ubuntu1 amd64 [installed]

Dccker のインスタンスを増やしたり、仮想マシンを増やしているとメール設定と配送テストが億劫になる。億劫だからといって全く設定しないと使えないサービスもある。なので、HostAはすべてのメールを HostB 経由でで送ればいいわけである。 しかし、メールのリレーだとかPostfixのあれこれは覚えたくないのである。そこで、もっとかんたんな方法がないか模索したわけである。

設定と覚えることがシンプル

postfixのことは殆ど知らなくていいのである。ssh接続先に sendmailが動く環境さえあればいい。

パスワードを平文保存しなくていい。

postfix にパスワードを平文保存するための、dockerfileの設定をどうするかと、などを考えなくていい。不要になれば 公開鍵のアクセス許可を抹消すればいい。

ポート開放などに悩まなくていい。

メール送信のサブミッションポートだとかOP25Bとか考えなくていい。22番へ接続してsendmailを起動、メールを配送するだけなのだから。

設定の概要

テストをするにあたり、次のような構成を考えた。

HostA ( postfix) ---ssh----> HostB (postfix  sendmail)-smtp--> gmail smtp など

ssh 関連の設定がちゃんとできるなら使えるはずだ。

  • HostA ( postfix をインストールしたが、自身は外部へ送信しない。
  • HostB ( postfix をインストール・設定済サーバ、smart-replay で外部へ送信する)

HostA Postfixは メール送信を ssh HostB sendmail -i で丸投げ。HostB Postfixは smartリレーで外部のSMTP(Google/Gmail)などへ丸投げ。こうすることとにする。

ssh を使ってメールを送信

HostBのsendmail は、実はSSH経由で呼び出すことができる。

hostBから HostAの sendmail を起動してメール送信

cat sample-mail.txt | ssh HostB sendmail -i -t 

ローカルの場合。

自ホストにpostfixが導入され設定済みであれば、ローカルのpostfix を経由してsendmail でメール送信が可能。

次のように、ローカルのUNIXソケットを使って sendmailコマンドを起動したら終了である。

cat sample-mail.txt | sendmail -i -t 

この、sendmail コマンドは、ssh 経由でも起動することができるので、とてもかんたんに sendmail を使うことができる。

ぶっちゃけ、php だとか、wordpressだとか、python だとかを開発環境で動かす際のメール配送はこれでほとんどが解決する。送信メールコマンドを /usr/sbin/sendmail から ssh hostB /usr/sbin/sendmail に設定を変えれば済むのだから。

ただ、仮想マシンやコンテナだとそうもいかないので、postfixを設定しssh 経由で丸投げすることにする。

postfixssh 経由で sendmail へ転送する。

postfix は メールの配送をいろいろなやりかたで転送することができる。 古えのメーリスだとか、ローカル配送だとか、LAN内で配送とか、部署ごとに配送とかできるわけである。

その一つが postfixのpipe である。すでにpipeがあるんだから、postfix が、 sshコマンドで外部sendmail を呼び出せば設定はとてつもなく簡単になるはずである。

HostA の Postfixssh hostB sendmail を実行させメール配送させる

HostA ( postfix) ---ssh----> HostB (postfix  sendmail)-smtp--> gmail smtp など
  • HostA ( postfix をインストールしたが、自身は外部へ送信しない。
  • HostB ( postfix をインストールしサーバ、smart-replay で外部へ送信する)

これをやる方法が transport service 定義である。

master.cf

postfix のmaster.cf に次の行を追記する。

ssh-relay unix    -       n       n       -       -     pipe
  user=takuya argv=/usr/bin/ssh HostB /usr/sbin/sendmail -i $recipient

main.cf

main.cf 設定に、次の1行を加え、postfix の転送をすべて ssh-relay 経由にする。default_transport を記述すればオッケ

default_transport = ssh-relay

反映

あとは postfix をリロードするわけである。

$ systemctl restart postfix

テスト

cat sample-mail.txt | sendmail -i -t 

これで、メールはPostfixから、ssh のコマンドパイプ(pipe)へ転送され、HostB側で送信処理される。

設定の記述量も極小であり、SSHのポートと公開鍵認証だけを意識すれば解決である。ウルトラシンプルである。

公開鍵の設定。

postfix のmaster.cf に追記した箇所を見てみる。

ssh-relay unix    -       n       n       -       -     pipe
  user=takuya argv=/usr/bin/ssh HostB /usr/sbin/sendmail -i $recipient

ここでは、どのようにメールを配送するのか書いてある。 unix ソケットで受け付けて pipeながす。

pipe の先に ssh コマンドを起動する。起動するコマンドは ssh コマンドで sshがHostBでリモートsendmail を起動する。

とくに、難しいことはない。

ただし、公開鍵認証でコマンドが実行できる必要がある。

hostA に takuya ユーザーを作成し、hostB へ鍵を登録する。

root@hostB:/root $ adduser takuya
root@hostB:/root $ su takuya
takuya@hostB:~ $ ssh-keyen -t rsa 
takuya@hostB:~ $ ssh-copy-id hostA

公開鍵の登録をすれば、ssh 経由で sendmail が呼び出せることを確認しておく

takuya@hostB:~ $ cat - | ssh hostA /usr/sbin/sendmail -i -t 
To:takuya@example.com
From:takuya@example.com
Subject: relay test


hello from HostA via ssh HostB

メールが無事に配送されることを確認する。あとは hostA の postfix にローカルからの sendmail コマンドでSSH経由させるだけである。 楽である。

この設定を作ったときに躓いたポイント。

ユーザーの秘密鍵パーミッション。と master.cf へ記述する user=$USER のユーザー

ssh を実行するユーザーは root/postfix とかだとうまく行かなかった。

  • postfix ユーザーで ssh を起動しようとしたら status=deferred (unknown mail transport error) になるし
  • mail ユーザーで ssh 起動しようとしたら、No such file or directory. Permission denied, please try again._ Permission denied, please try again になるし
  • root の場合は、postfix が privilegedはだめとかいうし。

というわけで一般ユーザーで起動するのが無難だった。

秘密鍵を指定してみる。

ssh コマンドを指定なのだから、秘密鍵を引数でファイル指定すればいいはずである。 ssh -i 秘密鍵PATHで使えるのでそれを設定すれば動くはずである。

ssh-relay unix    -       n       n       -       -     pipe
  user=mail argv=/usr/bin/ssh -i  秘密鍵パス  takuya@HostB /usr/sbin/sendmail -i $recipient

hostA で次のコマンドを実行して、HostBからメール送信ができれば、postfixも同じ設定を使えるはずである。

mail ユーザ が sendmail をリモート実行できることを確認する。

root@hostA:~ $ cat sample-mail.txt | sudo -u mail ssh -i /etc/mail/ssh-sendmail-key -l takuya hostB  /usr/sbin/sendmail -i takuya@example.com

送信できれば、mail ユーザーを使う設定を記入する

postfix/master.cf に設定を追記する

今回は、設定名を変えて追記した。

ssh-relay2 unix    -       n       n       -       -     pipe
  user=mail argv=/usr/bin/ssh -i /etc/mail/ssh-sendmail-key -l takuya 192.168.2.5 /usr/sbin/sendmail -i $recipient

postfix/main.cf に設定を追記する

default_transport = ssh-relay2

これで、固定ユーザーに依存せずにメール起動ができるのである。便利ですね。

公開鍵の機能を限定しておく。

特定の公開鍵では、機能を限定することが可能なので、 authorized_keys を使って機能を限定しておけば安心である。接続元を限定したり、起動可能なコマンドを限定しておけばいい。

実際にやってみると楽だった

たとえば、SSHが可能でsendmail が利用可能なレンタルサーバーやVPS経由でメールを送信すれば、 OP25B や submission ポートに悩まされずに済む。

また、VPS側で postfixをリッスンせず、SSHのみ済むのでファイアウォール設定がとてもシンプルに片付くのである。

また、仮想マシンを増やすたびに smart-replay ホストを設定しパスワード保存する必要もないし、 smart-relayを設定するたびに、Google SMTPサーバーや google account secutiy で警告をもらわずに済むのである。

ssh で トンネル貼る必要もないし、socks5しなくても済むし、VPNも要らないのである。SSHなのでちゃんと暗号化されているのである。

さくらVPSやheteml レンタルサーバーで ssh sendmail をしてしまえば、25番ポートからfromをアレしたメールが送り放題になってしまうのである。postfixSSH pipe経由とは、実に、けしからんメール配送解決策である。

参考資料

Using sendmail over SSH - Super User