2024-11-04

PostfixにSMTP Authの設定を追加

はじめに

SMTP認証を行う方法は色々ある。
  • Dovecot の SASL を使用 (たぶん、 PAM を使う。)
  • Cyrus SASL を使用し、 PAM の認証情報を使う。
  • Cyrus SASL を使用し、 Cyrus SASL 用のパスワードデータベースを用意する。
今回は、最後の方法を使用する。 総当たり攻撃を受けてもしパスワードが発覚したとしても、ユーザー名やパスワードを別のものにしておけば、他のサービスへの被害を抑えられるメリットがあるだろうという考え。

環境

OS: AlmaLinux release 9 (Rocky Linux release 8 での設定も付記する)

インストールとセットアップ

Cyrus SASLのライブラリをインストールする。 (`cyrus-sasl` は不要)
sudo dnf install cyrus-sasl-{lib,md5,plain}
予め、 Letsencrypt の証明書を取得しておき、 /etc/postfix/main.cf に以下を設定する。
smtpd_tls_cert_file = /etc/letsencrypt/live/example.com/fullchain.pem
smtpd_tls_key_file = /etc/letsencrypt/live/example.com/privkey.pem
smtpd_sasl_local_domain=$mydomain
smtpd_sasl_security_options=noanonymous
/etc/postfix/master.cf に以下を設定する。
smtps     inet  n       -       n       -       -       smtpd
  -o syslog_name=postfix/smtps
  -o smtpd_tls_wrappermode=yes
  -o smtpd_sasl_auth_enable=yes
  -o smtpd_recipient_restrictions=permit_sasl_authenticated,reject
/etc/sasl2/smtpd.conf に以下を設定する。 (mech_list の設定は削除する。または、 cram-md5 digest-md5 plain login を設定する。)
pwcheck_method: auxprop
ユーザーを追加し、パスワードを設定する。 (ユーザー名は適宜置き換えること。ドメイン名は smtpd_sasl_local_domain と同じものにする。) なお、パスワードを変更するだけの場合、オプション -c を付けない。
sudo saslpasswd2 -c -u example.com user1
パスワードデータベースにグループ sasl を設定し、ユーザー postfix を所属させる。
sudo groupadd sasl
sudo groupmems -a postfix -g sasl
sudo chgrp sasl /etc/sasl2/sasldb2
sudo chmog g+r /etc/sasl2/sasldb2
Note: EL8 では、 /etc/sasldb2 にパスワードファイルが存在する。

設定をチェックし、問題なければ Postfix を再起動する。

sudo postfix check
sudo systemctl restart postfix
OpenSSL で確認する。 (接続時に Verify return code: 0 (ok) が表示され、 EHLO に対して 250-AUTH DIGEST-MD5 CRAM-MD5 LOGIN PLAIN が帰ってきたらOK。)
openssl s_client -connect localhost:smtps
EHLO localhost
ファイアウォールを設定する。
sudo firewall-cmd --add-service smtps
sudo firewall-cmd --permanent --add-service smtps

2024-09-21

Postfix に DKIM の設定を行う方法

はじめに

DMARCでメールの検証を行うには、SPFとDKIM両方を設定しないといけない。 この記事では、DKIMの設定を取り上げる。

DKIMの概要

SPF が配送もとの IP アドレス (つまりヘッダーの `Received: from helo-host.example.org (resolved-host.example.org [192.0.2.27])` の部分) を検証するのに対して、 DKIM では、メールを配送する際に、主要なヘッダー情報 (`Date`, `From`, `Reply-To`, `To`, `Subject` など) に対して署名を付加する。 公開鍵を DNS の TXT レコードに設定することになっており、受信側のメールサーバーで署名を検証する。

SPF と同様に DNS レコードを使ってメールを検証するので、 DNS が改ざんされると第三者がなりすましメールを送ることができてしまう。また、メール本文の改ざんは DKIM では検知できない。

設定手順

このセクションでは、 EL9 (AlmaLinux 9 や Rocky Linux 9) 上の Postfix で DKIM 署名を付加するための設定を説明する。 EL8 でもほぼ同様の方法で設定できる。

OpenDKIM のインストール

前もって CRB と EPEL をインストールしておき、以下のコマンドで OpenDKIM をインストールする。
sudo dnf --enablerepo=epel,crb install opendkim opendkim-tools

キーの作成

cd $(mktemp -d)
opendkim-genkey --directory ./ --domain example.com --selector 20240921 --bit 2048 --append-domain
sudo cp 20240921.private /etc/opendkim/keys/ -i
sudo chown opendkim:opendkim /etc/opendkim/keys/20240921.private

DNSレコードの設定

公開鍵が記載されたファイル 20240921.txt が生成されるので、これを参照してDNSレコードを設定する。 上記の例の場合、 20240921._domainkey.example.com. の TXT レコードを設定する。 TXT以降はカッコでかこまれてダブルクオートがついているが、例えば Cloudflare の DNS 場合は、カッコ・ダブルクオート・改行を取って Content に登録する。

設定ファイルの編集

sudo cp /etc/opendkim.conf /etc/opendkim.conf-20240921
sudoedit /etc/opendkim.conf
以下のように編集して保存する。
@@ -36,7 +36,7 @@
 ##  Selects operating modes. Valid modes are s (sign) and v (verify). Default is v.
 ##  Must be changed to s (sign only) or sv (sign and verify) in order to sign outgoing
 ##  messages.
-Mode	v
+Mode	sv
 
 ##  Log activity to the system log.
 Syslog	yes
