MENU

メール技術検証 構築編

目次

はじめに

何をしたいか

実際にメールサーバーを構築し、メールの送受信の仕組みを理解する。
また、SPF・DKIM・DMARCによる送信ドメイン認証、SMTP AUTHによるユーザー認証、TLSによる通信の暗号化について、設定と動作検証を通して理解を深める。
本記事では、メールサーバーの構築と基本的な動作確認を実施する。
SPF・DKIM・DMARCによる送信ドメイン認証、SMTP AUTHによるユーザー認証、TLSによる通信の暗号化については次の記事で検証する。

メール技術検証 構築編 本記事
メール技術検証 セキュリティ設定・検証編 https://cybermemo.blog/mail-security-testing

本記事で構築する構成

DNSの構成および設定内容は、一部簡略化して記載。
OpenDKIM、OpenDMARC、SMTP AUTHについては、次の記事で設定/検証する。
※構成図に使用したアイコンは、素材サイト「CMAN」からダウンロードしたものです。

構成図

検証環境

仮想化ソフトウェア:Oracle VirtualBox
ゲストOS:Ubuntu Server 26.04.1 LTS(amd64)
SMTPサーバー:Postfix 3.10.6
IMAPサーバー:Dovecot 2.4.2
権威DNS:BIND 9.20.24
フルリゾルバ:Unbound 1.24.2
内部ネットワーク:192.168.56.0/24
検証ドメイン:child.lab.test
メールサーバー:mail.child.lab.test(192.168.56.50)

構築

DNSにMXレコードを設定

DNSSEC検証 準備・DNS構築編 で構築した環境を利用。

# Child DNSのゾーンファイルにMXレコードを追加
$ sudo vim /etc/bind/db.child.lab.test
$TTL 3600

@       IN SOA ns dnsmaster (
                2026101001 ; Serial
                3600       ; Refresh
                900        ; Retry
                4800     ; Expire
                86400      ; Negative Cache TTL
)

        IN NS   ns

ns      IN A    192.168.56.20
www     IN A    192.168.56.100
# Serialを変更
mail    IN A    192.168.56.50
@       IN MX   10 mail.child.lab.test.  # mailの設定を追記

# 構文チェック
$ sudo named-checkzone child.lab.test /etc/bind/db.child.lab.test
zone child.lab.test/IN: loaded serial 2026101001
OK

# BINDを再読み込み
$ sudo rndc reload child.lab.test
zone reload queued

# Clientで名前解決ができるか確認
$ dig @192.168.56.30 mail.child.lab.test A

; <<>> DiG 9.20.24-1ubuntu0.3-Ubuntu <<>> @192.168.56.30 mail.child.lab.test A
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 34602  #エラーなし
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;mail.child.lab.test.           IN      A

;; ANSWER SECTION:
mail.child.lab.test.    3600    IN      A       192.168.56.50  # 設定したAレコードが返ってきている

;; Query time: 6 msec
;; SERVER: 192.168.56.30#53(192.168.56.30) (UDP)
;; WHEN: Sat Oct 10 05:41:23 UTC 2026
;; MSG SIZE  rcvd: 64

$ dig @192.168.56.30 child.lab.test MX

; <<>> DiG 9.20.24-1ubuntu0.3-Ubuntu <<>> @192.168.56.30 child.lab.test MX
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 17047  #エラーなし
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;child.lab.test.                        IN      MX

;; ANSWER SECTION:
child.lab.test.         3600    IN      MX      10 mail.child.lab.test.  # 設定したMXレコードが返ってきている

;; Query time: 7 msec
;; SERVER: 192.168.56.30#53(192.168.56.30) (UDP)
;; WHEN: Sat Oct 10 05:45:43 UTC 2026
;; MSG SIZE  rcvd: 64

Postfixのインストールと設定

# システムのパッケージリストを更新
$ sudo apt update

# Postfixのインストール
$ sudo apt install postfix
postfix_install_1  
postfix_install_2
# インストール中にPostfixConfigurationという画面が表示された場合は、
 Internet Siteを選択し、System mail nameはメールドメイン(child.lab.test)を入力

# ステータス確認
$ sudo systemctl status postfix
[sudo: authenticate] Password:
● postfix.service - Postfix Mail Transport Agent (main/default instance)
     Loaded: loaded (/usr/lib/systemd/system/postfix.service; enabled; preset: enabled)
     Active: active (running) since Sat 2026-10-10 06:08:45 UTC; 11min ago

# Postfixの設定を確認。下線部分が修正箇所
$ postconf myhostname mydomain myorigin mydestination inet_interfaces mynetworks
myhostname = mail
mydomain = localdomain
myorigin = /etc/mailname
mydestination = $myhostname, child.lab.test, mail, localhost.localdomain, localhost
inet_interfaces = all
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128

