🕴️

TerrafromでBastionとAzure Fliesを構成してブラウザからVMにアクセスする環境を整える

に公開

はじめに

この記事では、Terraformを使ってAzureにBastionとAzure Filesを作成する方法を紹介します。本記事は以下の人を対象にしています。

  • AzureでのBastion構成方法を知りたい人
  • Azure Filesでファイル共有を構成したい人
  • TerraformでAzureにリソース作成をしたい人

リソースの説明

まず、BastionとAzure Filesについて簡単に説明します。

Bastionとは

BastionはAzureが提供するフルマネージド踏み台サーバサービスです。Bastionを使うことで、ブラウザから安全なRDP/SSH接続ができます。仮想マシンに接続する場合は踏み台サーバを用意して、RDP接続を構成する方法がありますが、bastionではパブリックIPを仮想マシンに追加しなくてよいので、簡単に安全な接続構成を作成できます。
Standard以上のSKUを使えば、ネイティブクライアントの機能で直接ファイルのコピー&ペーストができますが、Basicでは使えないので、ファイルのコピー&ペーストはAzure Filesを使います。

Azure Filesとは

Azure FilesはAzureが提供するフルマネージドファイル共有サービスです。ストレージアカウント内にファイル共有を作成して、仮想マシンに共有ファイルを追加することで、仮想マシンで作成したファイルなどをAzureにダウンロードしたり、Azureから仮想マシンにアップロードしたりできます。

作成するリソース

Terraformで以下のリソースを作成します。

  • リソースグループ
  • 仮想ネットワーク
  • サブネット(Bastion用サブネットも作成)
  • Bastion用パブリックIPアドレス
  • Bastion
  • ストレージアカウント
  • ファイル共有
  • ネットワークインターフェース
  • 仮想マシン

コード

以下のコードをprovider.tfとmain.tfにそれぞれ記述します。

provider.tf
terraform {
  required_version = ">=1.0"
  
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "~>4.0"
    }
  }
}

provider "azurerm" {
  # ここに作成先のサブスクリプションIDを入力
  subscription_id = "12345678-aaaa-bbbb-cccc-123456789012"
  
  features {
  
  }
}
main.tf
# リソースグループ
resource "azurerm_resource_group" "sample_rg" {
  name     = "sample-tf-rg"
  location = "japaneast"
}

# 仮想ネットワーク
resource "azurerm_virtual_network" "sample_vnet" {
  name                = "sample-vnet"
  location            = azurerm_resource_group.sample_rg.location
  resource_group_name = azurerm_resource_group.sample_rg.name
  address_space       = [ "10.110.0.0/17" ]
}

# サブネット
resource "azurerm_subnet" "sample_subnet" {
  name                 = "sample-subnet"
  resource_group_name  = azurerm_resource_group.sample_rg.name
  virtual_network_name = azurerm_virtual_network.sample_vnet.name
  address_space        = [ "10.110.11.0/24" ]
  service_endpoints    = [ "Microsoft.Storage" ]
}

# サブネット(Bastion用)
resource "azurerm_subnet" "sample_bastion_subnet" {
  name                 = "AzureBastionSubnet"
  resource_group_name  = azurerm_resource_group.sample_rg.name
  virtual_network_name = azurerm_virtual_network.sample_vnet.name
  address_space        = [ "10.110.10.192/26" ]
}

# パブリックIPアドレス(Bastion用)
resource "azurerm_public_ip" "sample_bastion_pip" {
  name                 = "sample-bastion-pip"
  location             = azurerm_resource_group.sample_rg.location
  resource_group_name  = azurerm_resource_group.sample_rg.name
  allocation_method    = "Static"
}

# Bastion
resource "azurerm_bastion_host" "bastion" {
  name                 = "sample-bastion"
  location             = azurerm_resource_group.sample_rg.location
  resource_group_name  = azurerm_resource_group.sample_rg.name
  sku                  = "Basic"

  ip_configuration {
    name                 = "config"
    subnet_id            = azurerm_subnet.sample_bastion_subnet.id
    public_ip_address_id = azurerm_public_ip.sample_bastion_pip.id
  }
}

