V2 プライベート環境 (Internal-only CAE + Application Gateway)
概要
V2 環境は、セキュリティを強化したプライベート Container Apps 環境です。
| 項目 | V1 (従来) | V2 (プライベート) |
|---|---|---|
| CAE タイプ | External | Internal-only |
| インターネット公開 | Container App 直接 | Application Gateway 経由 |
| WAF | なし | あり (OWASP 3.2) |
| ネットワーク | 共有 VNet | 専用 VNet (10.1.0.0/16) |
アーキテクチャ
Internet
│
▼
┌─────────────────────────────────────┐
│ Cloudflare (SSL/TLS) │
└─────────────────────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ Application Gateway + WAF │
│ (Per-tenant, Public IP) │
└─────────────────────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ Container Apps Environment │
│ (Internal-only, shared-v2) │
│ │
│ ├─ Container App (tenant A) │
│ ├─ Container App (tenant B) │
│ └─ Container App (tenant C) │
└─────────────────────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ Backend Resources (V1 VNet) │
│ ├─ MySQL Flexible Server │
│ ├─ Redis Cache │
│ └─ Storage Account │
└─────────────────────────────────────┘
新規テナントを V2 で作成
1. config.toml を設定
name = "my-company"
template = "monolith" # または "frontend-backend"
template_version = "v1.0.0"
["environments.prd"]
enabled = true
location = "japaneast"
site_url = "https://app.example.com"
use_shared_v2 = true # ← V2 CAE を使用
["environments.prd.frontend"]
image_name = "my-app"
image_tag = "latest"
# ... 他の設定
["environments.prd.application_gateway"]
enabled = true
min_capacity = 1
max_capacity = 3
waf_mode = "Prevention" # または "Detection"
2. デプロイ
# 環境変数を設定
infra decrypt my-company
# .env ファイルを編集
infra encrypt my-company
# Terraform を生成
infra generate my-company prd
# デプロイ
infra plan my-company prd
infra apply my-company prd
3. DNS を設定
# AGW の Public IP を確認
cd terraform/environments/tenants/my-company/prd
terraform output application_gateway_public_ip
DNS プロバイダー(Cloudflare 等)で A レコードを設定:
app.example.com→<AGW_PUBLIC_IP>
既存テナントを V2 に移行 (Blue-Green デプロイメント)
既存の V1 環境を V2 に移行する場合、Blue-Green デプロイメントで無停止移行が可能です。
概要
- V1 環境 (prd): 既存の Container App + DB/Redis/Storage
- V2 環境 (prd-v2): 新しい Container App (V2 CAE) + 既存の DB/Redis/Storage を共有
1. config.toml に prd-v2 環境を追加
# 既存の prd 環境はそのまま維持
["environments.prd"]
enabled = true
location = "japaneast"
site_url = "https://app.example.com"
# ... 既存の設定
# 新しい prd-v2 環境を追加
["environments.prd-v2"]
enabled = true
location = "japaneast"
site_url = "https://app.example.com"
use_shared_v2 = true
shared_resources_from = "prd" # ← DB/Redis/Storage を prd から共有
["environments.prd-v2.frontend"]
# prd と同じ設定をコピー
image_name = "my-app"
image_tag = "latest"
# ...
["environments.prd-v2.application_gateway"]
enabled = true
min_capacity = 1
max_capacity = 3
waf_mode = "Prevention"
2. V2 環境をデプロイ
# Terraform を生成
infra generate my-company prd-v2
# デプロイ(V1 には影響なし)
cd terraform/environments/tenants/my-company/prd-v2
terraform init
terraform plan
terraform apply
3. V2 環境をテスト
# AGW IP を取得
AGW_IP=$(terraform output -raw application_gateway_public_ip)
# 直接テスト
curl -H "Host: app.example.com" http://$AGW_IP
4. DNS を V2 に切り替え
Cloudflare/DNS プロバイダーで:
app.example.comの A レコードを V2 AGW IP に変更
5. V1 環境を削除(オプション)
V2 が安定したら、V1 の Container App を削除:
# V1 の Container App のみ削除(DB/Redis/Storage は残す)
# 注意: 手動で Azure Portal から削除するか、Terraform を調整
Application Gateway WAF 設定
WAF モード
| モード | 動作 | 推奨用途 |
|---|---|---|
| Detection | ログのみ、ブロックなし | テスト、移行初期 |
| Prevention | 悪意のあるリクエストをブロック | 本番環境 |
よくある誤検知と対策
Next.js/NextAuth アプリケーションでは、以下の誤検知が発生することがあります:
| 症状 | 原因 | 対策 |
|---|---|---|
| 403 Forbidden | Cookie が WAF ルールに該当 | Cookie 除外設定 |
| 403 Forbidden | JSON ボディが SQL インジェクションと誤判定 | ルール 942430, 942440 を無効化 |
これらの除外設定は monolith-ca-only モジュールにデフォルトで含まれています。
WAF ログの確認
# Azure Portal で確認
# Application Gateway → Diagnostic settings → WAF logs を有効化
# Log Analytics でクエリ
az monitor log-analytics query \
--workspace <workspace-id> \
--analytics-query "AzureDiagnostics | where Category == 'ApplicationGatewayFirewallLog' | where action_s == 'Blocked'"
ネットワーク構成
VNet CIDR
| VNet | CIDR | 用途 |
|---|---|---|
| V1 shared (JP) | 10.0.0.0/16 | 既存環境 |
| V2 shared | 10.1.0.0/16 | プライベート CAE |
サブネット
V2 shared (10.1.0.0/16):
| サブネット | CIDR | 用途 |
|---|---|---|
| App Gateway | 10.1.0.0/24 | Application Gateway |
| Container App | 10.1.64.0/18 | Container Apps |
| Database | 10.1.128.0/19 | (未使用、V1 と共有) |
NSG ルール
V1/V2 間の通信を許可するため、以下の NSG ルールが自動設定されます:
- V1 db-nsg: V2 CA サブネット → V1 DB サブネット (MySQL 3306)
- V2 container-app-nsg: V2 CA → V1 DB サブネット (Outbound)
SSL/TLS 設定
Cloudflare を使用する場合(推奨)
Cloudflare Proxy を有効にすると、SSL は Cloudflare が処理します:
- Cloudflare で DNS レコードを設定(Proxy: ON)
- SSL/TLS モード: Flexible または Full
- AGW は HTTP のままで OK
User → HTTPS → Cloudflare → HTTP → AGW → Container App
AGW で SSL 終端する場合
Key Vault に証明書をアップロードし、config.toml で指定:
["environments.prd.application_gateway"]
enabled = true
custom_domain = "app.example.com"
ssl_certificate_key_vault_secret_id = "https://my-keyvault.vault.azure.net/secrets/my-cert"
トラブルシューティング
Container App が DB に接続できない
原因: NSG ルールが不足
解決策:
# shared 環境の v2 統合を有効化
cd terraform/environments/shared
# main.tf で enable_v2_integration = true を確認
terraform apply
# shared-v2 環境の v1 DB アクセスを有効化
cd terraform/environments/shared-v2
# main.tf で enable_v1_db_access = true を確認
terraform apply
WAF が正当なリクエストをブロック
原因: OWASP ルールの誤検知
解決策:
- WAF ログで blocked ルール ID を確認
- config.toml または Terraform で除外設定を追加
DNS 解決ができない
原因: ローカル DNS キャッシュ
解決策:
# Mac
sudo dscacheutil -flushcache && sudo killall -HUP mDNSResponder
# テスト
dig app.example.com @8.8.8.8