💻

AzureFileSyncを試してみる その1

2022/09/20に公開

はじめに

Azure File Syncを試してみたかったので、Terraformで環境を作ってみました。色々とハマったところもあり、残しておきます。3回くらいに分けて書く予定。

システム構成

Azure File Syncはオンプレファイルサーバと接続してハイブリッドクラウド的な感じで使うようなサービスかと思います。今回はオンプレ側が用意できないので、Azure VM立ててそれと接続してます。細かい部分は後述してきますが、こんなイメージのものを作っていきたいと思います。以降、tfファイルごとにリソースの定義を説明してきます。

お決まり部分の定義

Terraformのバージョンやプロバイダーのバージョンを指定します。なお、このコードではバージョン固定にはしてませんが、Terraform 1.2.8、Azureのプロバイダー(azurerm 3.23.0、azuread 2.28.1)を利用しました。また、Azureで必須となるリソースグループをここで定義しています。

main.tf
terraform {

  required_version = "~>1.2.0"

  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "~>3.23.0"
    }
    azuread = {
      source  = "hashicorp/azuread"
      version = "~>2.28.0"
    }
  }
}

provider "azurerm" {
  features {}
}

resource "azurerm_resource_group" "this" {
  name     = "dev-rg"
  location = var.resource_group_location
}

変数の定義は以下のようにしてます。リソースグループのロケーションは東日本リージョンとしました。サブネットのアドレスもここで定義してます。

valiables.tf
variable "resource_group_location" {
  default     = "japaneast"
  description = "Location of the resource group"
}

variable "vnet_address" {
  type        = list(string)
  default     = ["10.0.0.0/16"]
  description = "virtual network address"
}

variable "vnet_subnet" {
  type        = list(string)
  default     = ["10.0.1.0/24"]
  description = "virtual network subnet"
}

variable "vnet_bastion_subnet" {
  type        = list(string)
  default     = ["10.0.0.192/26"]
  description = "bastion subnet(require a minimum of /26)"
}

ここまでで、この部分の定義ができました。(あまり意味ない絵ですが。。)

ネットワーク周りの定義

ネットワーク周りを作ります。Azure VMへのアクセスはBastion使いたいので、プライベートなサブネット(dev-subnet1)とBastion用のサブネット(AzureBastionSubnet)を用意しています。あとストレージアカウントとはサービスエンドポイントでつなぎたいので、その定義もしてます。

network.tf
resource "azurerm_virtual_network" "this" {
  name                = "dev-vnet"
  location            = azurerm_resource_group.this.location
  resource_group_name = azurerm_resource_group.this.name
  address_space       = var.vnet_address
}

resource "azurerm_subnet" "bastion_subnet" {
  name                 = "AzureBastionSubnet"
  resource_group_name  = azurerm_resource_group.this.name
  virtual_network_name = azurerm_virtual_network.this.name
  address_prefixes     = var.vnet_bastion_subnet
}

resource "azurerm_subnet" "dev_subnet1" {
  name                 = "dev-subnet1"
  resource_group_name  = azurerm_resource_group.this.name
  virtual_network_name = azurerm_virtual_network.this.name
  address_prefixes     = var.vnet_subnet
  service_endpoints    = ["Microsoft.Storage"]
}

次にNSGを作ります。dev-nsg-publicではBastionに必要となる通信を開けてます。[1]dev-nsg-privateではプライベートサブネットへの外部からの接続は基本NGとし、例外としてBastionサブネットからのRDPを許可してます。プライベートサブネットからの外部接続はhttpとhttpsのみ許可してます。[2]作成したNSGを各サブネットに適用します。dev-nsg-publicはAzureBastionSubnetに、dev-nsg-privateはdev-subnet1に紐づけてます。

nsg.tf
resource "azurerm_network_security_group" "public" {
  name                = "dev-nsg-public"
  location            = azurerm_resource_group.this.location
  resource_group_name = azurerm_resource_group.this.name
}

resource "azurerm_network_security_rule" "allow_https_inbound_bastion" {
  name                        = "AllowHttpsInbound"
  priority                    = 100
  direction                   = "Inbound"
  access                      = "Allow"
  protocol                    = "Tcp"
  source_port_range           = "*"
  destination_port_range      = "443"
  source_address_prefix       = "Internet"
  destination_address_prefix  = "*"
  resource_group_name         = azurerm_resource_group.this.name
  network_security_group_name = azurerm_network_security_group.public.name
}

resource "azurerm_network_security_rule" "allow_communication_inbound_bastion" {
  name                        = "AllowBastionHostCommunicationInbound"
  priority                    = 110
  direction                   = "Inbound"
  access                      = "Allow"
  protocol                    = "*"
  source_port_range           = "*"
  destination_port_ranges     = ["8080", "5701"]
  source_address_prefix       = "VirtualNetwork"
  destination_address_prefix  = "VirtualNetwork"
  resource_group_name         = azurerm_resource_group.this.name
  network_security_group_name = azurerm_network_security_group.public.name
}

