Azure VPN + YAMAHA RTX830 で VPN 環境構築

## はじめに

最近、オンプレミス環境からAzureクラウド環境への接続のため、Azure VPNとYAMAHA RTX830を使ったサイト間VPN接続を構築する機会がありました。この記事では、実際の構築時に気をつけたAzure特有のポイントをサンプルコードと共に解説します。

## Azure VPNの基本と接続タイプ

Azure VPN Gatewayは、オンプレミス環境とAzureの仮想ネットワーク（VNet）を安全に接続するためのサービスです。主に以下の2つの接続タイプがあります：

1. **サイト間（S2S）VPN接続**：オンプレミスのネットワーク全体とAzure VNetを接続
2. **ポイント対サイト（P2S）VPN接続**：個々のクライアントデバイスとAzure VNetを接続

本記事では、**サイト間(S2S)VPN接続**に焦点を当て、YAMAHA RTX830ルーターを使用した構成を解説します。

## ポイント1: Azure VPN Gatewayの適切なSKU選択

Azure VPN Gatewayには複数のSKUがあり、パフォーマンスとコスト要件に応じて選択する必要があります。

```hcl
# 実際のTerraformコードサンプル
resource "azurerm_virtual_network_gateway" "vpn" {
  name                = "vgw-p2s"
  location            = var.location
  resource_group_name = var.resource_group_name
  type                = "Vpn"
  vpn_type            = "RouteBased"
  sku                 = "VpnGw1"  # このSKU選択が重要
  
  ip_configuration {
    name                          = "vnetGatewayConfig"
    public_ip_address_id          = azurerm_public_ip.vpn_pip.id
    private_ip_address_allocation = "Dynamic"
    subnet_id                     = azurerm_subnet.gateway_subnet.id
  }
}
```

**コード解説:**
- `type = "Vpn"`: VPN接続タイプを指定
- `vpn_type = "RouteBased"`: ルートベースのVPNを使用（RTX830との互換性のため）
- `sku = "VpnGw1"`: バランスの取れたパフォーマンスとコストのSKU

RTX830との連携では、少なくとも`VpnGw1`以上を選択することが重要です。Basic SKUではIKEv2やカスタムIPsecポリシーの設定ができないため避けるべきです。また、帯域要件によって`VpnGw2`や`VpnGw3`などの上位SKUを検討してください。

## ポイント2: Azure特有のIPsecポリシー設定

Azure VPNとRTX830の互換性を確保するために、カスタムIPsecポリシーの正確な設定が必要です。

```hcl
# カスタムIPsecポリシーの設定例
resource "azurerm_virtual_network_gateway_connection" "vpn_connection" {
  name                       = "onprem-to-azure"
  resource_group_name        = var.resource_group
  location                   = var.location
  type                       = "IPsec"
  virtual_network_gateway_id = azurerm_virtual_network_gateway.vpn.id
  local_network_gateway_id   = azurerm_local_network_gateway.onpremise.id
  shared_key                 = var.vpn_shared_key
  
  # RTX830との互換性を持たせるカスタムIPsecポリシー
  ipsec_policy {
    dh_group         = "DHGroup14"     # RTX830の modp2048 に対応
    ike_encryption   = "AES256"        # RTX830の aes256-cbc に対応
    ike_integrity    = "SHA256"        # RTX830の sha256 に対応
    ipsec_encryption = "AES256"        # フェーズ2暗号化
    ipsec_integrity  = "SHA256"        # フェーズ2認証
    pfs_group        = "PFS2048"       # PFS有効設定
    sa_lifetime      = 3600            # セキュリティアソシエーションの有効期間(秒)
  }
}
```

**コード解説:**
- RTX830側の設定とAzure側の設定パラメータを一致させることが重要です
- RTX830設定から対応するAzureパラメータを正確にマッピングする必要があります:
  - RTX830: `ipsec ike group 1 modp2048` → Azure: `dh_group = "DHGroup14"`
  - RTX830: `ipsec ike encryption 1 aes256-cbc` → Azure: `ike_encryption = "AES256"`
  - RTX830: `ipsec ike hash 1 sha256` → Azure: `ike_integrity = "SHA256"`

RTX830側の対応する設定例:
```
ipsec ike version 1 2
ipsec ike duration ike-sa 1 28800
ipsec ike encryption 1 aes256-cbc
ipsec ike group 1 modp2048
ipsec ike hash 1 sha256
ipsec sa policy 1 1 esp aes256-cbc sha256-hmac
ipsec ike duration child-sa 1 3600
ipsec ike pfs 1 on
```

## ポイント3: 正確なローカルネットワークゲートウェイ設定

