Skip to content

CloudAstro/terraform-azurerm-bastion-host

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

4 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

azurerm_bastion_host Module

This module is designed to manage an Azure Bastion. The module supports configuration of diagnostic settings, role assignments, and various other features to manage and secure your Azure Bastion.

Features

  • Secure RDP and SSH Access: Establish RDP and SSH sessions directly in the Azure portal over Transport Layer Security (TLS), ensuring encrypted connections without exposing VMs to the public internet.
  • No Public IP Requirement: Access VMs using their private IP addresses, eliminating the necessity for public IPs and reducing the attack surface.
  • Agentless Connection:: Connect to VMs without installing additional agents or software; Azure Bastion is an agentless service.
  • Support for Multiple SKUs: Azure Bastion offers various SKUs—Developer, Basic, Standard, and Premium—each providing different features and scalability options to meet diverse organizational needs.
  • Advanced Features in Higher SKUs Standard and Premium SKUs offer additional capabilities such as:
    • File Transfer: Upload and download files between your local machine and the VM during an RDP or SSH session.
    • Session Recording: Record user sessions for auditing and compliance purposes.
    • Kerberos Authentication: Utilize Kerberos for authentication to enhance security.
    • Shareable Links: Generate links to provide temporary access to VMs without exposing them to the public internet.
    • Tunneling: Establish secure tunnels to VMs, enabling access to applications running on the VM without exposing ports.
  • Diagnostic Settings: Enables monitoring and logging for Azure Bastion resources to maintain performance and

Example Usage

resource "azurerm_resource_group" "this" {
  name     = "rg-bastion-full"
  location = "germanywestcentral"
}

module "vnet_full" {
  source = "CloudAstro/virtual-network/azurerm"

  name                = "vnet-full"
  location            = azurerm_resource_group.this.location
  resource_group_name = azurerm_resource_group.this.name
  address_space       = ["10.30.0.0/16"]
}

module "subnet_bastion" {
  source = "CloudAstro/subnet/azurerm"

  name                 = "AzureBastionSubnet"
  resource_group_name  = azurerm_resource_group.this.name
  virtual_network_name = module.vnet_full.virtual_network.name
  address_prefixes     = ["10.30.0.0/26"]
}

module "pip_bastion" {
  source = "CloudAstro/public-ip/azurerm"

  name                = "pip-bastion-example"
  location            = azurerm_resource_group.this.location
  resource_group_name = azurerm_resource_group.this.name
  sku                 = "Standard"
  allocation_method   = "Static"
  zones               = ["1"]
}

module "bastion_host" {
  source = "../../"

  name                      = "bastion-full"
  location                  = azurerm_resource_group.this.location
  resource_group_name       = azurerm_resource_group.this.name
  copy_paste_enabled        = true
  file_copy_enabled         = true
  ip_connect_enabled        = true
  kerberos_enabled          = true
  scale_units               = 3
  shareable_link_enabled    = true
  tunneling_enabled         = true
  session_recording_enabled = false
  sku                       = "Standard"
  zones                     = ["1"]

  ip_configuration = {
    name                 = "ipconfig1"
    subnet_id            = module.subnet_bastion.subnet.id
    public_ip_address_id = module.pip_bastion.publicip.id
  }

  tags = {
    environment = "lab"
    owner       = "ricloud"
  }
}

Requirements

Name Version
terraform ~> 1.9.0
azurerm >= 4.0.0

Providers

Name Version
azurerm >= 4.0.0

Resources

Name Type
azurerm_bastion_host.this resource
azurerm_monitor_diagnostic_setting.this resource
azurerm_subnet.bastion data source

Inputs

Name Description Type Default Required
location * location - (Required) Specifies the supported Azure location where the resource exists. Changing this forces a new resource to be created. Review Azure Bastion Host FAQ for supported locations.

Example Input:
location = "germanywestcentral"
string n/a yes
name * name - (Required) Specifies the name of the Bastion Host. Changing this forces a new resource to be created.

Example Input:
name = "myBastionHost"
string n/a yes
resource_group_name * resource_group_name - (Required) The name of the resource group in which to create the Bastion Host. Changing this forces a new resource to be created.

