Skip to content

Commit

Permalink
add bastion Premium sku and session recording
Browse files Browse the repository at this point in the history
  • Loading branch information
T0biii committed Sep 21, 2024
1 parent 78a8b5d commit 4e25386
Show file tree
Hide file tree
Showing 5 changed files with 128 additions and 23 deletions.
6 changes: 6 additions & 0 deletions internal/services/network/bastion_host_data_source.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,11 @@ func dataSourceBastionHost() *pluginsdk.Resource {
Computed: true,
},

"session_recording_enabled": {
Type: pluginsdk.TypeBool,
Computed: true,
},

"dns_name": {
Type: pluginsdk.TypeString,
Computed: true,
Expand Down Expand Up @@ -136,6 +141,7 @@ func dataSourceBastionHostRead(d *pluginsdk.ResourceData, meta interface{}) erro
d.Set("ip_connect_enabled", props.EnableIPConnect)
d.Set("shareable_link_enabled", props.EnableShareableLink)
d.Set("tunneling_enabled", props.EnableTunneling)
d.Set("session_recording_enabled", props.EnableSessionRecording)

copyPasteEnabled := true
if props.DisableCopyPaste != nil {
Expand Down
1 change: 1 addition & 0 deletions internal/services/network/bastion_host_data_source_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ func TestAccBastionHostDataSource_basic(t *testing.T) {
check.That(data.ResourceName).Key("file_copy_enabled").Exists(),
check.That(data.ResourceName).Key("ip_connect_enabled").Exists(),
check.That(data.ResourceName).Key("shareable_link_enabled").Exists(),
check.That(data.ResourceName).Key("session_recording_enabled").Exists(),
check.That(data.ResourceName).Key("ip_configuration.0.name").Exists(),
check.That(data.ResourceName).Key("ip_configuration.0.subnet_id").Exists(),
check.That(data.ResourceName).Key("ip_configuration.0.public_ip_address_id").Exists(),
Expand Down
69 changes: 47 additions & 22 deletions internal/services/network/bastion_host_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ var skuWeight = map[string]int8{
"Developer": 1,
"Basic": 2,
"Standard": 3,
"Premium": 4,
}

func resourceBastionHost() *pluginsdk.Resource {
Expand Down Expand Up @@ -140,6 +141,12 @@ func resourceBastionHost() *pluginsdk.Resource {
Default: false,
},

"session_recording_enabled": {
Type: pluginsdk.TypeBool,
Optional: true,
Default: false,
},

"virtual_network_id": {
Type: pluginsdk.TypeString,
Optional: true,
Expand Down Expand Up @@ -184,29 +191,34 @@ func resourceBastionHostCreate(d *pluginsdk.ResourceData, meta interface{}) erro
kerberosEnabled := d.Get("kerberos_enabled").(bool)
shareableLinkEnabled := d.Get("shareable_link_enabled").(bool)
tunnelingEnabled := d.Get("tunneling_enabled").(bool)
sessionRecordingEnabled := d.Get("session_recording_enabled").(bool)

if scaleUnits > 2 && (sku != bastionhosts.BastionHostSkuNameStandard && sku != bastionhosts.BastionHostSkuNamePremium) {
return fmt.Errorf("`scale_units` only can be changed when `sku` is `Standard` or `Premium`. `scale_units` is always `2` when `sku` is `Basic`")
}

if scaleUnits > 2 && sku == bastionhosts.BastionHostSkuNameBasic {
return fmt.Errorf("`scale_units` only can be changed when `sku` is `Standard`. `scale_units` is always `2` when `sku` is `Basic`")
if fileCopyEnabled && (sku != bastionhosts.BastionHostSkuNameStandard && sku != bastionhosts.BastionHostSkuNamePremium) {
return fmt.Errorf("`file_copy_enabled` is only supported when `sku` is `Standard` or `Premium`")
}

if fileCopyEnabled && sku == bastionhosts.BastionHostSkuNameBasic {
return fmt.Errorf("`file_copy_enabled` is only supported when `sku` is `Standard`")
if ipConnectEnabled && (sku != bastionhosts.BastionHostSkuNameStandard && sku != bastionhosts.BastionHostSkuNamePremium) {
return fmt.Errorf("`ip_connect_enabled` is only supported when `sku` is `Standard` or `Premium`")
}

if ipConnectEnabled && sku == bastionhosts.BastionHostSkuNameBasic {
return fmt.Errorf("`ip_connect_enabled` is only supported when `sku` is `Standard`")
if kerberosEnabled && (sku != bastionhosts.BastionHostSkuNameStandard && sku != bastionhosts.BastionHostSkuNamePremium) {
return fmt.Errorf("`kerberos_enabled` is only supported when `sku` is `Standard` or `Premium`")
}

if kerberosEnabled && sku == bastionhosts.BastionHostSkuNameBasic {
return fmt.Errorf("`kerberos_enabled` is only supported when `sku` is `Standard`")
if shareableLinkEnabled && (sku != bastionhosts.BastionHostSkuNameStandard && sku != bastionhosts.BastionHostSkuNamePremium) {
return fmt.Errorf("`shareable_link_enabled` is only supported when `sku` is `Standard` or `Premium`")
}

if shareableLinkEnabled && sku == bastionhosts.BastionHostSkuNameBasic {
return fmt.Errorf("`shareable_link_enabled` is only supported when `sku` is `Standard`")
if tunnelingEnabled && (sku != bastionhosts.BastionHostSkuNameStandard && sku != bastionhosts.BastionHostSkuNamePremium) {
return fmt.Errorf("`tunneling_enabled` is only supported when `sku` is `Standard` or `Premium`")
}

if tunnelingEnabled && sku == bastionhosts.BastionHostSkuNameBasic {
return fmt.Errorf("`tunneling_enabled` is only supported when `sku` is `Standard`")
if sessionRecordingEnabled && sku != bastionhosts.BastionHostSkuNamePremium {
return fmt.Errorf("`session_recording_enabled` is only supported when `sku` is `Premium`")
}

existing, err := client.Get(ctx, id)
Expand Down Expand Up @@ -256,6 +268,10 @@ func resourceBastionHostCreate(d *pluginsdk.ResourceData, meta interface{}) erro
parameters.Properties.EnableTunneling = pointer.To(tunnelingEnabled)
}

if sessionRecordingEnabled {
parameters.Properties.EnableSessionRecording = pointer.To(sessionRecordingEnabled)
}

if v, ok := d.GetOk("virtual_network_id"); ok {
if sku != bastionhosts.BastionHostSkuNameDeveloper {
return fmt.Errorf("`virtual_network_id` is only supported when `sku` is `Developer`")
Expand Down Expand Up @@ -315,44 +331,52 @@ func resourceBastionHostUpdate(d *pluginsdk.ResourceData, meta interface{}) erro

if d.HasChange("file_copy_enabled") {
fileCopyEnabled := d.Get("file_copy_enabled").(bool)
if fileCopyEnabled && sku == bastionhosts.BastionHostSkuNameBasic {
return fmt.Errorf("`file_copy_enabled` is only supported when `sku` is `Standard`")
if fileCopyEnabled && (sku != bastionhosts.BastionHostSkuNameStandard && sku != bastionhosts.BastionHostSkuNamePremium) {
return fmt.Errorf("`file_copy_enabled` is only supported when `sku` is `Standard` or `Premium`")
}
payload.Properties.EnableFileCopy = pointer.To(fileCopyEnabled)
}

if d.HasChange("ip_connect_enabled") {
ipConnectEnabled := d.Get("ip_connect_enabled").(bool)
if ipConnectEnabled && sku == bastionhosts.BastionHostSkuNameBasic {
return fmt.Errorf("`ip_connect_enabled` is only supported when `sku` is `Standard`")
if ipConnectEnabled && (sku != bastionhosts.BastionHostSkuNameStandard && sku != bastionhosts.BastionHostSkuNamePremium) {
return fmt.Errorf("`ip_connect_enabled` is only supported when `sku` is `Standard` or `Premium`")
}
payload.Properties.EnableIPConnect = pointer.To(ipConnectEnabled)
}

if d.HasChange("scale_units") {
scaleUnits := d.Get("scale_units").(int)
if scaleUnits > 2 && sku == bastionhosts.BastionHostSkuNameBasic {
return fmt.Errorf("`scale_units` only can be changed when `sku` is `Standard`. `scale_units` is always `2` when `sku` is `Basic`")
if scaleUnits > 2 && (sku != bastionhosts.BastionHostSkuNameStandard && sku != bastionhosts.BastionHostSkuNamePremium) {
return fmt.Errorf("`scale_units` only can be changed when `sku` is `Standard` or `Premium`. `scale_units` is always `2` when `sku` is `Basic`")
}
payload.Properties.ScaleUnits = pointer.To(int64(scaleUnits))
}

if d.HasChange("shareable_link_enabled") {
shareableLinkEnabled := d.Get("shareable_link_enabled").(bool)
if shareableLinkEnabled && sku == bastionhosts.BastionHostSkuNameBasic {
return fmt.Errorf("`shareable_link_enabled` is only supported when `sku` is `Standard`")
if shareableLinkEnabled && (sku != bastionhosts.BastionHostSkuNameStandard && sku != bastionhosts.BastionHostSkuNamePremium) {
return fmt.Errorf("`shareable_link_enabled` is only supported when `sku` is `Standard` or `Premium`")
}
payload.Properties.EnableShareableLink = pointer.To(shareableLinkEnabled)
}

if d.HasChange("tunneling_enabled") {
tunnelingEnabled := d.Get("tunneling_enabled").(bool)
if tunnelingEnabled && sku == bastionhosts.BastionHostSkuNameBasic {
return fmt.Errorf("`tunneling_enabled` is only supported when `sku` is `Standard`")
if tunnelingEnabled && (sku != bastionhosts.BastionHostSkuNameStandard && sku != bastionhosts.BastionHostSkuNamePremium) {
return fmt.Errorf("`tunneling_enabled` is only supported when `sku` is `Standard` or `Premium`")
}
payload.Properties.EnableTunneling = pointer.To(tunnelingEnabled)
}

if d.HasChange("session_recording_enabled") {
sessionRecordingEnabled := d.Get("session_recording_enabled").(bool)
if sessionRecordingEnabled && sku == bastionhosts.BastionHostSkuNamePremium {
return fmt.Errorf("`session_recording_enabled` is only supported when `sku` is `Premium`")
}
payload.Properties.EnableSessionRecording = pointer.To(sessionRecordingEnabled)
}

if d.HasChange("tags") {
payload.Tags = tags.Expand(d.Get("tags").(map[string]interface{}))

Expand Down Expand Up @@ -405,6 +429,7 @@ func resourceBastionHostRead(d *pluginsdk.ResourceData, meta interface{}) error
d.Set("kerberos_enabled", props.EnableKerberos)
d.Set("shareable_link_enabled", props.EnableShareableLink)
d.Set("tunneling_enabled", props.EnableTunneling)
d.Set("session_recording_enabled", props.EnableSessionRecording)

virtualNetworkId := ""
if vnet := props.VirtualNetwork; vnet != nil {
Expand Down
69 changes: 69 additions & 0 deletions internal/services/network/bastion_host_resource_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,21 @@ func TestAccBastionHost_developerSku(t *testing.T) {
})
}

func TestAccBastionHost_premiumSku(t *testing.T) {
data := acceptance.BuildTestData(t, "azurerm_bastion_host", "test")
r := BastionHostResource{}

data.ResourceTest(t, r, []acceptance.TestStep{
{
Config: r.premiumSku(data),
Check: acceptance.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
),
},
data.ImportStep(),
})
}

func (BastionHostResource) Exists(ctx context.Context, clients *clients.Client, state *pluginsdk.InstanceState) (*bool, error) {
id, err := bastionhosts.ParseBastionHostID(state.ID)
if err != nil {
Expand Down Expand Up @@ -445,3 +460,57 @@ resource "azurerm_bastion_host" "test" {
}
`, data.RandomInteger, data.Locations.Ternary, data.RandomString, data.RandomString)
}

func (BastionHostResource) premiumSku(data acceptance.TestData) string {
return fmt.Sprintf(`
provider "azurerm" {
features {}
}
resource "azurerm_resource_group" "test" {
name = "acctestRG-bastion-%d"
location = "%s"
}
resource "azurerm_virtual_network" "test" {
name = "acctestVNet%s"
address_space = ["192.168.1.0/24"]
location = azurerm_resource_group.test.location
resource_group_name = azurerm_resource_group.test.name
}
resource "azurerm_subnet" "test" {
name = "AzureBastionSubnet"
resource_group_name = azurerm_resource_group.test.name
virtual_network_name = azurerm_virtual_network.test.name
address_prefixes = ["192.168.1.224/27"]
}
resource "azurerm_public_ip" "test" {
name = "acctestBastionPIP%d"
location = azurerm_resource_group.test.location
resource_group_name = azurerm_resource_group.test.name
allocation_method = "Static"
sku = "Standard"
}
resource "azurerm_bastion_host" "test" {
name = "acctestBastion%s"
location = azurerm_resource_group.test.location
resource_group_name = azurerm_resource_group.test.name
sku = "Premium"
file_copy_enabled = true
ip_connect_enabled = true
kerberos_enabled = true
shareable_link_enabled = true
tunneling_enabled = true
session_recording_enabled = true
ip_configuration {
name = "ip-configuration"
subnet_id = azurerm_subnet.test.id
public_ip_address_id = azurerm_public_ip.test.id
}
}
`, data.RandomInteger, data.Locations.Primary, data.RandomString, data.RandomInteger, data.RandomString)
}
6 changes: 5 additions & 1 deletion website/docs/r/bastion_host.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ The following arguments are supported:

~> **Note:** `file_copy_enabled` is only supported when `sku` is `Standard`.

* `sku` - (Optional) The SKU of the Bastion Host. Accepted values are `Developer`, `Basic` and `Standard`. Defaults to `Basic`.
* `sku` - (Optional) The SKU of the Bastion Host. Accepted values are `Developer`, `Basic`, `Standard` and `Premium`. Defaults to `Basic`.

~> **Note** Downgrading the SKU will force a new resource to be created.

Expand All @@ -98,6 +98,10 @@ The following arguments are supported:

~> **Note:** `tunneling_enabled` is only supported when `sku` is `Standard`.

* `session_recording_enabled` - (Optional) Is Session Recording feature enabled for the Bastion Host. Defaults to `false`.

~> **Note:** `session_recording_enabled` is only supported when `sku` is `Premium`.

* `virtual_network_id` - (Optional) The ID of the Virtual Network for the Developer Bastion Host. Changing this forces a new resource to be created.

* `tags` - (Optional) A mapping of tags to assign to the resource.
Expand Down

0 comments on commit 4e25386

Please sign in to comment.