Plaintext
[ インターネット ]
│ (一切アクセス拒否!)
▼
┌─【 my-vnet (仮想ネットワーク) 】────────────────────────┐
│ │
│ ┌─ [container-subnet] ─┐ ┌─ [mysql-subnet] ───┐ │
│ │ │ │ │ │
│ │ Container App (Web) ┼─────>┼─> MySQL Server │ │
│ │ │ VNet │ (appdb) │ │
│ └──────────────────────┘ 内部 └────────────────────┘ │
│ 通信 │
│ ┌─ [vm-subnet] ────────┐ ▲ │
│ │ テスト用VM ┼──────┘ │
│ └──────────────────────┘ │
└─────────────────────────────────────────────────────────┘
これを実現するterraform(今回はnginx)
# ==================== プロバイダー設定 ====================
# Azureの操作に必要なプラグインの定義(features ブロックが必須です)
terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = ">= 3.0" # または 4.x
}
tls = {
source = "hashicorp/tls"
version = "~> 4.0"
}
local = {
source = "hashicorp/local"
version = "~> 2.0"
}
}
}
provider "azurerm" {
features {} # 👈 これが不足していたためエラーになっていました
}
# ==================== リソースグループ ====================
resource "azurerm_resource_group" "rg" {
name = "my-app-rg"
location = "japaneast"
}
# ==================== SSH鍵の自動生成 ====================
resource "tls_private_key" "vm_key" {
algorithm = "RSA"
rsa_bits = 4096
}
resource "local_file" "private_key" {
content = tls_private_key.vm_key.private_key_pem
filename = "${path.module}/vm_private_key.pem"
file_permission = "0400"
}
# ==================== VNet & Subnets ====================
resource "azurerm_virtual_network" "vnet" {
name = "my-vnet"
resource_group_name = azurerm_resource_group.rg.name
location = azurerm_resource_group.rg.location
address_space = ["10.0.0.0/16"]
}
# ACA用サブネット:仕様に合わせて最低要件の /23 に拡張
resource "azurerm_subnet" "container_subnet" {
name = "container-subnet"
resource_group_name = azurerm_resource_group.rg.name
virtual_network_name = azurerm_virtual_network.vnet.name
address_prefixes = ["10.0.0.0/23"]
delegation {
name = "ContainerApps"
service_delegation {
name = "Microsoft.App/environments"
actions = ["Microsoft.Network/virtualNetworks/subnets/join/action"]
}
}
}
# Bastion用サブネット
resource "azurerm_subnet" "bastion_subnet" {
name = "AzureBastionSubnet"
resource_group_name = azurerm_resource_group.rg.name
virtual_network_name = azurerm_virtual_network.vnet.name
address_prefixes = ["10.0.2.0/26"]
}
# MySQL用サブネット
resource "azurerm_subnet" "mysql_subnet" {
name = "mysql-subnet"
resource_group_name = azurerm_resource_group.rg.name
virtual_network_name = azurerm_virtual_network.vnet.name
address_prefixes = ["10.0.3.0/24"]
delegation {
name = "MySQLFlexible"
service_delegation {
name = "Microsoft.DBforMySQL/flexibleServers"
actions = ["Microsoft.Network/virtualNetworks/subnets/join/action"]
}
}
}
# テスト用VM専用サブネット
resource "azurerm_subnet" "vm_subnet" {
name = "vm-subnet"
resource_group_name = azurerm_resource_group.rg.name
virtual_network_name = azurerm_virtual_network.vnet.name
address_prefixes = ["10.0.4.0/24"]
}
# ==================== Private DNS ====================
resource "azurerm_private_dns_zone" "mysql" {
name = "privatelink.mysql.database.azure.com"
resource_group_name = azurerm_resource_group.rg.name
}
resource "azurerm_private_dns_zone_virtual_network_link" "mysql_link" {
name = "mysql-vnet-link"
resource_group_name = azurerm_resource_group.rg.name
private_dns_zone_name = azurerm_private_dns_zone.mysql.name
virtual_network_id = azurerm_virtual_network.vnet.id
}
# ==================== Log Analytics ====================
resource "azurerm_log_analytics_workspace" "main" {
name = "my-app-logs"
resource_group_name = azurerm_resource_group.rg.name
location = azurerm_resource_group.rg.location
sku = "PerGB2018"
}
# ==================== MySQL ====================
resource "azurerm_mysql_flexible_server" "mysql" {
# 【重要】他のユーザーと重複しないよう、末尾に独自の文字列を入れてください
name = "my-mysql-private-server-999"
resource_group_name = azurerm_resource_group.rg.name
location = azurerm_resource_group.rg.location
administrator_login = "mysqladmin"
administrator_password = "P@ssw0rd-ChangeMe123!"
sku_name = "GP_Standard_D2ds_v4"
version = "8.0.21"
delegated_subnet_id = azurerm_subnet.mysql_subnet.id
private_dns_zone_id = azurerm_private_dns_zone.mysql.id
depends_on = [azurerm_private_dns_zone_virtual_network_link.mysql_link]
}
resource "azurerm_mysql_flexible_database" "main" {
name = "appdb"
resource_group_name = azurerm_resource_group.rg.name
server_name = azurerm_mysql_flexible_server.mysql.name
charset = "utf8mb4"
collation = "utf8mb4_unicode_ci"
}
# ==================== Azure Bastion ====================
resource "azurerm_public_ip" "bastion_ip" {
name = "bastion-ip"
resource_group_name = azurerm_resource_group.rg.name
location = azurerm_resource_group.rg.location
allocation_method = "Static"
sku = "Standard"
}
resource "azurerm_bastion_host" "bastion" {
name = "my-bastion"
resource_group_name = azurerm_resource_group.rg.name
location = azurerm_resource_group.rg.location
ip_configuration {
name = "config"
subnet_id = azurerm_subnet.bastion_subnet.id
public_ip_address_id = azurerm_public_ip.bastion_ip.id
}
}
# ==================== テスト用 Linux VM ====================
resource "azurerm_network_interface" "vm_nic" {
name = "test-vm-nic"
resource_group_name = azurerm_resource_group.rg.name
location = azurerm_resource_group.rg.location
ip_configuration {
name = "internal"
subnet_id = azurerm_subnet.vm_subnet.id
private_ip_address_allocation = "Dynamic"
}
}
resource "azurerm_linux_virtual_machine" "test_vm" {
name = "test-vm"
resource_group_name = azurerm_resource_group.rg.name
location = azurerm_resource_group.rg.location
size = "Standard_B2s"
admin_username = "azureuser"
network_interface_ids = [azurerm_network_interface.vm_nic.id]
admin_ssh_key {
username = "azureuser"
public_key = tls_private_key.vm_key.public_key_openssh
}
os_disk {
caching = "ReadWrite"
storage_account_type = "Standard_LRS"
}
source_image_reference {
publisher = "Canonical"
offer = "0001-com-ubuntu-server-jammy"
sku = "22_04-lts"
version = "latest"
}
user_data = base64encode(<<-EOF
#!/bin/bash
apt-get update
apt-get install -y mysql-client
mkdir -p /opt/mysql
curl -sL https://dl.cacerts.digicert.com/DigiCertGlobalRootG2.crt.pem -o /opt/mysql/DigiCertGlobalRootG2.crt.pem
chmod 644 /opt/mysql/DigiCertGlobalRootG2.crt.pem
EOF
)
}
# ==================== Container App ====================
resource "azurerm_container_app_environment" "cae" {
name = "my-cae"
resource_group_name = azurerm_resource_group.rg.name
location = azurerm_resource_group.rg.location
infrastructure_subnet_id = azurerm_subnet.container_subnet.id
log_analytics_workspace_id = azurerm_log_analytics_workspace.main.id
depends_on = [azurerm_private_dns_zone_virtual_network_link.mysql_link]
}
resource "azurerm_container_app" "app" {
name = "my-web-app"
resource_group_name = azurerm_resource_group.rg.name
container_app_environment_id = azurerm_container_app_environment.cae.id
revision_mode = "Single"
ingress {
external_enabled = true
target_port = 80
transport = "http"
traffic_weight {
latest_revision = true
percentage = 100
}
}
template {
container {
name = "nginx"
image = "nginx:latest"
cpu = 0.5
memory = "1Gi"
}
}
}
# ==================== OUTPUT ====================
output "bastion_public_ip" {
value = azurerm_public_ip.bastion_ip.ip_address
}
output "vm_private_ip" {
value = azurerm_network_interface.vm_nic.private_ip_address
}
output "container_app_url" {
value = "https://${azurerm_container_app.app.latest_revision_fqdn}"
}
output "db_host" {
value = azurerm_mysql_flexible_server.mysql.fqdn
}
output "private_key_path" {
value = local_file.private_key.filename
description = "VMにSSHするための秘密鍵のパス"
}
bastionに接続する方法
cp vm_private_key.pem /mnt/c/Users/Public/Documents/
vmにbastionに接続する方法
2. Azureポータルの画面でファイルを選ぶ
青い 「ファイルの選択」 ボタンを押します。
Windowsのファイル選択画面が開くので、以下の順番でフォルダをたどってください。
PC > ローカルディスク (C:) > ユーザー > パブリック > パブリックのドキュメント
その中に vm_private_key.pem が入っているので、それを選んで「開く」を押します。
Windowsのアクセス拒否エラー(権限の罠)に引っかかることなく、きれいにファイルを読み込ませることができます!
ユーザー名を azureuser に直して、パスフレーズは空欄にした状態で、青くなった「接続」ボタン。