Example Input:
resource_group_name = "myResourceGroup"
string n/a yes
copy_paste_enabled * copy_paste_enabled - (Optional) Is Copy/Paste feature enabled for the Bastion Host. Defaults to true.

Example Input:
copy_paste_enabled = "true"
bool true no
diagnostic_setting The following arguments are supported:
* name - (Required) Specifies the name of the Diagnostic Setting. Changing this forces a new resource to be created.
-> NOTE: If the name is set to 'service' it will not be possible to fully delete the diagnostic setting. This is due to legacy API support.
* eventhub_name - (Optional) Specifies the name of the Event Hub where Diagnostics Data should be sent.
-> NOTE: If this isn't specified then the default Event Hub will be used.
* eventhub_authorization_rule_id - (Optional) Specifies the ID of an Event Hub Namespace Authorization Rule used to send Diagnostics Data.
-> NOTE: This can be sourced from the azurerm_eventhub_namespace_authorization_rule resource and is different from a azurerm_eventhub_authorization_rule resource.
-> NOTE: At least one of eventhub_authorization_rule_id, log_analytics_workspace_id, partner_solution_id and storage_account_id must be specified.
* enabled_log - (Optional) One or more enabled_log blocks as defined below.
-> NOTE: At least one enabled_log or metric block must be specified. At least one type of Log or Metric must be enabled.
* log_analytics_workspace_id - (Optional) Specifies the ID of a Log Analytics Workspace where Diagnostics Data should be sent.
-> NOTE: At least one of eventhub_authorization_rule_id, log_analytics_workspace_id, partner_solution_id and storage_account_id must be specified.
* metric - (Optional) One or more metric blocks as defined below.
-> NOTE: At least one enabled_log or metric block must be specified.
* storage_account_id - (Optional) The ID of the Storage Account where logs should be sent.
-> NOTE: At least one of eventhub_authorization_rule_id, log_analytics_workspace_id, partner_solution_id and storage_account_id must be specified.
* log_analytics_destination_type - (Optional) Possible values are AzureDiagnostics and Dedicated. When set to Dedicated, logs sent to a Log Analytics workspace will go into resource specific tables, instead of the legacy AzureDiagnostics table.
-> NOTE: This setting will only have an effect if a log_analytics_workspace_id is provided. For some target resource type (e.g., Key Vault), this field is unconfigurable. Please see resource types for services that use each method. Please see the documentation for details on the differences between destination types.
* partner_solution_id - (Optional) The ID of the market partner solution where Diagnostics Data should be sent. For potential partner integrations, click to learn more about partner integration.
-> NOTE: At least one of eventhub_authorization_rule_id, log_analytics_workspace_id, partner_solution_id and storage_account_id must be specified.

An enabled_log block supports the following:
* category - (Optional) The name of a Diagnostic Log Category for this Resource.
-> NOTE: The Log Categories available vary depending on the Resource being used. You may wish to use the azurerm_monitor_diagnostic_categories Data Source or list of service specific schemas to identify which categories are available for a given Resource.
* category_group - (Optional) The name of a Diagnostic Log Category Group for this Resource.
-> NOTE: Not all resources have category groups available.
-> NOTE: Exactly one of category or category_group must be specified.

A metric block supports the following:
* category - (Required) The name of a Diagnostic Metric Category for this Resource.
* -> NOTE: The Metric Categories available vary depending on the Resource being used. You may wish to use the azurerm_monitor_diagnostic_categories Data Source to identify which categories are available for a given Resource.
* enabled - (Optional) Is this Diagnostic Metric enabled? Defaults to true.
* timeouts - The timeouts block allows you to specify timeouts for certain actions:
* create - (Defaults to 30 minutes) Used when creating the Diagnostics Setting.
* update - (Defaults to 30 minutes) Used when updating the Diagnostics Setting.
* read - (Defaults to 5 minutes) Used when retrieving the Diagnostics Setting.
* delete - (Defaults to 60 minutes) Used when deleting the Diagnostics Setting.

