1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【Azure】Bicepを用いてAzure Firewallを作成する。

Posted at

1. はじめに

1-1 ご挨拶

初めまして、井村と申します。

Azure Firewallを調査する機会があり公式ドキュメントを読んだり、手動でAzure Firewallを作成したりしていました。公式ドキュメントには手動、コマンド、IaC等の手順でデプロイ方法があります。本記事は自分の理解を深めるため、Bicepを用いて構築、簡単な検証を行います。

2. Azure Firewallとは

2-1 ファイアウォールの概要

一般的なファイアウォールの概要となります。

  • ファイアウォールは、ネットワークの送受信トラフィックを 事前定義されたセキュリティ規則 に基づいて監視・制御するセキュリティ装置です。
  • 主な目的は、 信頼された内部ネットワーク信頼されていない外部ネットワーク(例:インターネット) の間に障壁を設け、 悪意のある攻撃から保護することです。

2-2 Azure Firewall の主な機能

Azure Firewallの主な機能は以下の通りです。

1 . ステートフル ファイアウォール

  • アクティブな接続の状態を追跡し、トラフィックのコンテキストに基づいて判断することができます。

2 . 高可用性と可用性ゾーン対応

  • 障害や高負荷時でも安定運用している。
  • 複数の可用性ゾーンにまたがる構成で、回復性と信頼性を実現できます。

3 . ネットワーク & アプリケーションレベルのフィルタリング

  • IP、ポート、プロトコルに基づくトラフィック制御をおこないます。
  • HTTP/Sなどのアプリケーション層プロトコルにも対応し、FQDN(完全修飾ドメイン名)単位でアクセス制御可能です。

4 . NAT(ネットワークアドレス変換)

  • SNAT:内部のプライベートIPをAzureのパブリックIPに変換(外向き通信)。
  • DNAT:外部からのパブリックIPを内部のプライベートIPに変換(内向き通信)。

5 . 脅威インテリジェンス統合

  • Microsoftの脅威情報を活用し、悪意のあるIPやドメインを検出・ブロックできます。
  • アラートや拒否ルールの設定が可能。

6 . ログ記録と監視

  • Azure Monitor、Log Analytics、Event Hubsと連携して、トラフィックの分析や問題診断が可能。

000_1.png

参考

2-3 Azure Firewall のSKU(種類)とおすすめの用途

Azure Frewallには3つの種類があります。種類によって利用可能な機能、金額が異なります。

SKU 対象 主な特徴
Basic SMB(中小企業) 最大 250 Mbps、基本的な保護機能
Standard 一般企業 L3〜L7のフィルタリング、脅威インテリジェンス、DNSプロキシ、Webカテゴリなど
Premium 機密性の高い業務(例:支払処理) マルウェア対策、TLS検査、IDPSなどの高度な脅威保護

詳細な内容は公式ドキュメントから確認できます。

000_2.png

参考

3. 事前準備

3-1 リソースグループの作成

公式ドキュメントに沿って Azure CLIVisual Studio Code と Bicep 拡張機能をインスールします。
上記終了後、Azure上にリソースを作成します。

1 . Azureへログイン

Azure上にリソースを作成するためログインします。

Azure CLI
az login

現在ログインしているAzureサブスクリプションを確認するには、以下のAzure CLIコマンドを使用します

Azure CLI
az account show

2 . リソースグループの作成

東日本リージョンで作成します。

Azure CLI
az group create --name rg-demo-dev --location japaneast

Azure上にリソースグループが作成されました。

001.png

4. 構築

Bicepで作成するリソースは以下の通りです。

Arch_Firewall.jpg

4-1 Bicepの準備

main.bicep
main.bicep
@description('作成するシステム名を指定します。')
param systemName string = 'demo'

@description('リソースグループのロケーション。今回は東日本リージョン (Japan East) を指定します。')
param location string = 'japaneast'

@description('環境を指定します。dev, stg, pro のいずれかを選択してください。')
@allowed([
  'dev'
  'stg'
  'pro'
])
param env string = 'dev'

@description('仮想ネットワークのアドレスプレフィックス(例: 10.0.0.0/16)')
param addressPrefixes array = [
  '10.0.0.0/16'
]

@description('可用性ゾーンを設定します。Zone numbers e.g. 1,2,3.')
param availabilityZones array = []

