はじめに
Bicepを勉強し始めたのですが、「こう書いてみたけどうまく動かないな…」というのがあったので備忘録的にまとめておきます。
作成するリソース
- Vnetを作成して、サブネットは2つ定義する。
- サブネットには、
AllowSpecificSSHInbound
というルール(IPアドレス:11.22.33.44からのSSH接続を許可)を持つNSGを紐づける。
⭕動くコード
それぞれ、コードの全量を載せてみます。
※もしかしたらパラメータファイルを使ったらもう少しスッキリするかと思います。
①VnetとNSGを定義する
param location string = 'eastus'
param MyName string = 'test-01'
param ipAddrPrefix string = '10.0.0.0/16'
param subnet1Prefix string = '10.0.0.0/24'
param subnet2Prefix string = '10.0.1.0/24'
var vnetName = '${MyName}-vnet'
var subnet1Name = '${MyName}-subnet1'
var subnet2Name = '${MyName}-subnet2'
var nsgName = '${MyName}-nsg'
resource virtualNetwork 'Microsoft.Network/virtualNetworks@2019-11-01' = {
name: vnetName
location: location
properties: {
addressSpace: {
addressPrefixes: [
ipAddrPrefix
]
}
subnets: [
{
name: subnet1Name
properties: {
addressPrefix: subnet1Prefix
networkSecurityGroup: {
id: nsg.id
}
}
}
{
name: subnet2Name
properties: {
addressPrefix: subnet2Prefix
networkSecurityGroup: {
id: nsg.id
}
}
}
]
}
}
resource nsg 'Microsoft.Network/networkSecurityGroups@2022-09-01' = {
name: nsgName
location: location
properties: {
securityRules: [
{
name: 'AllowSpecificSSHInbound'
properties: {
access: 'Allow'
direction: 'Inbound'
protocol: 'Tcp'
sourceAddressPrefix: '11.22.33.44'
sourcePortRange: '*'
destinationAddressPrefix: '*'
destinationPortRange: '22'
priority: 100
}
}
]
}
}
Vnetの定義の中でサブネットも併せて定義して、別で定義したNSGを紐づけるイメージです。
これが一番しっくりくる書き方なんじゃないかと思います。
②NSG/サブネット/NSGをそれぞれ定義する
param location string = 'eastus'
param MyName string = 'test-02'
param ipAddrPrefix string = '10.0.0.0/16'
param subnet1Prefix string = '10.0.0.0/24'
param subnet2Prefix string = '10.0.1.0/24'
var vnetName = '${MyName}-vnet'
var subnet1Name = '${MyName}-subnet1'
var subnet2Name = '${MyName}-subnet2'
var nsgName = '${MyName}-nsg'
resource vnet 'Microsoft.Network/virtualNetworks@2019-11-01' = {
name: vnetName
location: location
properties: {
addressSpace: {
addressPrefixes: [
ipAddrPrefix
]
}
}
}
resource subnet1 'Microsoft.Network/virtualNetworks/subnets@2022-09-01' ={
parent: vnet
name: subnet1Name
properties: {
addressPrefix: subnet1Prefix
networkSecurityGroup: {
id: nsg.id
}
}
}
resource subnet2 'Microsoft.Network/virtualNetworks/subnets@2022-09-01' ={
parent: vnet
name: subnet2Name
properties: {
addressPrefix: subnet2Prefix
networkSecurityGroup: {
id: nsg.id
}
}
}
resource nsg 'Microsoft.Network/networkSecurityGroups@2022-09-01' = {
name: nsgName
location: location
properties: {
securityRules: [
{
name: 'AllowSpecificSSHInbound'
properties: {
access: 'Allow'
direction: 'Inbound'
protocol: 'Tcp'
sourceAddressPrefix: '11.22.33.44'
sourcePortRange: '*'
destinationAddressPrefix: '*'
destinationPortRange: '22'
priority: 100
}
}
]
}
}
サブネットをVnetの外で定義します。その際、定義したサブネットはVnetの中に含まれるということをparent
で明示しています。
同じ設定のサブネットを複数Vnetで使いまわす際にはこの書き方が良いのかもしれません。
❌動かないコード
③Vnetの定義内にサブネットおよびNSGの定義内容もすべて含める
param location string = 'eastus'
param MyName string = 'test-03'
param ipAddrPrefix string = '10.0.0.0/16'
param subnet1Prefix string = '10.0.0.0/24'
param subnet2Prefix string = '10.0.1.0/24'
var vnetName = '${MyName}-vnet'
var subnet1Name = '${MyName}-subnet1'
var subnet2Name = '${MyName}-subnet2'
// var nsgName = '${MyName}-nsg'
resource vm 'Microsoft.Network/virtualNetworks@2019-11-01' = {
name: vnetName
location: location
properties: {
addressSpace: {
addressPrefixes: [
ipAddrPrefix
]
}
subnets: [
{
name: subnet1Name
properties: {
addressPrefix: subnet1Prefix
networkSecurityGroup: {
properties: {
securityRules: [
{
name: 'AllowSpecificSSHInbound'
properties: {
access: 'Allow'
direction: 'Inbound'
protocol: 'Tcp'
sourceAddressPrefix: '11.22.33.44'
sourcePortRange: '*'
destinationAddressPrefix: '*'
destinationPortRange: '22'
priority: 100
}
}
]
}
}
}
}
{
name: subnet2Name
properties: {
addressPrefix: subnet2Prefix
networkSecurityGroup: {
properties: {
securityRules: [
{
name: 'AllowSpecificSSHInbound'
properties: {
access: 'Allow'
direction: 'Inbound'
protocol: 'Tcp'
sourceAddressPrefix: '11.22.33.44'
sourcePortRange: '*'
destinationAddressPrefix: '*'
destinationPortRange: '22'
priority: 100
}
}
]
}
}
}
}
]
}
}
Vnetの定義ブロックの中に、すべての設定を詰め込んだ形です。
上記を実行すると以下のようなエラーメッセージが出力されました。
{
"status": "Failed",
"error": {
"code": "DeploymentFailed",
"target": "/subscriptions/<サブスクリプションID>/resourceGroups/<リソースグループ名>/providers/Microsoft.Resources/deployments/03.vnet",
"message": "At least one resource deployment operation failed. Please list deployment operations for details. Please see https://aka.ms/arm-deployment-operations for usage details.",
"details": [
{
"code": "InvalidRequestFormat",
"message": "Cannot parse the request.",
"details": [
{
"code": "MissingJsonReferenceId",
"message": "Value for reference id is missing. Path properties.subnets[0].properties.networkSecurityGroup."
},
{
"code": "MissingJsonReferenceId",
"message": "Value for reference id is missing. Path properties.subnets[1].properties.networkSecurityGroup."
}
]
}
]
}
}
メッセージ的にproperties.subnets[*].properties.networkSecurityGroup
の中にid
を指定していないためエラーになっているように思われたので、空っぽのNSG定義を追加してみました。
④Vnetの定義内にサブネットおよびNSGの定義内容もすべて含める(NSGはガラだけ定義)
param location string = 'eastus'
param MyName string = 'test-04'
param ipAddrPrefix string = '10.0.0.0/16'
param subnet1Prefix string = '10.0.0.0/24'
param subnet2Prefix string = '10.0.1.0/24'
var vnetName = '${MyName}-vnet'
var subnet1Name = '${MyName}-subnet1'
var subnet2Name = '${MyName}-subnet2'
var nsgName = '${MyName}-nsg'
resource vm 'Microsoft.Network/virtualNetworks@2019-11-01' = {
name: vnetName
location: location
properties: {
addressSpace: {
addressPrefixes: [
ipAddrPrefix
]
}
subnets: [
{
name: subnet1Name
properties: {
addressPrefix: subnet1Prefix
networkSecurityGroup: {
id: nsg.id
properties: {
securityRules: [
{
name: 'AllowSpecificSSHInbound'
properties: {
access: 'Allow'
direction: 'Inbound'
protocol: 'Tcp'
sourceAddressPrefix: '11.22.33.44'
sourcePortRange: '*'
destinationAddressPrefix: '*'
destinationPortRange: '22'
priority: 100
}
}
]
}
}
}
}
{
name: subnet2Name
properties: {
addressPrefix: subnet2Prefix
networkSecurityGroup: {
id: nsg.id
properties: {
securityRules: [
{
name: 'AllowSpecificSSHInbound'
properties: {
access: 'Allow'
direction: 'Inbound'
protocol: 'Tcp'
sourceAddressPrefix: '11.22.33.44'
sourcePortRange: '*'
destinationAddressPrefix: '*'
destinationPortRange: '22'
priority: 100
}
}
]
}
}
}
}
]
}
}
resource nsg 'Microsoft.Network/networkSecurityGroups@2022-09-01' = {
name: nsgName
location: location
}
id
がないというエラーに対処するためだけに、NSGのガラだけ定義しています。実はこのコードはエラーにならず登録はできます。ただNSGの設定を見てみると追加されているはずのAllowSpecificSSHInbound
ルールが追加されていませんでした。
⑤Vnet/サブネット/NSGをそれぞれ定義する(Vnetとサブネットの紐づけにparentを使わない)
param location string = 'eastus'
param MyName string = 'test-05'
param ipAddrPrefix string = '10.0.0.0/16'
param subnet1Prefix string = '10.0.0.0/24'
param subnet2Prefix string = '10.0.1.0/24'
var vnetName = '${MyName}-vnet'
var subnet1Name = '${MyName}-subnet1'
var subnet2Name = '${MyName}-subnet2'
var nsgName = '${MyName}-nsg'
resource vnet 'Microsoft.Network/virtualNetworks@2022-09-01' = {
name: vnetName
location: location
properties: {
addressSpace: {
addressPrefixes: [
ipAddrPrefix
]
}
subnets: [
{
id: subnet1.id
}
{
id: subnet2.id
}
]
}
}
resource subnet1 'Microsoft.Network/virtualNetworks/subnets@2022-09-01' ={
name: subnet1Name
properties: {
addressPrefix: subnet1Prefix
networkSecurityGroup: {
id: nsg.id
}
}
}
resource subnet2 'Microsoft.Network/virtualNetworks/subnets@2022-09-01' ={
name: subnet2Name
properties: {
addressPrefix: subnet2Prefix
networkSecurityGroup: {
id: nsg.id
}
}
}
resource nsg 'Microsoft.Network/networkSecurityGroups@2022-09-01' = {
name: nsgName
location: location
properties: {
securityRules: [
{
name: 'AllowSpecificSSHInbound'
properties: {
access: 'Allow'
direction: 'Inbound'
protocol: 'Tcp'
sourceAddressPrefix: '11.22.33.44'
sourcePortRange: '*'
destinationAddressPrefix: '*'
destinationPortRange: '22'
priority: 100
}
}
]
}
}
Vnetとサブネットの紐づけにparent
を使わず、properties.subnets[*]
の中にサブネットそれぞれのid
を指定してみました。
実行したところ、以下のようなエラーメッセージが出力されました。
InvalidTemplate - Deployment template validation failed: 'The template resource 'test-05-vnet' at line '1' and column '716' is not valid: The language expression property array index '1' is out of bounds.. Please see https://aka.ms/arm-functions for usage details.'.
なぜ動かないのか(自分なりの解釈)
なぜ動かないのか(定義として許されないのか)について調べてみましたが、公式ドキュメントなどからは見つけられなかったので、自分なりにNGとなる理由を考えてみました。もしドキュメントなどをご存じの方がいれば教えてください。
③はVnetのテンプレートドキュメントを見る限り、NSGのセキュリティルールも細かく定義できるように読み取れます。しかし、NSGのnameに該当する設定項目が無いため、Vnetの定義ブロック内ではNSGを新規作成できないのではと推測しています。
⑤については、仮にVnetの定義を全てコメントアウトした場合でも構文上はエラーにはなりませんが、Azure的には実現できない状態になる(サブネットだけ定義することはできない)ため、エラーになるのかなと考えています(②はVnetの定義をコメントアウトすると構文エラーになります)。