Bicepを使って仮想NetworkGateway(VPN Gateway)をデプロイする

:::note info
この記事の目的及び背景
検証用のサブスクリプションを移動しろとお達しがあり、Azure Portalからポチポチと構築をする方法しかとってこなかったが、再度同じ環境を作成するにあたり再現可能な状態としたいと考え、調査をしたので備忘を兼ねてに記載する。
:::

# 概要
1. リソースグループをサブスクリプションに作成する
1. 作成したリソースグループに Vnet を作成する
1. 作成した Vnet に VPN Gateway 用の SubNet を作成する
1. 作成したリソースグループに VPN Gateway 用のPublic Ip アドレスを作成する
1. VPN Gateway を作成する

:::note info
つまり、以下のチュートリアルをBicep を使用してコマンド一つで作成する
:::
https://learn.microsoft.com/ja-jp/azure/vpn-gateway/tutorial-site-to-site-portal



## この記事で作成できる成果物
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/232184/8f95232c-b7a0-fca7-dc98-ab27fa97f253.png)

## 参考とした記事

* 以下の記事のほぼ焼き回しとなるが、一つのコマンドで一度に作成可能な点で差別化

https://qiita.com/dessin/items/61b08502705cbaa32439

* 公式ドキュメント

https://learn.microsoft.com/ja-jp/azure/azure-resource-manager/bicep/scenarios-virtual-networks

https://learn.microsoft.com/ja-jp/azure/azure-resource-manager/bicep/deploy-to-subscription?tabs=azure-cli

# スクリプト内容

## 作成スクリプト
* main.bicep : すべての大元となるファイル、処理全体を記載
* vnet-hub.bicep : 仮想ネットワークのResource情報を記載
* publicIP.bicep : Public Ip アドレスのResource情報を記載
* nwgw.bicep : VPN GatewayのResource情報を記載

## main.bicep

* リソースグループを定義

https://learn.microsoft.com/ja-jp/azure/templates/microsoft.resources/resourcegroups?pivots=deployment-language-bicep

* その他のリソースをモジュールとして呼び出す

https://learn.microsoft.com/ja-jp/azure/azure-resource-manager/bicep/modules

```bicep : main.bicep
targetScope='subscription'
param location string = 'japaneast'
param hubResourceGroupName string = 'rg-hub'
param hubVetNmae string = 'vnet-hub'
param hubPublicIPAddressName string = 'publicip-gw-hub'
param hubNetworkGatewayName string = 'network-gw-hub'
param hubTags object = {
  environment: 'hub'
}
param tenantId string = 'xxxx'


resource hubResourceGroup 'Microsoft.Resources/resourceGroups@2024-03-01' = {
  location: location
  name: hubResourceGroupName
  tags: hubTags
}

module hubVnet 'vnet-hub.bicep'={
  scope: hubResourceGroup
  name: hubVetNmae
  params:{
    name: hubVetNmae
    location: location
    tags: hubTags
  }
}

module hubPublicIPAddress 'publicIp.bicep' =  {
  scope: hubResourceGroup
  name: hubPublicIPAddressName
  params:{
    name: hubPublicIPAddressName
    location: location
    tags: hubTags
  }
}

module hubNetworkGateway 'nwgw.bicep' = {
  scope: hubResourceGroup
  name: hubNetworkGatewayName
  params:{
    name: hubNetworkGatewayName
    location: location
    tags: hubTags
    publicIpAddressId: hubPublicIPAddress.outputs.Id
    subnetId: hubVnet.outputs.gwSubnetId
    tenantId: tenantId
  }
}
```

* `targetScope='subscription'`とすることでデフォルトだとResourceグループを指定しないとデプロイできないbicepファイルをサブスクリプションに対してデプロイすることが可能
* `scope` を指定することにより作成したリソースグループに対してリソースをデプロイできる
* リソースグループに対してデプロイするリソースはサブスクリプションに対してデプロイすることができないので`module` 化
* `outputs`を使用することで作成したresourceIdを取得

## vnet-hub.bicep

* 仮想ネットワークとサブネットを定義

https://learn.microsoft.com/ja-jp/azure/templates/microsoft.network/virtualnetworks?pivots=deployment-language-bicep