Azure側でオンプレミスネットワークを正確に表現するために、ローカルネットワークゲートウェイの設定が重要です。

```hcl
# ローカルネットワークゲートウェイの設定例
resource "azurerm_local_network_gateway" "onpremise" {
  name                = "onpremise-gateway"
  resource_group_name = var.resource_group
  location            = var.location
  gateway_address     = "219.104.XX.XX"        # オンプレミスルーターの実際のグローバルIP
  address_space       = ["192.168.100.0/24"]   # オンプレミスのアドレス空間
}
```

**コード解説:**
- `gateway_address`: RTX830のWAN側グローバルIPアドレスを指定
- `address_space`: オンプレミス側の内部ネットワークアドレス空間を正確に定義
  - RTX830設定の`ip lan1 address 192.168.100.1/24`に対応する設定

接続設定における実際の変数定義例:
```hcl
variable "router_public_ip" {
  type = string
  default = "219.104.XX.XX"    # 実際のグローバルIP
}

variable "router_network_address_space" {
  type = string
  default = "192.168.100.0/24" # 実際のLAN側ネットワーク
}
```

## ポイント4: ルーティング設定とサブネット設計

Azure VPN構成における正確なルーティング設定とサブネット設計が重要です。

```hcl
# VNet設定例
resource "azurerm_virtual_network" "vnet" {
  name                = "vnet-med-main"
  resource_group_name = var.resource_group
  location            = var.location
  address_space       = ["10.1.0.0/16"]
}

# ゲートウェイサブネット設定
resource "azurerm_subnet" "gateway_subnet" {
  name                 = "GatewaySubnet"  # 必ずこの名前にする必要がある
  resource_group_name  = var.resource_group
  virtual_network_name = azurerm_virtual_network.vnet.name
  address_prefixes     = ["10.1.1.0/24"]
}

# プライベートエンドポイント用サブネット
resource "azurerm_subnet" "private_endpoint_subnet" {
  name                 = "PrivateEndpointSubnet"
  resource_group_name  = var.resource_group
  virtual_network_name = azurerm_virtual_network.vnet.name
  address_prefixes     = ["10.1.3.0/24"]
}
```

**コード解説:**
- `GatewaySubnet`: VPNゲートウェイ用サブネット（名前は必ず「GatewaySubnet」とする）
- `PrivateEndpointSubnet`: プライベートエンドポイント用サブネット（Azure OpenAI Serviceなどに接続）

対応するRTX830側のルーティング設定:
```
# Azure側VNetへのルート設定
ip route 10.1.0.0/16 gateway tunnel 1
```

## ポイント5: Azure Private DNS Resolverの構成

オンプレミスとAzure間での名前解決を可能にするためのPrivate DNS Resolver設定。

```hcl
# DNSリゾルバー用サブネット
resource "azurerm_subnet" "private_dns_subnet" {
  name                 = "PrivateDnsSubnet"
  resource_group_name  = var.resource_group
  virtual_network_name = azurerm_virtual_network.vnet.name
  address_prefixes     = ["10.1.7.0/24"]
}

# インバウンドエンドポイント用サブネット
resource "azurerm_subnet" "private_inbound_endpoint_subnet" {
  name                 = "DnsInboundSubnet"
  resource_group_name  = var.resource_group
  virtual_network_name = azurerm_virtual_network.vnet.name
  address_prefixes     = ["10.1.8.0/24"]
}

# アウトバウンドエンドポイント用サブネット
resource "azurerm_subnet" "private_outbound_endpoint_subnet" {
  name                 = "DnsOutboundSubnet"
  resource_group_name  = var.resource_group
  virtual_network_name = azurerm_virtual_network.vnet.name
  address_prefixes     = ["10.1.9.0/24"]
}

# プライベートDNSリゾルバー
resource "azurerm_private_dns_resolver" "resolver" {
  name                = "dns-resolver"
  resource_group_name = var.resource_group
  location            = var.location
  virtual_network_id  = azurerm_virtual_network.vnet.id
}

# インバウンドエンドポイント
resource "azurerm_private_dns_resolver_inbound_endpoint" "inbound" {
  name                    = "inbound-endpoint"
  private_dns_resolver_id = azurerm_private_dns_resolver.resolver.id
  location                = var.location
  ip_configurations {
    private_ip_allocation_method = "Dynamic"
    subnet_id                    = azurerm_subnet.private_inbound_endpoint_subnet.id
  }
}
```

**コード解説:**
- リゾルバーには専用のサブネットが必要
- インバウンドエンドポイント: オンプレミスからのDNSクエリを受け付ける
- アウトバウンドエンドポイント: Azureからオンプレミス向けのDNSクエリを転送