# ストレージアカウント
resource "azurerm_storage_account" "sample_sa" {
  name                     = "azurefiles3675"
  location                 = azurerm_resource_group.sample_rg.location
  resource_group_name      = azurerm_resource_group.sample_rg.name
  account_tier             = "Standard"
  account_replication_type = "LRS"

  network_rules {
    default_action             = "Deny"
    # 自分のIPアドレスを入れる
    ip_rules                   = [ "100.123.123.250" ]
    virtual_network_subnet_ids = [ azurerm_subnet.sample_subnet.id ]
  }
}

# ファイル共有
resource "azurerm_storage_share" "files" {
  name               = "fileshare"
  storage_account_id = azurerm_storage_account.sample_sa.id
  quota              = 5
}

# ネットワークインターフェース
resource "azurerm_network_interface" "sample_nic" {
  name                 = "sample-nic"
  resource_group_name  = azurerm_resource_group.sample_rg.name
  location             = azurerm_resource_group.sample_rg.location

  ip_congiguration {
    name                          = "ipconfig"
    private_ip_address_allocation = "Static"
    subnet_id                     = azurerm_subnet.sample_subnet.id
    private_ip_address            = "10.110.11.12"
  }
}

# 仮想マシン
resource "azurerm_windows_virtual_machine" "sample_vm" {
  name                  = "sample-vm"
  resource_group_name   = azurerm_resource_group.sample_rg.name
  location              = azurerm_resource_group.sample_rg.location
  size                  = "Standard_D2s_v5"
  admin_username        = "localadmin"
  admin_password        = "Pass378Zenn!"
  network_interface_ids = [ azurerm_network_interface.sample_nic.id ]

  os_disk {
    name                 = "sample-OS-Disk"
    caching              = "ReadWrite"
    storage_account_type = "Premium_LRS"
  }

  source_image_reference {
    publisher = "MicrosoftWindowsServer"
    offer     = "WindowsServer"
    sku       = "2025-Datacenter"
    version   = "latest"
  }
}

自分のIPアドレスは、例えば以下のサイトから確認できます。
https://www.cman.jp/network/support/go_access.cgi
また、サブネットのサービスエンドポイントに"Microsoft.Storage"を追加するのを忘れずに!

コードの実行

以下のコマンドをPowerShellから実行して、Azureにリソースを作成します。こちらの記事も参考に。
https://zenn.dev/dainamit2025/articles/6ecaf4bea0c2e1

  • Terraformの初期化を実行
terraform init -upgrade
  • リソース作成の計画を作成
terraform plan -out main.tfplan
  • リソース作成の適用
terraform apply main.tfplan

Bastion作成の注意点

Bastionの作成は約10分ほどかかります。Terraformではリソースの作成順序は自動で決まり、並列でリソースを作成してくれるので、Bastionを作成している間は仮想マシンを作ってくれないのでは?などと心配する必要はありません。(Bastionは最後のほうに作成される)

ただし、Bastionは高価なサービスで、Basicで作成しても1日で約700円ほどかかります。料金は以下を参考。
https://azure.microsoft.com/ja-jp/pricing/details/azure-bastion/
そこで、料金を抑えたい場合はこまめに削除する必要があります。Terraformで特定のリソースのみを作成/削除したい場合はplan時にtargetオプションを使います。今回のようにBastionだけ削除したい場合は以下のコマンドでplanを実行します。

terraform plan -destroy -out main.destroy.tfplan -target="azurerm_bastion_host.bastion"

上のコマンドを実行すると「targetは通常時は使わないでください」という旨の警告が表示されますが、そのままapplyを実行してOKです。パブリックIPも存在するだけで課金対象なので、同じように削除しておくとよいでしょう。

仮想マシンにファイル共有を追加する

Terraformでファイル共有を作成することはできても、仮想マシンにファイル共有を追加する作業はTerraformの範囲外です。この記事では詳細の手順は省略しますが、以下の公式ドキュメントなどを参考に設定まで実施しましょう。

https://learn.microsoft.com/ja-jp/azure/storage/files/storage-how-to-use-files-windows#using-an-azure-file-share-with-windows

ざっくりな手順としては、

  • Azure Portalからスクリプトをコピーする
  • 設定先VMに接続
  • PowerShellを開いてコピーしたスクリプトを実行する

このステップで設定できます。
うまくいかない場合はネットワークやサービスエンドポイントなどの設定が正しいか確認しましょう。

おわりに

最後までご覧いただきありがとうございます!この記事では、Terraformを使って、BastionとAzure Filesを作成する手順を紹介しました。今後、仮想マシン以外の関数アプリなどの設定方法も紹介しようと考えています。

Discussion