Example Input:
diagnostic_settings = {
"diagnostic" = {
name = "diagnostic"
log_analytics_workspace_id = "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/myResourceGroup/providers/Microsoft.OperationalInsights/workspaces/myLogAnalyticsWorkspace"
storage_account_id = "/subscriptions/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/resourceGroups/myResourceGroup/providers/Microsoft.Storage/storageAccounts/myStorageAccount"
log_analytics_destination_type = "Dedicated"
eventhub_authorization_rule_id = null
eventhub_name = null
partner_solution_id = null
enabled_log = [
{
category = null
category_group = "allLogs"
}
]
metric = {
category = "AllMetrics"
enabled = true
}
timeouts = {
create = "30"
update = "30"
read = "5"
delete = "60"
}
}
}
map(object({
name = optional(string)
log_analytics_workspace_id = optional(string)
log_analytics_destination_type = optional(string, "Dedicated")
storage_account_id = optional(string)
eventhub_authorization_rule_id = optional(string)
eventhub_name = optional(string)
partner_solution_id = optional(string)
enabled_log = optional(list(object({
category = optional(string)
category_group = optional(string)
})))
metric = optional(object({
category = optional(string, "AllMetrics")
enabled = optional(bool)
}))
timeouts = optional(object({
create = optional(string, "30")
update = optional(string, "30")
read = optional(string, "5")
delete = optional(string, "60")
}))
}))
null no
file_copy_enabled * copy_paste_enabled - (Optional) Is Copy/Paste feature enabled for the Bastion Host. Defaults to true.

~> Note: file_copy_enabled is only supported when sku is Standard or Premium.

Example Input:
file_copy_enabled = "false"
bool true no
ip_configuration * ip_configuration - (Optional) A ip_configuration block as defined below. Changing this forces a new resource to be created.
A ip_configuration block supports the following:
* name - (Required) The name of the IP configuration. Changing this forces a new resource to be created.
* subnet_id - (Required) Reference to a subnet in which this Bastion Host has been created. Changing this forces a new resource to be created.
~> Note: The Subnet used for the Bastion Host must have the name AzureBastionSubnet and the subnet mask must be at least a /26.
* public_ip_address_id - (Required) Reference to a Public IP Address to associate with this Bastion Host. Changing this forces a new resource to be created.

Example Input:
ip_configuration = {
name = "myIpConfig"
subnet_id = "/subscriptions/xxxx/resourceGroups/xxxx/providers/Microsoft.Network/virtualNetworks/myVnet/subnets/AzureBastionSubnet"
public_ip_address_id = "/subscriptions/xxxx/resourceGroups/xxxx/providers/Microsoft.Network/publicIPAddresses/myPublicIP"
}
object({
name = string
subnet_id = string
public_ip_address_id = string
})
null no
ip_connect_enabled * ip_connect_enabled - (Optional) Is IP Connect feature enabled for the Bastion Host. Defaults to false.

~> Note: ip_connect_enabled is only supported when sku is Standard or Premium.

Example Input:
ip_connect_enabled = "false"
bool false no
kerberos_enabled * kerberos_enabled - (Optional) Is Kerberos authentication feature enabled for the Bastion Host. Defaults to false.

~> Note: kerberos_enabled is only supported when sku is Standard or Premium.

Example Input:
kerberos_enabled = "false"
bool false no
scale_units * 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.

~> Note: scale_units only can be changed when sku is Standard or Premium. scale_units is always 2 when sku is Basic.

Example Input:
scale_units = "2"
number 2 no
session_recording_enabled * 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.

Example Input:
session_recording_enabled = "false"
bool false no
shareable_link_enabled * shareable_link_enabled - (Optional) Is Shareable Link feature enabled for the Bastion Host. Defaults to false.

~> Note: shareable_link_enabled is only supported when sku is Standard or Premium. Example Input:

Example Input:
shareable_link_enabled = "false"
bool false no
sku * 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.

Example Input:
sku = "Standard"
string "Basic" no
tags * tags - (Optional) A mapping of tags to assign to the resource.

