【Azure】Bicepを用いてストレージアカウントへ接続するプライベートエンドポイントを作成する。

# 1. はじめに
### 1-1 ご挨拶
初めまして、井村と申します。
今更ですが Azure リソースをデプロイするドメイン固有言語 (DSL) であるBicepが使いやすいそうです。プライベートエンドポイントはよく利用するAzureサービスなので今回デプロイしてみました。備忘録として記事にします。

### 1-2 対象読者
- Azureに興味がある
- Bicepに興味がある

### 1-3 成果物
プライベートエンドポイントをデプロイすると自動的にNICが生成されます。今回はストレージアカウント用のプライベートエンドポイント、ストレージアカウント、プライベートDNSゾーンをデプロイします。

<img width="500" alt="SystemConfiguration.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1989465/18672332-648d-3bc7-5c33-042d3c72052d.png">


**図1 システム構成**

※事前にAzureアカウントは作成済みです。Azure CLI、Bicepはインストール済みです。

# 2. テンプレートの構成について
今回利用するBicepテンプレートは以下になります。

<details><summary>main.bicep</summary>

```bicep:bicep

// ---- 変数宣言 ----
@description('システムコード')
param systemCode string = 'hawk'

@description('リージョンはリソースグループと同様')
param location string = resourceGroup().location

@description('仮想ネットワーク名')
param virtualNetworkName string = 'vnet-${systemCode}'

@description('サブネット名')
param snetName string = 'snet-${systemCode}-private-endpoint'

@description('仮想ネットワーク用のプレフィックス')
param addressPrefix string = '10.0.0.0/16'

@description('サブネット用のプレフィックス')
param subnetPrefix string = '10.0.0.0/24'

@description('ストレージアカウント名')
param storageAccountsName string = 'st${systemCode}${uniqueString(resourceGroup().id)}'

@description('プライベートエンドポイント名')
param privateEndpointName string = 'private-endpoint-${storageAccountsName}'

@description('プライベートDNSゾーン名')
param privateDnsZonesName string = 'pdnsz-privatelink.${environment().suffixes.storage}'

@description('仮想ネットワークリンク名')
param virtualNetworkLinkName string = '${privateDnsZonesName}-${virtualNetworkName}'

// ---- 仮想ネットワーク作成 ----
resource virtualNetwork 'Microsoft.Network/virtualNetworks@2020-11-01' = {
  name: virtualNetworkName
  location: location
  properties: {
    addressSpace: {
      addressPrefixes: [
        addressPrefix
      ]
    }
    subnets: [
      {
        name: snetName
        properties: {
          addressPrefix: subnetPrefix
        }
      }
    ]
  }
  resource subnet1 'subnets' existing = {
    name: snetName
  }

}

// ---- プライベートDNSゾーン作成 ----
resource privateDnsZones 'Microsoft.Network/privateDnsZones@2018-09-01' = {
  name: privateDnsZonesName
  location: 'global'
  resource storageAccountsRecord 'A' = {
    name: storageAccountsName
    properties: {
      ttl: 3600
      aRecords: [
        {
          ipv4Address: first(first(privateEndpoint.properties.customDnsConfigs).ipAddresses)
        }
      ]
    }
  }
  resource link 'virtualNetworkLinks' = {
    name: virtualNetworkLinkName
    location: 'global'
    properties: {
      registrationEnabled: false
      virtualNetwork: {
        id: virtualNetwork.id
      }
    }
  }
}

// ---- ストレージアカウント作成 ----
resource storageAccounts 'Microsoft.Storage/storageAccounts@2022-05-01' = {
  name: storageAccountsName
  location: location
  sku: {
    name: 'Standard_LRS'
  }
  kind: 'StorageV2'
  properties: {
    accessTier: 'Hot'
  }
  resource spc 'privateEndpointConnections' = {
    name: storageAccountsName
    properties: {
      privateEndpoint: {}
      privateLinkServiceConnectionState: {
        status: 'Approved'
      }
    }
  }
}

// ---- プライベートエンドポイント作成 ----
resource privateEndpoint 'Microsoft.Network/privateEndpoints@2020-11-01' = {
  name: privateEndpointName
  location: location
  properties: {
    privateLinkServiceConnections: [
      {
        name: privateEndpointName
        properties: {
          privateLinkServiceId: storageAccounts.id
          groupIds: [
            'blob'
          ]
        }
      }
    ]
    subnet: {
      id: virtualNetwork::subnet1.id
    }
  }
}


```
</details>


# 3. 構築
それでは、構築始めます。リソースグループはAzure CLIで作成します。
### 3-1 リソースグループの作成

```bash:bash
# Azureへログイン
az login

# 変数宣言
systemCode=hawk
myResourceGroup="rg-$systemCode"
location=japaneast

# リソースグループの作成
az group create -l $location -n $myResourceGroup
```

### 3-2 各Azureサービスの作成
項番2で記述したBicepテンプレートを利用して各Azureサービスをデプロイします。

```bash:bash
# Azureへログイン
az login

# 変数宣言
systemCode=hawk
myResourceGroup="rg-$systemCode"
location=japaneast

# Azureサービスの作成
az deployment group create --resource-group $myResourceGroup --template-file main.bicep

```