# Postfixの設定を修正
$ sudo postconf -e 'myhostname = mail.child.lab.test'
$ sudo postconf -e 'mydomain = child.lab.test'
$ sudo postconf -e 'mydestination = $myhostname, localhost.$mydomain, localhost, $mydomain'

# Postfixの設定チェック
# resolv.confの所有者がrootではないため警告が発生している
$ sudo postfix check
postfix/postfix-script: warning: not owned by root: /var/spool/postfix/etc/resolv.conf

# resolv.confの所有者/所有グループをrootに変更
$ ls -l /var/spool/postfix/etc/resolv.conf
-rw-r--r-- 1 systemd-resolve systemd-resolve 920 Oct 10 06:08 /var/spool/postfix/etc/resolv.conf
$ sudo chown root:root /var/spool/postfix/etc/resolv.conf
$ ls -l /var/spool/postfix/etc/resolv.conf
-rw-r--r-- 1 root root 920 Oct 10 06:08 /var/spool/postfix/etc/resolv.conf

# Postfixの設定を再チェック
# 何も表示されなければ問題なし
$ sudo postfix check

# Postfixを再読み込み
$ sudo postfix reload
postfix/postfix-script: refreshing the Postfix mail system

# Postfixの設定を再確認
$ postconf myhostname mydomain myorigin mydestination inet_interfaces mynetworks
myhostname = mail.child.lab.test
mydomain = child.lab.test
myorigin = /etc/mailname
mydestination = $myhostname, localhost.$mydomain, localhost, $mydomain
inet_interfaces = all
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128

メールサーバー(Postfix)へメールを送信

# TCP/25番ポートがLISTENになっていることを確認
$ sudo ss -lntp | grep ':25 '
LISTEN 0      100          0.0.0.0:25        0.0.0.0:*    users:(("master",pid=1272,fd=13))
LISTEN 0      100             [::]:25           [::]:*    users:(("master",pid=1272,fd=14))

# ここからclient端末へ切り替えて、SMTP接続
# SMTPサーバーへ接続
$ nc -C 192.168.56.50 25
220 mail.child.lab.test ESMTP Postfix (Ubuntu)

# メール送信
# 下線部分が入力箇所
EHLO client.child.lab.test
250-mail.child.lab.test
250-PIPELINING
250-SIZE 10240000
250-VRFY
250-ETRN
250-STARTTLS
250-ENHANCEDSTATUSCODES
250-8BITMIME
250-DSN
250-SMTPUTF8
250 CHUNKING
MAIL FROM:<sender@child.lab.test>
250 2.1.0 Ok
RCPT TO:<mailadmin@child.lab.test>
250 2.1.5 Ok
DATA
354 End data with <CR><LF>.<CR><LF>
From: sender@child.lab.test
To: mailadmin@child.lab.test
Subject: SMTP Test

This is a test mail.
.
250 2.0.0 Ok: queued as 9EB2140252
QUIT

# メールサーバー側でメール確認
$ sudo cat /var/mail/mailadmin
From sender@child.lab.test  Sat Oct 10 12:23:43 2026
Return-Path: <sender@child.lab.test>
X-Original-To: mailadmin@child.lab.test
Delivered-To: mailadmin@child.lab.test
Received: from client.child.lab.test (unknown [192.168.56.40])
        by mail.child.lab.test (Postfix) with ESMTP id 9EB2140252
        for <mailadmin@child.lab.test>; Sat, 10 Oct 2026 12:21:09 +0000 (UTC)
From: sender@child.lab.test
To: mailadmin@child.lab.test
Subject: SMTP Test

This is a test mail.

WiresharkでSMTP通信をキャプチャ

せっかくなので、SMTP通信がWiresharkでどう見えるのか確認しておく。

SMTPでフィルタした結果。

wireshark_smtp

TCPストリーム

wireshark_tcpstream

Dovecotのインストール

# システムのパッケージリストを更新
$ sudo apt update

# Dovecotのインストール
$ sudo apt install dovecot-core dovecot-imapd

# ステータス確認
$ sudo systemctl status dovecot
● dovecot.service - Dovecot IMAP/POP3 email server
     Loaded: loaded (/usr/lib/systemd/system/dovecot.service; enabled; preset: enabled)
     Active: active (running) since Sat 2026-10-10 14:12:05 UTC; 5min ago

DovecotのTLS証明書作成

# Dovecotの設定を確認
$ sudo doveconf mail_driver passdb userdb ssl auth_allow_cleartext ssl_server_cert_file ssl_server_key_file
mail_driver = mbox
passdb pam {
}
userdb passwd {
}
ssl = yes
auth_allow_cleartext = no
ssl_server_cert_file = /etc/dovecot/private/dovecot.pem
ssl_server_key_file = /etc/dovecot/private/dovecot.key