Example input:
tags = {
env = test
region = gwc
}
map(string) null no
timeouts The timeouts block allows you to specify timeouts for certain actions:
* create - (Defaults to 30 minutes) Used when creating the Bastion Host.
* read - (Defaults to 5 minutes) Used when retrieving the Bastion Host.
* update - (Defaults to 30 minutes) Used when updating the Bastion Host.
* delete - (Defaults to 30 minutes) Used when deleting the Bastion Host.
object({
create = optional(string, "30")
read = optional(string, "5")
update = optional(string, "30")
delete = optional(string, "30")
})
null no
tunneling_enabled * tunneling_enabled - (Optional) Is Tunneling feature enabled for the Bastion Host. Defaults to false.

~> Note: tunneling_enabled is only supported when sku is Standard or Premium.
Example Input:
tunneling_enabled = "false"
bool false no
virtual_network_id * virtual_network_id - (Optional) The ID of the Virtual Network for the Developer Bastion Host. Changing this forces a new resource to be created.

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

Example Input:
virtual_network_id = "/subscriptions/xxxx/resourceGroups/xxxx/providers/Microsoft.Network/virtualNetworks/myVnet"
string null no
zones * zones - (Optional) Specifies a list of Availability Zones in which this Public Bastion Host should be located. Changing this forces a new resource to be created.

Example Input:
zones = ["1", "2"]
list(string) null no

Outputs

Name Description
bastion_host * name – (Required) The name of the Bastion Host.
* resource_group_name – (Required) The name of the Resource Group where the Bastion Host exists.
* id – The ID of the Bastion Host.
* location – The Azure Region where the Bastion Host exists.
* copy_paste_enabled – I Is Copy/Paste feature enabled for the Bastion Host.
* file_copy_enabled – Is File Copy feature enabled for the Bastion Host.
* sku - The SKU of the Bastion Host.
* ip_connect_enabled – Is IP Connect feature enabled for the Bastion Host.
* scale_units – The number of scale units provisioned for the Bastion Host.
* shareable_link_enabled – Is Shareable Link feature enabled for the Bastion Host.
* tunneling_enabled – Is Tunneling feature enabled for the Bastion Host.
* session_recording_enabled – Is Session Recording feature enabled for the Bastion Host.
* dns_name – The FQDN for the Bastion Host.
* tags –A mapping of tags assigned to the Bastion Host.
* zones – A list of Availability Zones in which this Bastion Host is located.

The ip_configuration block supports the following:
* name - The name of the IP configuration.
* subnet_id - Reference to the subnet in which this Bastion Host has been created.
* public_ip_address_id Reference to a Public IP Address associated to this Bastion Host.

Example output:
output "bastion_dns_name" {
value = module.bastion.bastion_host.name
}

Modules

No modules.

🌐 Additional Information

For more information about Azure Bastion and their configurations, refer to the [https://learn.microsoft.com/en-us/azure/bastion/bastion-overview). This module helps you manage Azure Bastion.

📚 Resources

⚠️ Notes

  • Public IP Requirement: Bastion requires a Standard Public IP attached directly to the Bastion resource (not the VM). Ensure this IP remains available, as removing it will disrupt Bastion access.
  • Understand SKU Limitations: Features like file transfer, IP Connect, and session recording are only available with Standard or Premium SKUs. If you select Basic, you will not have access to these features.
  • File Transfer and Tunneling: While helpful, features like file transfer and tunneling could introduce security risks if improperly configured. Enable these features only if necessary, and consider additional monitoring to detect unauthorized activity.
  • Cost Management: Hourly and Data Transfer Charges: Bastion is billed hourly, plus data transfer costs, which can accumulate over time. Regularly monitor usage and shut down VMs not in active use to avoid unnecessary charges.
  • Failover and High Availability: Availability Zones for Redundancy: For production environments, use Availability Zones (Standard SKU) to ensure high availability and minimize downtime. A single zone Bastion Host is vulnerable to outages in that zone.
  • Validate your Terraform configuration to ensure that Azure Bastion resources are created and configured correctly, including diagnostic settings and role assignments.

🧾 License

This module is licensed under the MIT License. See the LICENSE file for more details.

About

This module is designed to manage an Azure Bastion

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages