目次
1. ゾーン別 IP アドレス設計方針(Zone-Based IP Allocation)
192.168.2.0/24 セグメントを機能ごとの「ゾーン(Zone)」に分類し、将来のスケールアウト時に迷わない拡張性を確保します。以下はPhase 0時点で策定した設計方針です。実装が進むにつれて一部は方針転換しています(詳細は表下の精査メモ参照)。
| IPアドレス範囲 | ゾーン名 | 主な用途・割り当て |
|---|---|---|
| 192.168.2.1 〜 2.10 | Infrastructure Zone | FortiGate GW(.1)、GW冗長(.2)、AlmaLinux 9 Host(.3)、予備 |
| 192.168.2.11 〜 2.19 | Core Services Zone | DNS/NTP(.11)、Headscale(.13)、Authentik(.16)、OpenZiti(.17) |
| 192.168.2.20 〜 2.29 | Security & Mgmt Zone | Prometheus/Grafana(.12)、Syslog(.14)、Loki(.15)、Wazuh(.20) |
| 192.168.2.30 〜 2.99 | Application Zone | Samba(.30予定)、Nextcloud(.31)、Gitea(.32)、Vaultwarden(.33) |
| 192.168.2.100 〜 2.199 | Container(macv0)Zone | Podman macv0 仮想IF動的割り当て領域 |
| 192.168.2.200 〜 2.254 | Temporary / Test Zone | PoC・一時検証用動的アドレス領域 |
IP アドレス設計・予約方針(IP Allocation Policy)
| IPアドレス | 割り当て対象 / 役割 | 備考 |
|---|---|---|
| 192.168.2.1 | FortiGate Gateway(Port1) | 境界ファイアウォール |
| 192.168.2.2 | Gateway Reserve | 冗長化(VRRP/HA)用予約 |
| 192.168.2.3 | AlmaLinux 9 Host(mgmt-server) | ホストOS(Samba/Podman/Ansible) |
| 192.168.2.4 〜 2.10 | Infra Reserve | 将来のインフラコア機器用予約 |
| 192.168.2.11 | identity-dns-ntp(Unbound/Chrony) | 基盤DNS/NTPコンテナ ★本書の構築対象 |
| 192.168.2.12 | Prometheus / Grafana(設計時点の想定) | 実装ではAlmaLinux本体(.3)に集約。下記の精査メモ参照 |
| 192.168.2.13 | Headscale | Tailscale コントロールサーバ |
| 192.168.2.14 | Syslog(設計時点の想定) | 実装ではAlmaLinux本体(.3)でrsyslog中継。下記の精査メモ参照 |
| 192.168.2.15 | Loki(設計時点の想定) | 実装ではAlmaLinux本体(.3)に集約。下記の精査メモ参照 |
| 192.168.2.16 | Authentik | IdP(認証・認可基盤) |
| 192.168.2.17 | OpenZiti | ZTNAコントローラ(将来) |
| 192.168.2.18 〜 2.29 | Service Reserve | 将来のマイクロサービス用予約 |
| 192.168.2.30 〜 2.254 | Macv0 / Dynamic Pool | ポッド・Macv0用動的割り当て領域 |
精査メモ:Prometheus/Grafana/Lokiは、なぜ専用IPを使わなかったか
Phase 0策定時点では、Prometheus/Grafana/Syslog/Lokiにもそれぞれ専用のmacvlan IPを割り当てる設計だった。しかし実際にPhase 2でこれらを構築する段階で、AlmaLinux本体(192.168.2.3)上でホストネットワーク(Network=host)として稼働させ、ポート番号で使い分ける方式に変更した。
この判断の背景には、本ロードマップの過程で繰り返し遭遇したmacvlanのホスト分離問題がある(macvlanネットワーク上のコンテナと、そのmacvlanの親インターフェースを持つホスト自身は、双方向に直接通信できないという制約。詳細はPhase 2実践マニュアルの「境界ファイアウォールの新規ポリシー不通」等でも触れている関連の教訓)。観測基盤はホスト自身のあらゆるメトリクス・ログを収集する性質上、ホストとの通信が絶えず発生するため、あえてmacvlanの専用IPを持たせず、ホストネットワークで直接動かす方が構成がシンプルで、この種の到達性問題を根本から回避できると判断した。
2. リモートアクセス & ファイル共有の推奨アクセスモデル
セキュリティとパフォーマンスを両立するため、用途に応じたアクセス経路を厳密に分離します。
| 利用シーン | 経路 | 接続先 |
|---|---|---|
| LAN内アクセス | SMB / Port 445 | Samba(LAN内超高速ファイル転送) |
| リモートアクセス | HTTPS / Authentik MFA | Nextcloud(Web/スマホ閲覧・安全編集) |
| 管理者アクセス | Headscale / OpenZiti | 各種管理画面・SSH(暗号化オーバーレイ) |
3. 100% Quadlet(IaC)による DNS/NTP コンテナ構築
3-1. unbound.conf(実装・最終版)
設計初期段階では将来のサブドメイン追加に備え local-zone: transparent(未定義クエリを上位DNSへフォールバック)を検討していましたが、home.local は外部に登録されていない内部専用ドメインのため、上位DNSへフォールバックしても解決できません。そのため実装では static(home.local配下は明示的なlocal-dataのみ応答、それ以外はNXDOMAIN)を採用し、ホスト追加時はlocal-dataに1行追記する運用としました。
精査ポイント:transparent → static への設計変更
外部に存在しない内部ドメイン(home.local)を対象とする場合、staticの方が「登録漏れの内部ホストが誤って外部DNSへ問い合わせに漏れる」事故を防げるため、セキュリティ上も適切な選択です。将来Ansibleテンプレートでlocal-dataを自動生成するIaC化を予定しています。
sudo vi /srv/containers/identity/unbound/unbound.conf
server:
interface: 0.0.0.0
port: 53
do-ip4: yes
do-udp: yes
do-tcp: yes
# セキュリティ設定:LAN内とループバック以外からの問い合わせは拒否
# ★172.16.1.0/24(DMZ)はここに書かない、というのが今回の設計判断です
access-control: 127.0.0.0/8 allow
access-control: 192.168.2.0/24 allow
# 内部ドメインの定義
local-zone: "home.local." static
# LAN ホスト・コンテナ一覧
local-data: "mgmt-server.home.local. IN A 192.168.2.3"
local-data: "macv0.home.local. IN A 192.168.2.99"
local-data: "identity-dns.home.local. IN A 192.168.2.11"
local-data: "monitoring.home.local. IN A 192.168.2.12"
local-data: "headscale.home.local. IN A 192.168.2.13"
local-data: "syslog.home.local. IN A 192.168.2.14"
local-data: "loki.home.local. IN A 192.168.2.15"
local-data: "idp.home.local. IN A 192.168.2.16"
local-data: "openziti.home.local. IN A 192.168.2.17"
3-2. chrony.conf
sudo vi /srv/containers/identity/chrony/chrony.conf
# 同期先の日本標準時サーバー(NICT)
pool ntp.nict.jp iburst
# クライアントへの時刻提供を許可する範囲(LAN内のみ)
# ★ここにも172.16.1.0/24は書きません
allow 192.168.2.0/24
# 時刻が大きくズレていた場合、起動直後3回までは一気に補正する
makestep 1.0 3
3-3. Quadlet ユニットファイルの定義
Requires=network-online.target を追加し、ネットワークが完全に有効化された後でのみ起動する堅牢な依存関係を設定します。
sudo vi /etc/containers/systemd/identity-dns-ntp.container
[Unit]
Description=Identity DNS and NTP Service (Unbound & Chrony)
After=network-online.target
Requires=network-online.target
[Service]
Restart=always
RestartSec=10
[Container]
ContainerName=identity-dns-ntp
Image=identity-dns-ntp:latest
Network=systemd-local_lan
IP=192.168.2.11
Volume=/srv/containers/identity/unbound/unbound.conf:/etc/unbound/unbound.conf:Z
Volume=/srv/containers/identity/chrony/chrony.conf:/etc/chrony/chrony.conf:Z
[Install]
WantedBy=multi-user.target
# systemd 適用と起動確認
sudo systemctl daemon-reload
sudo systemctl start identity-dns-ntp
sudo systemctl status identity-dns-ntp
sudo journalctl -u identity-dns-ntp -n 20 --no-hostname
4. 構築時トラブルと解決(enable vs start)
daemon-reload後に systemctl enable --now を実行したところ、以下のエラーで起動できませんでした。
Failed to enable unit: Unit /run/systemd/generator/identity-dns-ntp.service is transient or generated.
Quadletが生成するユニットは /run/systemd/generator/(実行時に自動生成される一時的な場所)に配置されます。daemon-reload の時点でsystemdにより自動的に有効化されるため、手動での enable は「これは自動生成されたユニットです」と拒否されます。
enable は不要。start のみで起動する
OS起動時の自動起動はQuadletが自動処理するため、手動操作は起動(start)のみで十分です。
# 1. (念のため) 手動起動した同名コンテナが残っている場合は強制削除
sudo podman rm -f identity-dns-ntp 2>/dev/null || true
# 2. Quadlet サービスを開始(enable ではなく start を実行する)
sudo systemctl start identity-dns-ntp
# 3. ステータス確認(Active: active (running) になれば成功)
sudo systemctl status identity-dns-ntp
Active: active (running) since Sat 2026-08-01 11:55:41 JST
Main PID: 14078 (conmon)
8月 01 11:55:41 identity-dns-ntp[14078]: [entrypoint] Unbound(DNS)を起動します...
8月 01 11:55:41 identity-dns-ntp[14078]: [entrypoint] Chrony(NTP)を起動します...
8月 01 11:55:41 systemd[1]: Started Identity DNS and NTP Service (Unbound & Chrony).
5. SELinux 運用・トラブルシューティングガイド
5-1. SELinux 稼働モードの事前確認(誤設定防止)
作業前に SELinux が確実に Enforcing モードであることを確認します。
# 1. 現在のモード確認(Enforcing であることを確認)
getenforce
# 2. SELinux ステータス詳細確認
sestatus
5-2. ラベルの復元 & 拒否ログ(AVC)解析手順
# コンテナディレクトリのラベル確認・復元
ls -dZ /srv/containers/identity/*
sudo restorecon -R -v /srv/containers/identity
# SELinux 拒否ログ(AVC)が発生した場合の解析手順
sudo ausearch -m avc -ts recent
sudo ausearch -m avc -ts recent | audit2why
精査メモ
今回のQuadletボリュームマウントには :Z ラベルオプションを付与済みのため、SELinuxによるコンテナアクセス拒否(AVC)は発生していません。上記コマンドは今後のトラブル発生時の一次切り分け手順として常備してください。
6. 3点エンドツーエンド通信検証(3-Point Verification)
単なる nc のみならず、「クライアント → FortiGate → アプリケーション」の3点で通信キャプチャとログの整合性を検証します。
# 【Point 1: クライアント側】送信パケット生成とキャプチャ
nc -zuv 192.168.2.11 53
sudo tcpdump -i any host 192.168.2.11 and port 53 -n
# 【Point 2: FortiGate側】FW通過ログの確認(FortiGate CLI)
# diagnose log filter category 0
# diagnose log filter field dstip 192.168.2.11
# diagnose log read
# 【Point 3: アプリケーション側】着信ログ確認(AlmaLinux 9 Host)
sudo journalctl -u identity-dns-ntp -n 10 --no-hostname
7. Phase 0 完了検証(Definition of Done)& 監査証跡
# 【証跡1】systemd および Podman ステータス
sudo systemctl status identity-dns-ntp --no-pager
sudo podman ps --filter name=identity-dns-ntp
# 【証跡2】DNS 応答確認(dig / host / nslookup)
dig @192.168.2.11 mgmt-server.home.local +short
dig @192.168.2.11 google.com +short
# 【証跡3】NTP 同期確認(Stratum 2〜4: 正常、Stratum 16: 異常 / Leap status: Normal)
sudo podman exec identity-dns-ntp chronyc tracking
$ dig @192.168.2.11 mgmt-server.home.local +short
192.168.2.3 ← 内部DNS解決:成功
$ dig @192.168.2.11 google.com +short
172.217.213.102 ... ← 外部フォワード解決:成功
$ sudo podman exec identity-dns-ntp chronyc tracking
Reference ID : 85F3EEF3 (ntp-a2.nict.go.jp)
Stratum : 2
System time : 0.002259203 seconds slow of NTP time
Leap status : Normal
内部FQDN解決・外部フォワード解決・NTP高精度同期(Stratum 2、NICT日本標準時、時刻差1秒未満)のすべてが実機で確認できました。
DoD達成状況
- 全サーバの時刻同期差が1秒未満であること 証跡あり(0.0023秒)
- 内部FQDNの名前解決が正常動作すること 証跡あり
- TLS証明書の自動更新確認(Caddy導入フェーズで実施予定) Phase 4以降で検証
podman kill強制終了 → 自律復旧の実地確認 Restart=always設定済み・実地試験は未実施
8. 【Phase 0.5】 日常ヘルスチェックスクリプト
毎日1分でCPU・メモリ・ディスク・主要サービスを点検するコマンドセットです。
echo "=== 1. System Uptime & Load Average ===" && uptime
echo "=== 2. CPU & Memory Usage ===" && free -h
echo "=== 3. Disk Space ===" && df -h /
echo "=== 4. Service Status ===" && systemctl is-active identity-dns-ntp
echo "=== 5. NTP Sync State ===" && podman exec identity-dns-ntp chronyc tracking | grep Stratum
echo "=== 6. DNS Resolution ===" && dig @192.168.2.11 google.com +short
echo "=== 7. SELinux Violations (Today) ===" && sudo ausearch -m avc -ts today | wc -l
9. 【Phase 0.6】 リストア演習(Disaster Recovery Test)
「バックアップが確実に復元できること」を検証する演習です。
- 疑似障害の発生:設定ファイルを誤って削除/破壊。
sudo mv /srv/containers/identity/unbound/unbound.conf /srv/containers/identity/unbound/unbound.conf.bak sudo systemctl restart identity-dns-ntp # → エラーで起動不可または名前解決失敗を確認 - バックアップからのリストア:
sudo cp /srv/containers/identity/unbound/unbound.conf.bak /srv/containers/identity/unbound/unbound.conf sudo restorecon -v /srv/containers/identity/unbound/unbound.conf sudo systemctl restart identity-dns-ntp - 動作復旧の確認&証跡保存:
dig @192.168.2.11 mgmt-server.home.local +short # → 正常に 192.168.2.3 が返ることを確認してテスト完了
10. 【Phase 0.7 / 0.8】 バージョン管理・環境スナップショット & セキュリティベースライン
環境バージョンの一括記録
{
echo "=== Date ===" && date
echo "=== OS Kernel ===" && uname -r
echo "=== OS Version ===" && cat /etc/redhat-release
echo "=== Podman Version ===" && podman version
echo "=== systemd Version ===" && systemctl --version | head -n 1
echo "=== SELinux Status ===" && getenforce
} | sudo tee /var/log/env_baseline.log
セキュリティベースライン・チェックリスト
| チェック項目 | 標準セキュリティ基準 | 確認コマンド | 状態 |
|---|---|---|---|
| NTP | 正確な時刻同期が維持されている | chronyc tracking → Stratum 2〜4 | PASS(証跡あり) |
| SELinux | Enforcing モードであること | getenforce → Enforcing | 未実施・記録待ち |
| Firewall | 必要なポート(53, 123等)以外閉塞 | firewall-cmd --list-all または FortiGate ACL | 未実施・記録待ち |
| SSH | Root直接ログイン禁止・鍵認証 | /etc/ssh/sshd_config(PermitRootLogin no) | 未実施・記録待ち |
| Audit | コンテナ起動・コンフィグ変更の記録 | journalctl ログ保存およびQuadlet永続化 | PASS(journalctlログ採取済み) |
精査メモ
実機ログとして確認できているのは「NTP同期」と「systemd/Podmanの稼働・Audit証跡」の2項目である。SELinux・Firewall・SSHの3項目は設計上の前提としているが、コマンド出力による実地証跡は未採取のため「未実施・記録待ち」のステータスとしている。
Phase 0 基盤確立(Foundation)完了 🎉
ゼロトラスト統合基盤の最も重要な土台である【Phase 0】(IP設計 192.168.2.0/24・DNS/NTP・Quadlet IaC化・FortiGate境界制御)が完了しました。全体ロードマップは「ゼロトラスト統合基盤検証ロードマップ」を参照してください。
11. 次ステップ:【Phase 1:Samba + authentik 連携】への接続
本マニュアルの「7. Phase 0 完了検証」および「9. リストア演習」が完了しましたら、次の Phase 1(Sambaファイルサーバのデプロイおよび Authentik 連携)へ進みます。
- Samba Quadletデプロイ:192.168.2.3(AlmaLinux 9)上に Quadlet で Samba を配置(192.168.2.30 または ホストIP共用)。
- authentik LDAP Outpost連携:authentik(192.168.2.16)の LDAP 認証機能を有効化し、Sambaユーザー管理を認可(RBAC)統合。
- ハイブリッドアクセス確認:LAN内 → Samba(SMB Port 445)直接接続で超高速アクセス/リモート → Nextcloud(HTTPS)+ authentik MFA で安全ブラウザ編集/管理者 → Headscale / OpenZiti 経由でのセキュア運用。