@description('仮想マシンのOSバージョンを指定します。')
@allowed([
  '2022-datacenter'
  '2022-datacenter-azure-edition'
  '2022-datacenter-azure-edition-core'
  '2022-datacenter-azure-edition-core-smalldisk'
  '2022-datacenter-azure-edition-smalldisk'
  '2022-datacenter-core'
  '2022-datacenter-core-g2'
  '2022-datacenter-core-smalldisk'
  '2022-datacenter-core-smalldisk-g2'
  '2022-datacenter-g2'
  '2022-datacenter-smalldisk'
  '2022-datacenter-smalldisk-g2'
])
param OSVersion string = '2022-datacenter-azure-edition-smalldisk'

@description('仮想マシンのサイズを指定します。')
@allowed([
  'Standard_B1s'
  'Standard_B1ms'
  'Standard_B2s'
  'Standard_F1'
  'Standard_B2ms'
])
param vmSize string = 'Standard_B2ms'

@description('マネージドディスクの種類を指定します。')
@allowed([
  'PremiumV2_LRS'
  'Premium_LRS'
  'Premium_ZRS'
  'StandardSSD_LRS'
  'StandardSSD_ZRS'
  'Standard_LRS'
  'UltraSSD_LRS'
])
param storageAccountType string = 'Standard_LRS'

@description('仮想マシンのログインユーザー名を指定します。' )
param adminUsername string = 'azureuser'

@description('仮想マシンのログインパスワードを指定します。' )
@minLength(12)
@secure()
param adminPassword string // P@ssw0rd1234!

@description('ネットワークセキュリティグループの名前。')
var nsgName = 'nsg-${systemName}-${env}'

@description('仮想ネットワークの名前。')
var vnetName = 'vnet-${systemName}-${env}'

@description('作成するサブネットの一覧。各サブネットに名前とアドレスプレフィックスを指定します。')
var subnets = [
  {
    name: 'snet-worker'
    subnetPrefix: '10.0.1.0/24'
  }
  {
    name: 'AzureFirewallSubnet' // Azure Firewall 用の予約サブネット名
    subnetPrefix: '10.0.10.0/26'
  }
  {
    name: 'AzureBastionSubnet' // Azure Bastion 用の予約サブネット名
    subnetPrefix: '10.0.11.0/26'
  }
]

@description('Azure Firewall のプライベートIPアドレス。')
var nextHopIP = '10.0.10.4'

@description('Azure Firewall のプライベートIPアドレス。')
var vmPriIP = '10.0.1.4'

@description('ファイアウォールのパブリックIPアドレスの名前。')
var pipFWName = 'pip-${systemName}-${env}-fw'

@description('Azure BastionのパブリックIPアドレスの名前。')
var pipbasName = 'pip-${systemName}-${env}-bas'

@description('ファイアウォールの名前。')
var afwName = 'afw-${systemName}-${env}'

@description('ファイアウォールポリシーの名前。')
var afwpName = 'afwp-${systemName}-${env}'

@description('ルートテーブルの名前。')
var rtName = 'rt-${systemName}-${env}'

@description('カスタムルート(UDR:ユーザ定義ルート)の名前。' )
var udrName = 'udr-${systemName}-${env}'

@description('ネットワークインターフェイスの名前。')
var nicName = 'nic-${systemName}-${env}'

@description('仮想マシンの名前。')
var vmName = 'vm-${systemName}-${env}'

@description('仮想マシンのマネージドランコマンドの名前。')
var rcName = 'rc-${systemName}-${env}'

@description('Azure Bastionの名前。')
var basName = 'bas-${systemName}-${env}'

// リソース作成
// ネットワークセキュリティグループの作成
resource nsg 'Microsoft.Network/networkSecurityGroups@2024-07-01' = {
  name: nsgName
  location: location
  properties: {
    securityRules: [
      {
        name: 'AllowInBoundRDP'
        properties: {
          priority: 100
          protocol: 'TCP'
          access: 'Allow'
          direction: 'Inbound'
          sourceAddressPrefix: subnets[2].subnetPrefix
          destinationAddressPrefix: subnets[0].subnetPrefix
          sourcePortRange: '*'
          destinationPortRange: '3389'
        }
      }
      {
        name: 'AllowVnetInBound'
        properties: {
          priority: 200
          protocol: 'Tcp'
          access: 'Allow'
          direction: 'Inbound'
          sourceAddressPrefix: subnets[1].subnetPrefix
          destinationAddressPrefix: subnets[0].subnetPrefix
          sourcePortRange: '*'
          destinationPortRange: '80'
        }
      }
    ]
  }
}

// ファイアウォール用パブリックアドレスアドレスの作成
resource pipFW 'Microsoft.Network/publicIPAddresses@2023-11-01' = {
  name: pipFWName
  location: location
  zones: ((length(availabilityZones) == 0) ? null : availabilityZones)
  sku: {
      name: 'Standard'
  }
  properties: {
    publicIPAllocationMethod: 'Static'
    publicIPAddressVersion: 'IPv4'
  }
}

// Azure Bastion用パブリックアドレスの作成
resource pipBastion 'Microsoft.Network/publicIPAddresses@2023-11-01' = {
  name: pipbasName
  location: location
  zones: ((length(availabilityZones) == 0) ? null : availabilityZones)
  sku: {
      name: 'Standard'
  }
  properties: {
    publicIPAllocationMethod: 'Static'
    publicIPAddressVersion: 'IPv4'
  }
}

// ルートテーブルの作成
resource rt 'Microsoft.Network/routeTables@2023-09-01' = {
  name: rtName
  location: location
  properties: {
    disableBgpRoutePropagation: false
    routes: [
      {
        name: udrName
        properties: {
          addressPrefix: '0.0.0.0/0'
          nextHopType: 'VirtualAppliance'
          nextHopIpAddress: nextHopIP
        }
      }
    ]
  }
}

// 仮想ネットワークの作成
resource vnet 'Microsoft.Network/virtualNetworks@2023-11-01' = {
  name: vnetName
  location: location
  properties: {
    addressSpace: {
      addressPrefixes: addressPrefixes
    }
    subnets: [
      {
        name: subnets[0].name
        properties: {
          addressPrefix: subnets[0].subnetPrefix
          routeTable: {
            id: rt.id
          }
          networkSecurityGroup: {
            id: nsg.id
          }
        }
      }
      {
        name: subnets[1].name
        properties: {
          addressPrefix: subnets[1].subnetPrefix
        }
      }
      {
        name: subnets[2].name
        properties: {
          addressPrefix: subnets[2].subnetPrefix
        }
      }
    ]
  }
}

// ファイアウォールポリシーの作成
resource afwp 'Microsoft.Network/firewallPolicies@2022-01-01'= {
  name: afwpName
  location: location
  properties: {
    threatIntelMode: 'Off'
  }
}

// DNATルールコレクショングループの作成
resource dnatRuleCollectionGroup 'Microsoft.Network/firewallPolicies/ruleCollectionGroups@2022-01-01' = {
  parent: afwp
  name: 'DefaultDnatRuleCollectionGroup'
  properties: {
    priority: 100
    ruleCollections: [
      {
        ruleCollectionType: 'FirewallPolicyNatRuleCollection'
        action: {
          type: 'Dnat'
        }
        name: 'dnat-rule-collection'
        priority: 100
        rules: [
          {
            ruleType: 'NatRule'
            name: 'dnat-rule-01'
            sourceAddresses: [
              '*'
            ]
            destinationAddresses: [
              pipFW.properties.ipAddress
            ]
            destinationPorts: [
              '80'
            ]
            translatedAddress: vmPriIP
            translatedPort: '80'
            ipProtocols: [
              'TCP'
            ]
          }
        ]
      }
    ]
  }
}

// アプリケーションルールコレクショングループの作成
resource applicationRuleCollectionGroup 'Microsoft.Network/firewallPolicies/ruleCollectionGroups@2022-01-01' = {
  parent: afwp
  name: 'DefaultApplicationRuleCollectionGroup'
  properties: {
    priority: 300
    ruleCollections: [
      {
        ruleCollectionType: 'FirewallPolicyFilterRuleCollection'
        name: 'update-rule-win'
        priority: 100
        action: {
          type: 'Allow'
        }
        rules: [
          {
            ruleType: 'ApplicationRule'
            name: 'winupdate-rule-01'
            protocols: [
              {
                protocolType: 'Https'
                port: 443
              }
              {
                protocolType: 'Http'
                port: 80
              }
            ]
            fqdnTags: [
              'WindowsUpdate'
            ]
            terminateTLS: false
            sourceAddresses: [
              subnets[0].subnetPrefix
            ]
          }
        ]
      }
      {
        ruleCollectionType: 'FirewallPolicyFilterRuleCollection'
        name: 'global-rule-url-microsoft'
        priority: 200
        action: {
          type: 'Allow'
        }
        rules: [
          {
            ruleType: 'ApplicationRule'
            name: 'microsoft-rule-01'
            protocols: [
              {
                protocolType: 'Https'
                port: 443
              }
            ]
            targetFqdns: [
              '*.microsoft.com'
            ]
            terminateTLS: false
            sourceAddresses: [
              subnets[0].subnetPrefix
            ]
          }
        ]
      }
    ]
  }
  dependsOn: [
    dnatRuleCollectionGroup
  ]
}