@@ -101,12 +101,12 @@
 ##  Gives the location of a file mapping key names to signing keys. In simple terms,
 ##  this tells OpenDKIM where to find your keys. If present, overrides any KeyFile
 ##  directive in the configuration file. Requires SigningTable be enabled.
-# KeyTable	/etc/opendkim/KeyTable
+KeyTable	/etc/opendkim/KeyTable
 
 ##  Defines a table used to select one or more signatures to apply to a message based
 ##  on the address found in the From: header field. In simple terms, this tells
 ##  OpenDKIM how to use your keys. Requires KeyTable be enabled.
-# SigningTable	refile:/etc/opendkim/SigningTable
+SigningTable	refile:/etc/opendkim/SigningTable
 
 ##  Identifies a set of "external" hosts that may send mail through the server as one
 ##  of the signing domains without credentials as such.

sudoedit /etc/opendkim/KeyTable
以下の1行を加える。
20240921._domainkey.example.com example.com:20240921:/etc/opendkim/keys/20240921.private

sudoedit /etc/opendkim/SigningTable 
以下の1行を加える。
*@example.com 20240921._domainkey.example.com

OpenDKIMを起動する

sudo systemctl enable --now opendkim.service
sudo systemctl status opendkim.service

Postfixの設定

cd /etc/postfix/
sudo cp main.cf main.cf-20240921
sudoedit main.cf
以下の3行を追加する。
smtpd_milters = local:/run/opendkim/opendkim.sock
non_smtpd_milters = local:/run/opendkim/opendkim.sock
milter_default_action = accept
もしローカルからしか配送しないなら、 smtpd_milters は設定しなくてよさそう。

Postfixを再起動する

グループも設定したので、再起動する。
sudo systemctl restart postfix
sudo systemctl status postfix

動作確認

TXTレコードが設定されているかどうか確認する。
dig txt 20240921._domainkey.example.com
他のメールサーバーへ送信してみる。 Gmailなどへ送付すれば、「メッセージのソースを表示」からDKIMの検証状況を確認できる。
date -R | mutt -s 'DKIM key should be added' user@example.org
もし問題があれば、 /etc/postfix/main.cf をもとに戻して確認しよう。

小言

SSLのように外部の機関に認証してもらう必要がなく、コストがかからないのがありがたい。

参考

2024-07-28

GCCでは文字列リテラルをstrlenへ渡すと定数に展開される

最近のGCCは標準関数を使ったコードがコンパイル時に計算されてしまうことがあって、良くできている。 例えば、GCCで文字列リテラルを strlen へ渡すと、定数に置き換えられる。

入力コード例: リテラル文字を strlen で数えて返す関数。

#include <string.h>

int func()
{
	return strlen("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
}
私の手元にある gcc 13.3.1 20240522 (Red Hat 13.3.1-1) を使用してコンパイルする。
$ cc -O1 -S a.c
コンパイル結果: -O1 でコンパイルしたところ、26を返すだけの関数にコンパイルされる。
func:
.LFB0:
	.cfi_startproc
	movl	$26, %eax
	ret
	.cfi_endproc

具体的な使用例としては、マクロ定義したリテラル文字をその長さと一緒に strncmp へ渡すときのような場合があるだろう。

#define PREFIX "com.example."
int check_prefix(const char *text)
{
	if (strncmp(text, PREFIX, strlen(PREFIX)) == 0)
		return 1;
	return 0;
}
このようなコードを書いた時、 strlen が呼び出されるので処理時間が無駄になるなどと考える必要はない。

2024-07-16

Screenの設定により、Screen上のVimの起動時に誤動作

Screenの中でVimを起動するとなぜか変な文字が入力されるという問題が起こっていたのだけれど、ようやく回避方法がわかった。

前提として、 .screenrc に以下のように設定して Ctrl+G で screen のコマンドを入力するようにしていた。 これを他のキーに変えると問題が起こらない。

.vimrc に以下の記述を加えると、問題が起こらなくなった。

if &term=="screen.xterm-256color"
        set t_RB=
endif
このことから、t_RB (request terminal background color) が悪さをしているらしい。 おそらく、リクエストを出すと screen を通り越して端末に伝わり、端末が結果を返すときに、私が割り当てた Ctrl+G のコードが送られ、それを screen が処理してしまうのだろう。

最終的に、以下のように記述することにした。

if &term=="screen.xterm-256color"
        " For .screenrc setting 'escape ^Ww', t_RB caused an issue.
        " Let's disable all request-type termcap settings.
        set t_RB= t_RF= t_RC= t_RI= t_Ri= t_RS= t_RT= t_RV=
endif

2024-06-30

youtube-dl: 音声だけをダウンロードする方法

フォーマットの一覧を取得
youtube-dl --list-format URL
出力例:
251          webm       audio only audio_quality_medium  118k , webm_dash container, opus  (48000Hz), 23.18MiB
140          m4a        audio only audio_quality_medium  129k , m4a_dash container, mp4a.40.2 (44100Hz), 25.25MiB
160          mp4        256x144    144p   53k , mp4_dash container, avc1.4d400c, 30fps, video only, 10.35MiB
134          mp4        640x360    360p  219k , mp4_dash container, avc1.4d401e, 30fps, video only, 42.87MiB
136          mp4        1280x720   720p  900k , mp4_dash container, avc1.64001f, 30fps, video only, 175.69MiB
137          mp4        1920x1080  1080p 1957k , mp4_dash container, avc1.640028, 30fps, video only, 381.82MiB
18           mp4        640x360    360p  316k , avc1.42001E, 30fps, mp4a.40.2 (44100Hz), 61.65MiB (best)

特定のフォーマットだけを選択してダウンロード (この例では251)

youtube-dl -k -f 251 URL