# 証明書の内容を確認
# subjectとissuerがFQDNになっていない
$ sudo openssl x509 -in /etc/dovecot/private/dovecot.pem -noout -subject -issuer -dates -ext subjectAltName
subject=CN=mail
issuer=CN=mail
notBefore=Oct 10 06:07:02 2026 GMT
notAfter=Oct  7 06:07:02 2036 GMT
X509v3 Subject Alternative Name:
    DNS:mail

# ファイルを確認
# シンボリックリンクになっている
$ sudo ls -l /etc/dovecot/private/dovecot.key
lrwxrwxrwx 1 root root 38 Oct 10 14:12 /etc/dovecot/private/dovecot.key -> /etc/ssl/private/ssl-cert-snakeoil.key
$ sudo ls -l /etc/dovecot/private/dovecot.pem
lrwxrwxrwx 1 root root 36 Oct 10 14:12 /etc/dovecot/private/dovecot.pem -> /etc/ssl/certs/ssl-cert-snakeoil.pem

# シンボリックリンクを解除
$ sudo unlink /etc/dovecot/private/dovecot.pem
$ sudo unlink /etc/dovecot/private/dovecot.key

# 自己署名証明書を作成
$ sudo openssl req -x509 -newkey rsa:3072 -sha256 -nodes \
> -keyout /etc/dovecot/private/dovecot.key \
> -out /etc/dovecot/private/dovecot.pem \
> -days 365 \
> -subj "/CN=mail.child.lab.test" \
> -addext "subjectAltName=DNS:mail.child.lab.test" \
> -addext "extendedKeyUsage=serverAuth"

# 作成した証明書の確認
$ sudo ls -l /etc/dovecot/private/dovecot.pem
-rw-r--r-- 1 root root 1562 Oct 11 03:46 /etc/dovecot/private/dovecot.pem
$ sudo ls -l /etc/dovecot/private/dovecot.key
-rw------- 1 root root 2484 Oct 11 03:46 /etc/dovecot/private/dovecot.key
$ sudo openssl x509 \
> -in /etc/dovecot/private/dovecot.pem \
> -noout -subject -issuer -dates \
> -ext subjectAltName \
> -ext extendedKeyUsage
subject=CN=mail.child.lab.test
issuer=CN=mail.child.lab.test
notBefore=Oct 11 03:46:37 2026 GMT
notAfter=Oct 11 03:46:37 2027 GMT
X509v3 Extended Key Usage:
    TLS Web Server Authentication

# Dovecotの再起動
$ sudo systemctl restart dovecot
$ sudo systemctl is-active dovecot
active

Dovecotの動作確認

# clientで作業
# 接続確認
~$ openssl s_client -starttls imap \
> -connect 192.168.56.50:143 \
> -servername mail.child.lab.test
Connecting to 192.168.56.50
CONNECTED(00000003)
depth=0 CN=mail.child.lab.test
verify error:num=18:self-signed certificate
verify return:1
depth=0 CN=mail.child.lab.test
verify return:1
---
Certificate chain
 0 s:CN=mail.child.lab.test
   i:CN=mail.child.lab.test
   a:PKEY: RSA, 3072 (bit); sigalg: sha256WithRSAEncryption
   v:NotBefore: Oct 11 03:46:37 2026 GMT; NotAfter: Oct 11 03:46:37 2027 GMT
---
(中略)
---
New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
Protocol: TLSv1.3
Server public key is 3072 bit
This TLS version forbids renegotiation.
Compression: NONE
Expansion: NONE
No ALPN negotiated
Early data was not sent
Verify return code: 18 (self-signed certificate)  # 自己署名証明書を使用している場合のエラーコード
---
(中略)
---
read R BLOCK
a001 LOGOUT
* BYE Logging out
a001 OK Logout completed.
closed

# ネットワーク経由で証明書を取得
$ openssl s_client -starttls imap \
> -connect 192.168.56.50:143 \
> -servername mail.child.lab.test \
> -showcerts </dev/null 2>/dev/null \
> | openssl x509 -outform PEM > ~/mail-server.crt

# 取得した証明書の確認
$ openssl x509 -in ~/mail-server.crt -noout -subject -issuer -fingerprint -sha256
subject=CN=mail.child.lab.test
issuer=CN=mail.child.lab.test
sha256 Fingerprint=3E:DE:F6:A6:9D:55:DA:3C:62:D2:31:2F:DA:6A:DB:52:F5:FE:67:73:B7:4C:20:99:93:B1:89:BF:44:F2:10:21

# メールサーバーで作業
# メールサーバー側のフィンガープリントを確認
$ sudo openssl x509 \
> -in /etc/dovecot/private/dovecot.pem \
> -noout -fingerprint -sha256
[sudo: authenticate] Password:
sha256 Fingerprint=3E:DE:F6:A6:9D:55:DA:3C:62:D2:31:2F:DA:6A:DB:52:F5:FE:67:73:B7:4C:20:99:93:B1:89:BF:44:F2:10:21

# clientで作業
$ openssl s_client -starttls imap \
> -connect 192.168.56.50:143 \
> -servername mail.child.lab.test \
> -CAfile ~/mail-server.crt \  # 指定した証明書を信頼の基点として、サーバー証明書を検証する
> -verify_hostname mail.child.lab.test \  # 証明書に記載されたサーバー名が、指定したホスト名と一致するか検証する
> -verify_return_error  # 証明書の検証に失敗した場合、エラーを無視せずTLS接続を中断する
Connecting to 192.168.56.50
CONNECTED(00000003)
depth=0 CN=mail.child.lab.test
verify return:1
(中略)
---
New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
Protocol: TLSv1.3
Server public key is 3072 bit
This TLS version forbids renegotiation.
Compression: NONE
Expansion: NONE
No ALPN negotiated
Early data was not sent
Verify return code: 0 (ok)  # エラーなし
---
(中略)
---
read R BLOCK

# IMAP認証と動作確認
# 下線部分が入力箇所
a001 LOGIN mailadmin "パスワード"
* CAPABILITY IMAP4rev1 SASL-IR LOGIN-REFERRALS ID ENABLE IDLE SORT SORT=DISPLAY THREAD=REFERENCES THREAD=REFS THREAD=ORDEREDSUBJECT MULTIAPPEND URL-PARTIAL CATENATE UNSELECT CHILDREN NAMESPACE UIDPLUS LIST-EXTENDED I18NLEVEL=1 CONDSTORE QRESYNC ESEARCH ESORT SEARCHRES WITHIN CONTEXT=SEARCH LIST-STATUS BINARY MOVE REPLACE SNIPPET=FUZZY PREVIEW=FUZZY PREVIEW SPECIAL-USE STATUS=SIZE SAVEDATE COMPRESS=DEFLATE INPROGRESS NOTIFY LITERAL+
a001 OK Logged in
a002 SELECT INBOX
* FLAGS (\Answered \Flagged \Deleted \Seen \Draft)
* OK [PERMANENTFLAGS (\Answered \Flagged \Deleted \Seen \Draft \*)] Flags permitted.
* 3 EXISTS
* 3 RECENT
* OK [UNSEEN 1] First unseen.
* OK [UIDVALIDITY 1791695038] UIDs valid
* OK [UIDNEXT 4] Predicted next UID
a002 OK [READ-WRITE] Select completed (0.005 + 0.000 + 0.004 secs).
a003 FETCH 1 BODY.PEEK[]
* 1 FETCH (BODY[] {418}
Return-Path: <sender@child.lab.test>
X-Original-To: mailadmin@child.lab.test
Delivered-To: mailadmin@child.lab.test
Received: from client.child.lab.test (unknown [192.168.56.40])
        by mail.child.lab.test (Postfix) with ESMTP id 9EB2140252
        for <mailadmin@child.lab.test>; Sat, 10 Oct 2026 12:21:09 +0000 (UTC)
From: sender@child.lab.test
To: mailadmin@child.lab.test
Subject: SMTP Test

This is a test mail.
)
a003 OK Fetch completed (0.001 + 0.000 secs).
a004 LOGOUT

WiresharkでIMAP通信をキャプチャ

wireshark_imap
No.内容通信内容
4~8IMAP平文でCAPABILITYの問い合わせと応答
9STARTTLSクライアントがTLSへの切り替えを要求
11OKサーバーがSTARTTLS要求を受け付ける
12Client HelloTLSハンドシェイク開始
14Server HelloTLS 1.3のハンドシェイクが進行
15~19Application DataなどTLSの暗号化されたレコードが送受信される
21以降Application DataTLSで保護された通信が継続する

まとめ

今回はPostfixとDovecotを使用してメールサーバーを構築し、SMTPによるメール送信とIMAPによるメール取得が正常に行えることを確認した。
また、IMAPのSTARTTLSによる通信の暗号化とサーバー証明書の作成も実施した。
次回はこの環境を使用してSMTP AUTH、SMTPのSTARTTLS、SPF・DKIM・DMARCを導入し、メールの認証や通信の暗号化について検証する。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

勉強中のセキュリティエンジニアです。
初心者の目線で学んだことをまとめています。

コメント

コメントする

CAPTCHA


目次