// ファイアウォールの作成
resource afw 'Microsoft.Network/azureFirewalls@2023-11-01' = {
  name: afwName
  location: location
  zones: ((length(availabilityZones) == 0) ? null : availabilityZones)
  properties: {
    sku: {
      name: 'AZFW_VNet'
      tier: 'Standard'
    }
    firewallPolicy: {
      id: afwp.id
    }
    ipConfigurations: [
      {
        name: 'ipconfig1'
        properties: {
          subnet: {
            id: vnet.properties.subnets[1].id
          }
          publicIPAddress: {
            id: pipFW.id
          }
        }
      }
    ]
  }
  dependsOn: [
    dnatRuleCollectionGroup
    applicationRuleCollectionGroup
  ]
}

// ネットワークインターフェイスの作成
resource nic 'Microsoft.Network/networkInterfaces@2021-02-01' = {
  name: nicName
  location: location
  properties: {
    ipConfigurations: [
      {
        name: 'ipconfig1'
        properties: {
          privateIPAllocationMethod: 'Dynamic'
          subnet: {
            id: resourceId('Microsoft.Network/virtualNetworks/subnets', vnet.name, subnets[0].name)
          }
        }
      }
    ]
  }
}

// 仮想マシンの作成
resource vm 'Microsoft.Compute/virtualMachines@2021-07-01' = {
  name: vmName
  location: location
  properties: {
    hardwareProfile: {
      vmSize: vmSize
    }
    osProfile: {
      computerName: vmName
      adminUsername: adminUsername
      adminPassword: adminPassword
    }
    storageProfile: {
      imageReference: {
        publisher: 'MicrosoftWindowsServer'
        offer: 'WindowsServer'
        sku: OSVersion
        version: 'latest'
      }
      osDisk: {
        createOption: 'FromImage'
        managedDisk: {
          storageAccountType: storageAccountType
        }
      }
    }
    networkProfile: {
      networkInterfaces: [
        {
          id: nic.id
        }
      ]
    }
  }
}

// Managed Run Command
resource runCommand 'Microsoft.Compute/virtualMachines/runCommands@2024-03-01' = {
  name: rcName
  location: location
  parent: vm
  properties: {
    source: {
      script: 'Install-WindowsFeature -Name Web-Server -IncludeManagementTools'
    }
  }
}

// Azure Bastionの作成
resource bastion 'Microsoft.Network/bastionHosts@2023-11-01' = {
  name: basName
  location: location
  properties: {
    ipConfigurations: [
      {
        name: 'bastionIpConfig'
        properties: {
          subnet: {
            id: resourceId('Microsoft.Network/virtualNetworks/subnets', vnet.name, 'AzureBastionSubnet')
          }
          publicIPAddress: {
            id: pipBastion.id
          }
        }
      }
    ]
  }
}

4-2 リソースのデプロイ

Azure CLI
az deployment group create --template-file main.bicep --resource-group rg-demo-dev

※仮想マシンのログインパスワードを聞かれますので設定します。

正常終了するとリソースが作成されます。

004.png

5. 検証

DNATルールコレクショングループおよびアプリケーションルールコレクショングループの検証をおこないます。

5-1 DNat

1 . DNAT検証を行います。Azure Firewallに関連付けされているパブリックIPアドバイスに対してブラウザからアクセスします。

005.png

2 . Webサーバにアクセスできました。

006.png

5-2 アプリケーション

Azure Bastion経由で仮想マシンにログインします。

1 . 仮想マシンのEdgeを開きOfficeを開きます。

007.png

2 . ブロックされることが確認できました。

008.png

3 . 許可している microsoft.com にアクセスします。

009.png

4 . アクセスできました。

010.png

5 . Windows Updateを確認します。

011.png

6 . インストール&再起動後、適用済みのWindows Updateを確認します。反映されていることが確認できました。

012.png

6. 終わりに

本記事を最後まで読んで頂きましてありがとうございます。
無事にIaCを利用して構築・検証まで出来ました。課題が発生した際に調査し、解決すると一安心ですね。

7. 参考

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?