Skip to content

Commit b20d0dc

Browse files
committed
Toggle private only enabled conditionally
1 parent 920eb79 commit b20d0dc

File tree

4 files changed

+35
-41
lines changed

4 files changed

+35
-41
lines changed

internal/services/network/bastion_host_resource.go

Lines changed: 26 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -147,13 +147,6 @@ func resourceBastionHost() *pluginsdk.Resource {
147147
Default: false,
148148
},
149149

150-
"private_only_enabled": {
151-
Type: pluginsdk.TypeBool,
152-
Optional: true,
153-
Default: false,
154-
ForceNew: true,
155-
},
156-
157150
"session_recording_enabled": {
158151
Type: pluginsdk.TypeBool,
159152
Optional: true,
@@ -172,6 +165,12 @@ func resourceBastionHost() *pluginsdk.Resource {
172165
Computed: true,
173166
},
174167

168+
"private_only_enabled": {
169+
Type: pluginsdk.TypeBool,
170+
Computed: true,
171+
ForceNew: true,
172+
},
173+
175174
"tags": commonschema.Tags(),
176175

177176
"zones": commonschema.ZonesMultipleOptionalForceNew(),
@@ -187,35 +186,22 @@ func resourceBastionHost() *pluginsdk.Resource {
187186
}),
188187
func(ctx context.Context, d *pluginsdk.ResourceDiff, meta interface{}) error {
189188
sku := bastionhosts.BastionHostSkuName(d.Get("sku").(string))
190-
privateOnlyEnabled := d.Get("private_only_enabled").(bool)
191-
192-
if privateOnlyEnabled && sku != bastionhosts.BastionHostSkuNamePremium {
193-
return errors.New("`private_only_enabled` is only supported when `sku` is `Premium`")
194-
}
195189

196190
// GetRawConfig is used because `public_ip_address_id` may reference another resource and be unknown during plan.
197191
// d.Get() returns "" for unknown values, which would incorrectly trigger the required check.
198192
// By inspecting the raw config, we can distinguish between "not set" and "unknown" and skip validation when unknown.
199193
rawConfig := d.GetRawConfig()
200194
ipConfigRaw := rawConfig.AsValueMap()["ip_configuration"]
201-
ipConfiguration := d.Get("ip_configuration").([]interface{})
202-
if privateOnlyEnabled {
203-
if !ipConfigRaw.IsNull() && ipConfigRaw.IsKnown() && len(ipConfiguration) > 0 {
204-
ipConfigMap := ipConfiguration[0].(map[string]interface{})
205-
if v, ok := ipConfigMap["public_ip_address_id"]; ok && v.(string) != "" {
206-
return errors.New("`public_ip_address_id` must not be set when `private_only_enabled` is `true`")
207-
}
208-
}
209-
} else if sku != bastionhosts.BastionHostSkuNameDeveloper {
210-
if len(ipConfiguration) == 0 {
211-
return errors.New("`ip_configuration` with `public_ip_address_id` is required when `private_only_enabled` is `false`")
212-
}
213195

214-
if !ipConfigRaw.IsNull() && ipConfigRaw.IsKnown() {
215-
pipRaw := ipConfigRaw.AsValueSlice()[0].AsValueMap()["public_ip_address_id"]
216-
if pipRaw.IsKnown() && (pipRaw.IsNull() || pipRaw.AsString() == "") {
217-
return errors.New("`public_ip_address_id` is required in `ip_configuration` when `private_only_enabled` is `false`")
218-
}
196+
// Basic and Standard SKUs require public_ip_address_id; Developer uses virtual_network_id instead.
197+
// Premium without public_ip_address_id enables private-only mode.
198+
if sku != bastionhosts.BastionHostSkuNamePremium && sku != bastionhosts.BastionHostSkuNameDeveloper {
199+
if ipConfigRaw.IsNull() || !ipConfigRaw.IsKnown() || len(ipConfigRaw.AsValueSlice()) == 0 {
200+
return errors.New("`ip_configuration` with `public_ip_address_id` is required when `sku` is `Basic` or `Standard`")
201+
}
202+
pipRaw := ipConfigRaw.AsValueSlice()[0].AsValueMap()["public_ip_address_id"]
203+
if pipRaw.IsKnown() && (pipRaw.IsNull() || pipRaw.AsString() == "") {
204+
return errors.New("`public_ip_address_id` must be set in `ip_configuration` when `sku` is `Basic` or `Standard`")
219205
}
220206
}
221207

@@ -240,7 +226,6 @@ func resourceBastionHostCreate(d *pluginsdk.ResourceData, meta interface{}) erro
240226
fileCopyEnabled := d.Get("file_copy_enabled").(bool)
241227
ipConnectEnabled := d.Get("ip_connect_enabled").(bool)
242228
kerberosEnabled := d.Get("kerberos_enabled").(bool)
243-
privateOnlyEnabled := d.Get("private_only_enabled").(bool)
244229
shareableLinkEnabled := d.Get("shareable_link_enabled").(bool)
245230
tunnelingEnabled := d.Get("tunneling_enabled").(bool)
246231
sessionRecordingEnabled := d.Get("session_recording_enabled").(bool)
@@ -324,6 +309,17 @@ func resourceBastionHostCreate(d *pluginsdk.ResourceData, meta interface{}) erro
324309
parameters.Properties.EnableSessionRecording = pointer.To(sessionRecordingEnabled)
325310
}
326311

312+
ipConfigs := d.Get("ip_configuration").([]interface{})
313+
privateOnlyEnabled := false
314+
if sku == bastionhosts.BastionHostSkuNamePremium {
315+
if len(ipConfigs) > 0 {
316+
ipConfigMap := ipConfigs[0].(map[string]interface{})
317+
if v, ok := ipConfigMap["public_ip_address_id"]; ok && v.(string) != "" {
318+
privateOnlyEnabled = true
319+
}
320+
}
321+
}
322+
327323
if privateOnlyEnabled {
328324
parameters.Properties.EnablePrivateOnlyBastion = pointer.To(privateOnlyEnabled)
329325
}

internal/services/network/bastion_host_resource_test.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ func TestAccBastionHost_privateOnly(t *testing.T) {
163163
Config: r.privateOnly(data),
164164
Check: acceptance.ComposeTestCheckFunc(
165165
check.That(data.ResourceName).ExistsInAzure(r),
166+
check.That(data.ResourceName).Key("private_only_enabled").HasValue("true"),
166167
),
167168
},
168169
data.ImportStep(),
@@ -559,11 +560,10 @@ resource "azurerm_subnet" "test" {
559560
}
560561
561562
resource "azurerm_bastion_host" "test" {
562-
name = "acctestBastion%s"
563-
location = azurerm_resource_group.test.location
564-
resource_group_name = azurerm_resource_group.test.name
565-
sku = "Premium"
566-
private_only_enabled = true
563+
name = "acctestBastion%s"
564+
location = azurerm_resource_group.test.location
565+
resource_group_name = azurerm_resource_group.test.name
566+
sku = "Premium"
567567
568568
ip_configuration {
569569
name = "ip-configuration"

website/docs/d/bastion_host.html.markdown

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ In addition to the Arguments listed above - the following Attributes are exporte
5858

5959
* `session_recording_enabled` - Is Session Recording feature enabled for the Bastion Host.
6060

61-
* `private_only_enabled` - Is the Bastion Host deployed in Private-Only mode.
61+
* `private_only_enabled` - Whether Private-Only deployment is enabled for the Bastion Host.
6262

6363
* `dns_name` - The FQDN for the Bastion Host.
6464

website/docs/r/bastion_host.html.markdown

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -86,10 +86,6 @@ The following arguments are supported:
8686

8787
~> **Note:** `kerberos_enabled` is only supported when `sku` is `Standard` or `Premium`.
8888

89-
* `private_only_enabled` - (Optional) Is Private-Only deployment enabled for the Bastion Host. Defaults to `false`. Changing this forces a new resource to be created.
90-
91-
~> **Note:** `private_only_enabled` is only supported when `sku` is `Premium`. When `private_only_enabled` is `true`, `public_ip_address_id` in `ip_configuration` must not be specified.
92-
9389
* `scale_units` - (Optional) The number of scale units with which to provision the Bastion Host. Possible values are between `2` and `50`. Defaults to `2`.
9490

9591
~> **Note:** `scale_units` only can be changed when `sku` is `Standard` or `Premium`. `scale_units` is always `2` when `sku` is `Basic`.
@@ -124,7 +120,7 @@ A `ip_configuration` block supports the following:
124120

125121
* `public_ip_address_id` - (Optional) Reference to a Public IP Address to associate with this Bastion Host. Changing this forces a new resource to be created.
126122

127-
~> **Note:** `public_ip_address_id` is required when `private_only_enabled` is `false`.
123+
~> **Note:** `public_ip_address_id` is required when `sku` is `Basic` or `Standard`. When `sku` is `Premium` and `public_ip_address_id` is omitted, the Bastion Host is deployed in Private-Only mode (`private_only_enabled` will be `true`).
128124

129125
## Attributes Reference
130126

@@ -134,6 +130,8 @@ In addition to the Arguments listed above - the following Attributes are exporte
134130

135131
* `dns_name` - The FQDN for the Bastion Host.
136132

133+
* `private_only_enabled` - Whether Private-Only deployment is enabled for the Bastion Host.
134+
137135
## Timeouts
138136

139137
The `timeouts` block allows you to specify [timeouts](https://developer.hashicorp.com/terraform/language/resources/configure#define-operation-timeouts) for certain actions:

0 commit comments

Comments
 (0)