# 4. 設定確認
デプロイされた各Azureサービスにて私が今まで気にしてなかったり、勉強になった部分を紹介いたします。

### 4-1 プライベートDNSゾーン
#### 4-1-1 レコード
Aレコードの名前を変数storageAccountsNameで定義、IPアドレスをプライベートエンドポイントから取得しています。

<img width="500" alt="1_qiita_dns1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1989465/63375a45-369b-520f-b429-458cfac4897d.png">

```bicep:bicep
  resource storageAccountsRecord 'A' = {
    name: storageAccountsName
    properties: {
      ttl: 3600
      aRecords: [
        {
          ipv4Address: first(first(privateEndpoint.properties.customDnsConfigs).ipAddresses)
        }
      ]
    }

```
#### 4-1-2 仮想ネットワークリンク
このような設定がありましたね。勉強不足でございました。
以下リンクの抜粋になります。
「zure でプライベート DNS ゾーンを作成したら、仮想ネットワークをそれにリンクする必要があります。 リンクされると、その仮想ネットワークでホストされている VM はプライベート DNS ゾーンにアクセスできるようになります。」
[仮想ネットワーク リンクとは](https://learn.microsoft.com/ja-jp/azure/dns/private-dns-virtual-network-links)


<img width="500" alt="2_qiita_dns2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1989465/16080e28-d66a-80d0-411b-b66f91c75a32.png">

```bicep:bicep
  resource link 'virtualNetworkLinks' = {
    name: virtualNetworkLinkName
    location: 'global'
    properties: {
      registrationEnabled: false
      virtualNetwork: {
        id: virtualNetwork.id
      }
    }
  }

```

### 4-2 ストレージアカウント
#### 4-2-1 エンドポイントコネクション(接続)
こちらも必須でしたので設定しました。

<img width="500" alt="3_qiita_st1.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1989465/81117dd5-f6ee-776d-4731-58becd6dda17.png">

```bicep:bicep
  resource spc 'privateEndpointConnections' = {
    name: storageAccountsName
    properties: {
      privateEndpoint: {}
      privateLinkServiceConnectionState: {
        status: 'Approved'
      }
    }
  }

```

# 5. 動作確認
Azureポータルから手動で仮想マシンを作成しました。その仮想マシンにログインし、ドメイン名からIPアドレスを確認しました。
結果、プライベートIPアドレスを取得することができました。

![test.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1989465/9470756f-cd47-50a7-82b5-c9d6943b9a6d.png)

# 6. デプロイ時のエラー
今回Bicepテンプレートを用いてデプロイすると以下のエラーメッセージが表示されます。

![4_qiita_error1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1989465/4cf8a61c-447d-a08c-598d-db3e899b4a00.png)

操作の詳細は以下になります。
プロビジョニングステータスが「Failed」となっています。
色々と調べてみましたが、これといった記事がみつかりませんでした。
リソースのメタデータプロパティでリソース自体の機能には問題ないらしい。。たしかにプロビジョニング操作は「Create」で動作確認にも影響はありませんでした。情報を求む。

![5_qiita_error2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1989465/784a418f-0af8-5c76-5a34-28d12775981c.png)



# 7. おわりに
本記事を最後まで読んで頂きましてありがとうございます。
デプロイエラーが発生し、結論を出すまでの過程において様々な情報を読み漁りました。
日々勉強だなと思いました。

# 8. 参考記事
-  [仮想ネットワーク リンクとは](https://learn.microsoft.com/ja-jp/azure/dns/private-dns-virtual-network-links)
-  [Microsoft.Storage storageAccounts/privateEndpointConnections](https://learn.microsoft.com/ja-jp/azure/templates/microsoft.storage/storageaccounts/privateendpointconnections?pivots=deployment-language-bicep)
-  [Bicep での子リソースの名前と種類の設定](https://learn.microsoft.com/ja-jp/azure/azure-resource-manager/bicep/child-resource-name-type)
-  [Bicep を使って仮想ネットワーク リソースを作成する](https://learn.microsoft.com/ja-jp/azure/azure-resource-manager/bicep/scenarios-virtual-networks)
-  [Microsoft.Network privateDnsZones/A](https://learn.microsoft.com/en-us/azure/templates/microsoft.network/privatednszones/a?pivots=deployment-language-bicep#arecord)
-  [azure-quickstart-templates/quickstarts/microsoft.web/private-webapp-with-app-gateway-and-apim/main.bicep](https://github.com/Azure/azure-quickstart-templates/blob/master/quickstarts/microsoft.web/private-webapp-with-app-gateway-and-apim/main.bicep)
-  [よくある Azure デプロイ エラーのトラブルシューティングに関する記事](https://learn.microsoft.com/ja-jp/azure/azure-resource-manager/troubleshooting/common-deployment-errors)
-  [Azure プライベート エンドポイントの接続に関する問題のトラブルシューティング](https://learn.microsoft.com/en-us/azure/private-link/troubleshoot-private-endpoint-connectivity)