resource "azurerm_network_security_rule" "allow_gatewaymanager_inbound_bastion" {
  name                        = "AllowGatewayManagerInbound"
  priority                    = 120
  direction                   = "Inbound"
  access                      = "Allow"
  protocol                    = "Tcp"
  source_port_range           = "*"
  destination_port_range      = "443"
  source_address_prefix       = "GatewayManager"
  destination_address_prefix  = "*"
  resource_group_name         = azurerm_resource_group.this.name
  network_security_group_name = azurerm_network_security_group.public.name
}

resource "azurerm_network_security_rule" "allow_loadbalancer_inbound_bastion" {
  name                        = "AllowAzureLoadBalancerInbound"
  priority                    = 130
  direction                   = "Inbound"
  access                      = "Allow"
  protocol                    = "Tcp"
  source_port_range           = "*"
  destination_port_range      = "443"
  source_address_prefix       = "AzureLoadBalancer"
  destination_address_prefix  = "*"
  resource_group_name         = azurerm_resource_group.this.name
  network_security_group_name = azurerm_network_security_group.public.name
}

resource "azurerm_network_security_rule" "deny_all_inbound_bastion" {
  name                        = "DenyAllInbound"
  priority                    = 200
  direction                   = "Inbound"
  access                      = "Deny"
  protocol                    = "*"
  source_port_range           = "*"
  destination_port_range      = "*"
  source_address_prefix       = "*"
  destination_address_prefix  = "*"
  resource_group_name         = azurerm_resource_group.this.name
  network_security_group_name = azurerm_network_security_group.public.name
}


resource "azurerm_network_security_rule" "allow_sshrdp_outbound_bastion" {
  name                        = "AllowSshRdpOutbound"
  priority                    = 100
  direction                   = "Outbound"
  access                      = "Allow"
  protocol                    = "*"
  source_port_range           = "*"
  destination_port_ranges     = ["22", "3389"]
  source_address_prefix       = "*"
  destination_address_prefix  = "VirtualNetwork"
  resource_group_name         = azurerm_resource_group.this.name
  network_security_group_name = azurerm_network_security_group.public.name
}

resource "azurerm_network_security_rule" "allow_azurecloud_outbound_bastion" {
  name                        = "AllowAzureCloudOutbound"
  priority                    = 110
  direction                   = "Outbound"
  access                      = "Allow"
  protocol                    = "Tcp"
  source_port_range           = "*"
  destination_port_range      = "443"
  source_address_prefix       = "*"
  destination_address_prefix  = "AzureCloud"
  resource_group_name         = azurerm_resource_group.this.name
  network_security_group_name = azurerm_network_security_group.public.name
}

resource "azurerm_network_security_rule" "allow_communication_outbound_bastion" {
  name                        = "AllowBastionHostCommunicationOutbound"
  priority                    = 120
  direction                   = "Outbound"
  access                      = "Allow"
  protocol                    = "*"
  source_port_range           = "*"
  destination_port_ranges     = ["8080", "5701"]
  source_address_prefix       = "VirtualNetwork"
  destination_address_prefix  = "VirtualNetwork"
  resource_group_name         = azurerm_resource_group.this.name
  network_security_group_name = azurerm_network_security_group.public.name
}

resource "azurerm_network_security_rule" "allow_http_outbound_bastion" {
  name                        = "AllowGetSessionInformation"
  priority                    = 130
  direction                   = "Outbound"
  access                      = "Allow"
  protocol                    = "*"
  source_port_range           = "*"
  destination_port_range      = "80"
  source_address_prefix       = "*"
  destination_address_prefix  = "Internet"
  resource_group_name         = azurerm_resource_group.this.name
  network_security_group_name = azurerm_network_security_group.public.name
}

resource "azurerm_network_security_rule" "deny_all_outbound_bastion" {
  name                        = "DenyAllOutbound"
  priority                    = 200
  direction                   = "Outbound"
  access                      = "Deny"
  protocol                    = "*"
  source_port_range           = "*"
  destination_port_range      = "*"
  source_address_prefix       = "*"
  destination_address_prefix  = "*"
  resource_group_name         = azurerm_resource_group.this.name
  network_security_group_name = azurerm_network_security_group.public.name
}


resource "azurerm_network_security_group" "private" {
  name                = "dev-nsg-private"
  location            = azurerm_resource_group.this.location
  resource_group_name = azurerm_resource_group.this.name
}

