🦐

【Azure】Terraformを使ってストレージアカウントを作成してみよう!

に公開

はじめに

  • IaCでリソース作成をしてみたかったのでTerraformを使い、ストレージアカウントを作成しました
  • 今回は、Azureにある既存のリソースグループにStorage Account(+Blobコンテナ)をTerraformで作る流れについて解説します

ゴールと全体像

  • Terraform で Azure に接続(Azure CLI 認証)
  • 既存 リソースグループ(RG)(例:InductionCourse_202507_son)を 参照
  • Storage Account を 作成(HTTPSのみ、パブリック禁止、LRS など基本設定)
  • Blob コンテナ(例:tfstate)も一緒に 作成
  • よくあるハマり(プロバイダ登録/プロパティ名の変更)も回避

準備:ツールのインストール

Azure CLI のインストール(コマンド)

会社PCでインストールが難しい場合はAzure Cloud Shell(ポータル右上「>_」)でもOK。CLIが最初から入っています。(Microsoft Learn)

Windows(winget)

winget install -e --id Microsoft.AzureCLI

winget が使えない場合は、Microsoft公式の Windows 向け手順(MSI / ZIP)もあります。(Microsoft Learn)
上の winget コマンド自体は winget パッケージ情報でも確認できます。(winget.run)

インストール確認

az --version

Terraform のインストール(例:WindowsでZIP手動配置)

(会社PCでも通りやすい方法)

$TFV="1.6.6"
$Dst="$env:USERPROFILE\Tools\terraform"
$Zip="$env:TEMP\terraform_$TFV.zip"
$Url="https://releases.hashicorp.com/terraform/$TFV/terraform_${TFV}_windows_amd64.zip"
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
New-Item -ItemType Directory -Path $Dst -Force | Out-Null
Invoke-WebRequest -Uri $Url -OutFile $Zip
Expand-Archive -Path $Zip -DestinationPath $Dst -Force
& "$Dst\terraform.exe" -version
# 任意: PATHに追加 → 新しいターミナルで `terraform -version`
[Environment]::SetEnvironmentVariable("PATH", $env:PATH + ";$Dst", "User")

Azure へのログイン&サブスク選択

# (任意) いったんログアウト
az logout

# 指定テナントでログイン(必要に応じて --use-device-code)
az login --tenant <テナントID>

# 対象サブスクリプションに切替
az account set --subscription <サブスクリプションID>

# 確認
az account show --query "{user:user.name, subscriptionId:id, tenantId:tenantId}" -o table

プロジェクト雛形(最小)

your-folder/
└─ infra/
   ├─ providers.tf
   ├─ variables.tf
   ├─ locals.tf
   ├─ main.tf
   ├─ outputs.tf
   └─ envs/
      └─ dev/
         └─ terraform.tfvars

infra/providers.tf

terraform {
  required_version = ">= 1.6.0"
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "~> 3.100"
    }
    random = {
      source  = "hashicorp/random"
      version = "~> 3.6"
    }
  }
}

provider "azurerm" {
  features {}
  use_cli = true
  # 組織権限の都合で自動登録が403になる場合はオン
  skip_provider_registration = true
}

infra/variables.tf

variable "env"                 { type = string, default = "dev" }
variable "system"              { type = string, default = "demo" } # 英数字推奨(短め)
variable "resource_group_name" { type = string }                   # 既存 RG 名
variable "location"            { type = string, default = "" }     # 空ならRGと同じ
variable "containers"          { type = list(string), default = [] } # 例 ["tfstate"]

infra/locals.tf

locals {
  base_name = lower("st${var.system}${var.env}")
  sa_name   = substr("${local.base_name}${random_string.suffix.result}", 0, 24)
}

infra/main.tf

data "azurerm_resource_group" "rg" {
  name = var.resource_group_name
}

resource "random_string" "suffix" {
  length  = 6
  upper   = false
  special = false
  numeric = true
}

locals {
  effective_location = var.location != "" ? var.location : data.azurerm_resource_group.rg.location
}

resource "azurerm_storage_account" "sa" {
  name                            = local.sa_name
  resource_group_name             = data.azurerm_resource_group.rg.name
  location                        = local.effective_location

  account_kind                    = "StorageV2"
  account_tier                    = "Standard"
  account_replication_type        = "LRS"

  https_traffic_only_enabled      = true     # v3推奨名
  allow_nested_items_to_be_public = false    # v3推奨名
  min_tls_version                 = "TLS1_2"

  blob_properties {
    delete_retention_policy { days = 7 }
  }

  tags = {
    env    = var.env
    system = var.system
  }
}

resource "azurerm_storage_container" "containers" {
  for_each              = toset(var.containers)
  name                  = each.key
  storage_account_name  = azurerm_storage_account.sa.name
  container_access_type = "private"
}

infra/outputs.tf

output "storage_account_name"  { value = azurerm_storage_account.sa.name }
output "primary_blob_endpoint" { value = azurerm_storage_account.sa.primary_blob_endpoint }

infra/envs/dev/terraform.tfvars

# ★ここだけ自分の環境に合わせて修正
resource_group_name = "InductionCourse_202507_son"

# 任意
system     = "demo"
env        = "dev"
containers = ["tfstate"]  # 不要なら []
# location = "japaneast"  # RGと同じで良ければ省略

実行手順

cd your-folder\infra

terraform init
terraform plan -var-file="envs/dev/terraform.tfvars" -out=tfplan
terraform apply "tfplan"
# または: terraform apply -var-file="envs/dev/terraform.tfvars" -auto-approve

成功すると

  • Storage Account 名(例:stdemodev4blozl
  • Blob エンドポイント(例:https://stdemodev4blozl.blob.core.windows.net/
    が出力されます
  • Azure Portalを確認したところ、ちゃんとリソースが作成されていました!

確認コマンド(任意)

az storage account show -n <storage_account_name> -g <resource_group_name> -o table
az storage container list --account-name <storage_account_name> --auth-mode login -o table

よくあるエラーと対処

  • Unsupported argument(プロパティ名の変更)
    allow_blob_public_accessallow_nested_items_to_be_public
    enable_https_traffic_onlyhttps_traffic_only_enabled に置き換え。

  • Resource Provider の登録で 403
    skip_provider_registration = trueprovider "azurerm" に追加。
    併せて Microsoft.StorageRegistered か確認:
    az provider show --namespace Microsoft.Storage --query registrationState -o tsv

  • tfplan が見つからない
    直前の plan -out=tfplan が失敗していないか確認。エラーを直し再実行。

  • 名前規則エラー
    SA名は小文字英数字3〜24文字。system は短め英数字推奨。


片付け(費用防止)

terraform destroy -var-file="envs/dev/terraform.tfvars"

このコマンドを実行した後に

Do you really want to destroy all resources?
  Terraform will destroy all your managed infrastructure, as shown above.
  There is no undo. Only 'yes' will be accepted to confirm.

  Enter a value: yes

と出るので、「yes」を入力した後にEnterを押して削除してください


まとめ

  • Azure CLI を入れてサブスク選択 → Terraform で 既存RG参照→SA作成の流れ
  • 3.x 系ではプロパティ名が刷新されている点に注意
  • 組織の権限制約がある場合は 自動登録オフ+Microsoft.Storage Registered を確認

参考:Windows / macOS / Linux の Azure CLI 公式インストール手順、および Cloud Shell(CLI同梱)。(Microsoft Learn, Homebrew Formulae)

改善点・誤りなどあれば、コメントで教えていただけると嬉しいです!

ヘッドウォータース

Discussion