```bicep: vnet-hub.bicep
param name string
param location string = resourceGroup().location
param tags object = {}
param subnetGwName string = 'GatewaySubnet'

resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-11-01' = {
  name: name
  location: location
  properties: {
    addressSpace: {
      addressPrefixes: [
        '10.0.1.0/24'
      ]
    }
    subnets: [
      {
        name: subnetGwName
        properties: {
          addressPrefix: '10.0.1.0/27'
        }
      }
    ]
  }
  tags: tags

  resource subnetGw 'subnets' existing = {
    name: subnetGwName
  }
}

output gwSubnetId string = virtualNetwork::subnetGw.id
```
* `output`に作成したサブネットのResourceIdを出力

## publicIP.bicep

* public IP アドレスを定義

https://learn.microsoft.com/ja-jp/azure/templates/microsoft.network/publicipaddresses?pivots=deployment-language-bicep

```bicep: publicIP.bicep
param name string
param location string = resourceGroup().location
param tags object = {}

resource publicIPAddresses 'Microsoft.Network/publicIPAddresses@2023-11-01' = {
  name: name
  location: location
  sku: {
    name: 'Standard'
    tier: 'Regional'
  }
  properties: {
    publicIPAddressVersion: 'IPv4'
    publicIPAllocationMethod: 'Static'
    idleTimeoutInMinutes: 4
    ipTags: []
  }
  tags: tags
}

output Id string = publicIPAddresses.id
```
* `output`に作成したpublicIPのResourceIdを出力

## nwgw.bicep

* VPN Gatewayを定義

https://learn.microsoft.com/ja-jp/azure/templates/microsoft.network/virtualnetworkgateways?pivots=deployment-language-bicep

```bicep: nwgw.bicep
param name string
param location string = resourceGroup().location
param tags object = {}
param publicIpAddressId string
param subnetId string
param tenantId string
param vpngwSKU string = 'VpnGw1'
param activeactive bool = false

resource networkGateway 'Microsoft.Network/virtualNetworkGateways@2023-11-01'={
  name: name
  location: location
  tags: tags
  properties: {
    ipConfigurations: [
      {
        id: 'string'
        name: 'string'
        properties: {
          privateIPAllocationMethod: 'Dynamic'
          publicIPAddress: {
            id: publicIpAddressId
          }
          subnet: {
            id: subnetId
          }
        }
      }
    ]
    sku: {
      name: vpngwSKU
      tier: vpngwSKU
    }
    gatewayType: 'Vpn'
    vpnType: 'RouteBased'
    activeActive: activeactive
    vpnClientConfiguration: {
      vpnClientAddressPool: {
        addressPrefixes: [
          '192.168.10.0/24'
        ]
      }
      vpnClientProtocols: [
        'OpenVPN'
      ]
      vpnAuthenticationTypes: [
        'AAD'
      ]
      vpnClientRootCertificates: []
      vpnClientRevokedCertificates: []
      vngClientConnectionConfigurations: []
      radiusServers: []
      vpnClientIpsecPolicies: []
      aadTenant: 'https://login.microsoftonline.com/${tenantId}/'
      aadAudience: '41b23e61-6c1e-4545-b367-cd054e0ed4b4'
      aadIssuer: 'https://sts.windows.net/${tenantId}/'
    }
  }
}
```
* `vpnClientConfiguration`の`addressPrefixes`はローカル環境のIPアドレスをもとに設定
* `vpnClientConfiguration`の認証に関しては以下のドキュメントに記載のある内容を`aadTenant`,`aadAudience`,`aadIssuer`に設定

https://learn.microsoft.com/ja-jp/azure/vpn-gateway/openvpn-azure-ad-tenant#enable-authentication

# デプロイ
* 各bicepファイルを一つのディレクトリに保存し、そのディレクトリにて以下のコマンドを実行してデプロイ
```shell
az deployment sub create --template-file main.bicep --location JapanEast
```

https://learn.microsoft.com/ja-jp/cli/azure/deployment/sub?view=azure-cli-latest#az-deployment-sub-create

:::note warn
デプロイに20分程度かかる
:::

# デプロイが完了したら。。。
* 以下の手順に沿ってVPN clientから設定ファイルをインポートし接続可能であることを確認

https://learn.microsoft.com/ja-jp/azure/vpn-gateway/openvpn-azure-ad-tenant#download-the-azure-vpn-client-profile-configuration-package

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/232184/8af667fb-fe5e-6fdd-238f-b48314e92b3b.png)

# あとがき
* Azure Portalよりポチポチやればそこまで時間がかからない作業だが、スクリプト化することで再現可能なものにすることができた。周囲への配布などにも活用できそう