resource "azurerm_network_security_rule" "allow_rdp_inbound_private" {
  name                        = "AllowRDPInbound_private"
  priority                    = 100
  direction                   = "Inbound"
  access                      = "Allow"
  protocol                    = "*"
  source_port_range           = "*"
  destination_port_range      = "3389"
  source_address_prefixes     = var.vnet_bastion_subnet
  destination_address_prefix  = "*"
  resource_group_name         = azurerm_resource_group.this.name
  network_security_group_name = azurerm_network_security_group.private.name
}

resource "azurerm_network_security_rule" "deny_all_inbound_private" {
  name                        = "DenyAllInbound_private"
  priority                    = 200
  direction                   = "Inbound"
  access                      = "Deny"
  protocol                    = "*"
  source_port_range           = "*"
  destination_port_range      = "*"
  source_address_prefix       = "*"
  destination_address_prefix  = "*"
  resource_group_name         = azurerm_resource_group.this.name
  network_security_group_name = azurerm_network_security_group.private.name
}

resource "azurerm_network_security_rule" "allow_http_outbound_private" {
  name                        = "AllowHttpOutbound_private"
  priority                    = 100
  direction                   = "Outbound"
  access                      = "Allow"
  protocol                    = "Tcp"
  source_port_range           = "*"
  destination_port_range      = "80"
  source_address_prefix       = "*"
  destination_address_prefix  = "*"
  resource_group_name         = azurerm_resource_group.this.name
  network_security_group_name = azurerm_network_security_group.private.name
}

resource "azurerm_network_security_rule" "allow_https_outbound_private" {
  name                        = "AllowHttpsOutbound_private"
  priority                    = 110
  direction                   = "Outbound"
  access                      = "Allow"
  protocol                    = "Tcp"
  source_port_range           = "*"
  destination_port_range      = "443"
  source_address_prefix       = "*"
  destination_address_prefix  = "*"
  resource_group_name         = azurerm_resource_group.this.name
  network_security_group_name = azurerm_network_security_group.private.name
}

resource "azurerm_network_security_rule" "deny_all_outbound_private" {
  name                        = "DenyAllOutbound_private"
  priority                    = 200
  direction                   = "Outbound"
  access                      = "Deny"
  protocol                    = "*"
  source_port_range           = "*"
  destination_port_range      = "*"
  source_address_prefix       = "*"
  destination_address_prefix  = "*"
  resource_group_name         = azurerm_resource_group.this.name
  network_security_group_name = azurerm_network_security_group.private.name
}

resource "azurerm_subnet_network_security_group_association" "public" {
  subnet_id                 = azurerm_subnet.bastion_subnet.id
  network_security_group_id = azurerm_network_security_group.public.id
  depends_on = [
    azurerm_network_security_rule.allow_azurecloud_outbound_bastion,
    azurerm_network_security_rule.allow_communication_inbound_bastion,
    azurerm_network_security_rule.allow_communication_outbound_bastion,
    azurerm_network_security_rule.allow_gatewaymanager_inbound_bastion,
    azurerm_network_security_rule.allow_http_outbound_bastion,
    azurerm_network_security_rule.allow_https_inbound_bastion,
    azurerm_network_security_rule.allow_loadbalancer_inbound_bastion,
    azurerm_network_security_rule.allow_sshrdp_outbound_bastion,
    azurerm_network_security_rule.deny_all_inbound_bastion,
    azurerm_network_security_rule.deny_all_outbound_bastion
  ]
}

resource "azurerm_subnet_network_security_group_association" "private" {
  subnet_id                 = azurerm_subnet.dev_subnet1.id
  network_security_group_id = azurerm_network_security_group.private.id
}

ネットワーク周りの定義ができました。

Bastionの定義

Bastionを作ります。Bastionの要件を満たすPIP[3]を作ってBastionに紐づけてます。

bastion.tf
resource "azurerm_public_ip" "this" {
  name                = "dev-bastion-ip"
  resource_group_name = azurerm_resource_group.this.name
  location            = azurerm_resource_group.this.location
  allocation_method   = "Static"
  sku                 = "Standard"
}

resource "azurerm_bastion_host" "this" {
  name                = "dev-bastion"
  location            = azurerm_resource_group.this.location
  resource_group_name = azurerm_resource_group.this.name

  ip_configuration {
    name                 = "public"
    subnet_id            = azurerm_subnet.bastion_subnet.id
    public_ip_address_id = azurerm_public_ip.this.id
  }
}

Bastionの定義ができました。

おわりに

今回はここまで。次回はAzure VM立ててエージェント入れる部分の定義やストレージ周りの定義について書きたいと思います。

脚注
  1. https://docs.microsoft.com/ja-jp/azure/bastion/bastion-nsg ↩︎

  2. Azure既定のSNATを利用。168.63.129.16や169.254.169.254、KMSのアドレスあたりは明示的に許可しなくても通信できました。 ↩︎

  3. https://learn.microsoft.com/ja-jp/azure/virtual-network/ip-services/configure-public-ip-bastion ↩︎

Discussion