対応するRTX830のDNS設定:
```
# DNS設定
dns host lan1
dns server XXX.XXX.XXX.XXX XXX.XXX.XXX.XXX
dns private address spoof on
```

## ポイント6: Private Endpointによるセキュアなサービスアクセス

Azure OpenAI ServiceなどのマネージドサービスにセキュアにアクセスするためのPrivate Endpoint設定。

```hcl
# OpenAI Serviceのリソース例
resource "azurerm_cognitive_account" "openai" {
  name                  = "${var.prefix}openai"
  location              = var.location
  resource_group_name   = var.resource_group
  kind                  = "OpenAI"
  sku_name              = "S0"
  custom_subdomain_name = "${var.prefix}openai"
  
  # パブリックネットワークアクセスを無効化
  public_network_access_enabled = false
}

# プライベートエンドポイント
resource "azurerm_private_endpoint" "openai_endpoint" {
  name                = "pe-openai"
  location            = var.location
  resource_group_name = var.resource_group
  subnet_id           = azurerm_subnet.private_endpoint_subnet.id

  private_service_connection {
    name                           = "openai-privateserviceconnection"
    is_manual_connection           = false
    private_connection_resource_id = azurerm_cognitive_account.openai.id
    subresource_names              = ["account"]
  }
  
  # プライベートDNSゾーン設定
  private_dns_zone_group {
    name                 = "default"
    private_dns_zone_ids = [azurerm_private_dns_zone.openai.id]
  }
}

# プライベートDNSゾーン
resource "azurerm_private_dns_zone" "openai" {
  name                = "privatelink.openai.azure.com"
  resource_group_name = var.resource_group
}

# VNetリンク
resource "azurerm_private_dns_zone_virtual_network_link" "openai_link" {
  name                  = "openai-vnet-link"
  resource_group_name   = var.resource_group
  private_dns_zone_name = azurerm_private_dns_zone.openai.name
  virtual_network_id    = azurerm_virtual_network.vnet.id
  registration_enabled  = false
}
```

**コード解説:**
- `public_network_access_enabled = false`: パブリックアクセスを無効化
- `subresource_names = ["account"]`: OpenAI Serviceのサブリソース名
- プライベートDNSゾーン: `privatelink.openai.azure.com`を設定
- VNetリンク: プライベートDNSゾーンとVNetを関連付け

## まとめ：RTX830とAzureの連携における重要点

今回のサンプルコードで説明した重要ポイントをまとめると：

1. **VPNゲートウェイ**: 少なくとも`VpnGw1`以上のSKUを選択
2. **IPsecポリシー**: RTX830の設定とAzure設定の正確なマッピング
3. **ローカルネットワークゲートウェイ**: オンプレミスネットワークの正確な設定
4. **サブネット設計**: GatewaySubnetやPrivateEndpointSubnetの適切な設計
5. **DNSリゾルバー**: ハイブリッド名前解決のための適切な構成
6. **プライベートエンドポイント**: マネージドサービスへのセキュアなアクセス設定

これらのポイントを押さえることで、YAMAHA RTX830とAzureを使用した安全で安定したハイブリッドクラウド環境を構築できます。

## 注意事項

- 本記事の設定例は特定の環境に基づいています。実際の構築では環境に合わせた調整が必要です。
- 記事内のIPアドレスやドメインは一部伏せています。実環境では適切な値を設定してください。
- 実装前に十分なテストと検証を行ってください。

## 参考リンク

- [Azure Virtual Network Gateway のドキュメント](https://docs.microsoft.com/ja-jp/azure/vpn-gateway/)
- [TerraformによるAzureリソースの管理](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs)
- [YAMAHA RTX830マニュアル](https://network.yamaha.com/products/routers/rtx830/index)
- [Azure Private DNS Resolver](https://docs.microsoft.com/ja-jp/azure/dns/dns-private-resolver-overview)
- [Azure Private Endpoint](https://docs.microsoft.com/ja-jp/azure/private-link/private-endpoint-overview)

---
### 私たちについて
東京・鹿児島・高知の3拠点で、商用時系列データベースCLOUDSHIPと可視化ソフトRealBoardを軸としたIoT/DXプラットフォーム向けソフトウェアの開発・販売を行うS/Wメーカーです。

クラウド(主にAWSやGC)やIoT関連の開発支援サービスやソリューションの受託開発サービスも提供しています。[鹿児島・高知での開発エンジニア採用](https://www.prompt-x.jp/recruit)を強化中で、PROMPT-Xで働きたいと思える情報発信に努めています。