Skip to content
Published on

IPsec完全攻略 — VPNトンネルの動作原理から構築まで

Authors
  • Name
    Twitter
IPsec Deep Dive

はじめに

VPNをオンにするとインターネットが遅くなることは知っているけど、なぜ遅くなるか知っていますか?それは内部でIPsecというプロトコルがすべてのパケットを暗号化し、認証し、トンネリングしているからです。

IPsecはネットワークエンジニアだけでなく、クラウドアーキテクト(VPCピアリング、Site-to-Site VPN)、DevOpsエンジニア(WireGuard vs IPsec)、セキュリティエンジニアすべてにとって必須の知識です。

IPsecとは?

IPsec (IP Security) = IP層(L3)で動作するセキュリティプロトコルスイート

構成要素:
├── AH (Authentication Header): 認証のみ(完全性 + 送信元確認)
├── ESP (Encapsulating Security Payload): 暗号化 + 認証(実務で99%├── IKE (Internet Key Exchange): 鍵交換 + SAネゴシエーション
└── SA (Security Association): セキュリティ接続情報の格納庫

核心概念

SA(Security Association)— セキュリティ接続の契約書

SA = 2つのデバイス間の「セキュリティ合意書」

含まれる情報:
├── SPI (Security Parameter Index): SA識別子(32bit)
├── 暗号化アルゴリズム: AES-256-GCM
├── 認証アルゴリズム: SHA-256 HMAC
├── 鍵の値: 共有秘密鍵
├── 有効期間: 3600秒または100GB
└── モード: トンネル / トランスポート

SAは一方向 → 双方向通信にはSA2つ必要!

トンネルモード vs トランスポートモード

[トランスポートモード(Transport Mode)]
  ホスト間の直接通信
  元のIPヘッダーを保持、ペイロードのみ暗号化

  ┌──────────┬──────────┬────────────────┐
IP Header│ESP Header│ 暗号化された    │
   (元の)   │          │ Payload  └──────────┴──────────┴────────────────┘

[トンネルモード(Tunnel Mode)]Site-to-Site VPN
  ゲートウェイ間(元のパケット全体を包む)
  新しいIPヘッダーを追加、元のIPも暗号化!

  ┌──────────┬──────────┬─────────────────────────┐
  │ 新しいIPESP Header│ 暗号化された             │
Header   │          │ [元のIP + Data]  └──────────┴──────────┴─────────────────────────┘

実務でトンネルモードが重要な理由: 内部ネットワークのIPアドレスが外部に露出しない!

ESP(Encapsulating Security Payload)— 核心

ESPパケット構造:

┌─────────────────────────────────────────────┐
IP Header(新しい、トンネルモード)├─────────────────────────────────────────────┤
ESP Header│  ├── SPI (32bit): どのSAを使うか            │
│  └── Sequence Number (32bit): リプレイ防止   │
├─────────────────────────────────────────────┤
│ 暗号化領域(Encrypted)                      │
│  ├── 元のIP Header(トンネルモード)│  ├── 元のPayload(TCP/UDP + Data)│  └── ESP Trailer(Padding + Next Header)├─────────────────────────────────────────────┤
ESP Auth (ICV): HMAC-SHA256(完全性検証)    │
└─────────────────────────────────────────────┘
# ESP暗号化プロセス(疑似コード)
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
import os

def esp_encrypt(original_packet, sa):
    """ESP暗号化(AES-256-GCM)"""
    # 1. SAから鍵とアルゴリズムを取得
    key = sa.encryption_key  # 256-bit
    spi = sa.spi
    seq = sa.next_sequence_number()

    # 2. ESP Header生成
    esp_header = spi.to_bytes(4, 'big') + seq.to_bytes(4, 'big')

    # 3. Padding追加(ブロックサイズに合わせる)
    pad_len = (16 - (len(original_packet) + 2) % 16) % 16
    padding = bytes(range(1, pad_len + 1))
    esp_trailer = padding + bytes([pad_len, 4])  # 4 = IP-in-IP

    # 4. 暗号化(AES-256-GCM)
    nonce = os.urandom(12)
    aesgcm = AESGCM(key)
    plaintext = original_packet + esp_trailer
    ciphertext = aesgcm.encrypt(nonce, plaintext, esp_header)  # AAD = ESP Header

    # 5. 新しいIP Header + ESP Header + 暗号化データ
    new_ip = create_ip_header(sa.tunnel_src, sa.tunnel_dst)
    return new_ip + esp_header + nonce + ciphertext

IKE(Internet Key Exchange)— 鍵ネゴシエーション

IPsecで最も複雑な部分!2つのフェーズに分かれます。

Phase 1(IKE SA)— 「お互いを信頼できるか?」

目的: 安全なチャネルの確立(以降のPhase 2を保護)

[Initiator]                    [Responder]
    │                              │
    │──── SA Proposal ────────────▶│  暗号化/ハッシュ/DHグループ提案
    │◀─── SA Accepted ────────────│  合意
    │                              │
    │──── DH Public Value ────────▶│  Diffie-Hellman鍵交換
    │◀─── DH Public Value ────────│  双方が同じ秘密鍵を導出!
    │                              │
    │──── Auth (PSK/Cert) ────────▶│  事前共有鍵または証明書
    │◀─── Auth ────────────────────│  相互認証
    │                              │
    ╔══════════════════════════════╗
IKE SA確立(暗号化チャネル) ║
    ╚══════════════════════════════╝

Phase 2(IPsec SA)— 「どのトラフィックをどう保護するか」

IKE SAで保護されたチャネル内で:

[Initiator]                    [Responder]
    │                              │
    │──── IPsec SA Proposal ──────▶│  ESP/AH、暗号化アルゴリズム
    │◀─── IPsec SA Accepted ──────│  合意
    │                              │
    │──── Traffic Selector ────────▶│  どのIP/Port範囲を保護?
    │◀─── Traffic Selector ────────│  合意
    │                              │
    ╔══════════════════════════════╗
IPsec SA確立(x2、双方向)   ║
    ║  → 実データの暗号化開始!     ║
    ╚══════════════════════════════╝

Diffie-Hellman鍵交換(魔法の核心)

# DH鍵交換 — 盗聴者が見ても秘密鍵は分からない!
p = 23  # 大きな素数(実際: 2048/4096 bit)
g = 5   # 生成元

# Alice
a = 6   # Aliceの秘密値
A = pow(g, a, p)  # 5^6 mod 23 = 8  → 公開送信

# Bob
b = 15  # Bobの秘密値
B = pow(g, b, p)  # 5^15 mod 23 = 19 → 公開送信

# 共有秘密鍵の導出(同じ値!)
alice_secret = pow(B, a, p)  # 19^6 mod 23 = 2
bob_secret = pow(A, b, p)    # 8^15 mod 23 = 2

assert alice_secret == bob_secret  # ✅ 同じ秘密鍵!
# 盗聴者: p=23, g=5, A=8, B=19を知っていても
# aやbが分からなければ秘密鍵2は求められない(離散対数問題)

実務: AWS Site-to-Site VPN

オンプレミス (192.168.1.0/24)
    ├── Customer Gateway (IPsec)
    │       │
    │       │ ══ IPsecトンネル1 (Active) ══
    │       │ ══ IPsecトンネル2 (Standby) ══
    │       │
    ├── Virtual Private Gateway
AWS VPC (10.0.0.0/16)
# LinuxでIPsec VPN設定(strongSwan)
sudo apt install strongswan

# /etc/ipsec.conf
cat << 'EOF'
conn aws-vpn
    type=tunnel
    auto=start
    left=203.0.113.1          # ローカルパブリックIP
    leftsubnet=192.168.1.0/24 # ローカルネットワーク
    right=52.10.20.30         # AWS VGW IP
    rightsubnet=10.0.0.0/16   # AWS VPC CIDR
    ike=aes256-sha256-modp2048
    esp=aes256-sha256
    keyexchange=ikev2
    authby=secret
EOF

# /etc/ipsec.secrets
echo '203.0.113.1 52.10.20.30 : PSK "MyPreSharedKey123"' | sudo tee /etc/ipsec.secrets

# 起動
sudo ipsec restart
sudo ipsec status

IPsec vs WireGuard vs OpenVPN

項目IPsec (IKEv2)WireGuardOpenVPN
レイヤーL3L3L3/L4
コード量約40万行約4千行約10万行
速度高速最速普通
設定複雑簡単普通
モバイル優秀 (IKEv2)優秀普通
エンタープライズ標準新興広く使用

クイズ — IPsec(クリックして確認!)

Q1. ESPとAHの違いは? ||ESP: 暗号化 + 認証(完全性)。AH: 認証のみ(暗号化なし)。実務ではESPが99%使用される||

Q2. トンネルモードとトランスポートモードの違いは? ||トンネルモード: 元のIPパケット全体を新しいIPで包んで暗号化(ゲートウェイ間VPN)。トランスポートモード: 元のIPヘッダーを保持し、ペイロードのみ暗号化(ホスト間の直接通信)||

Q3. IKE Phase 1とPhase 2の役割は? ||Phase 1: IKE SA確立 — DH鍵交換 + 相互認証で安全なチャネルを確保。Phase 2: IPsec SA確立 — Phase 1チャネル内で実際のトラフィック保護ポリシーを合意||

Q4. SPI(Security Parameter Index)とは? ||32ビットの識別子で、受信側がどのSA(セキュリティ合意)を適用するか判断するために使用。ESPヘッダーに含まれる||

Q5. DH鍵交換が安全な理由は? ||離散対数問題 — 公開値(g, p, A, B)を知っていても秘密指数(a, b)を求めることが計算的に不可能。盗聴者がすべての公開通信を見ても共有秘密鍵を導出できない||

Q6. IPsecでSAが一方向である理由とその結果は? ||各SAは一方向のトラフィックのみ保護(セキュリティパラメータが方向ごとに異なりうる)。そのため双方向通信にはSA2つ(インバウンド + アウトバウンド)が必要||