What is Azure Bastion Terraform?
Azure Bastion Terraform means defining Azure’s managed secure VM administration service as infrastructure as code instead of building it manually in the portal. The main resource is azurerm_bastion_host, and Microsoft’s current Bastion Terraform quickstart shows it being deployed with a resource group, virtual network, dedicated Bastion subnet, and public IP. :contentReference[oaicite:6]{index=6}
Why Terraform is used for Azure Bastion
Bastion may look straightforward in the portal, but it is still a security-sensitive architecture component. Terraform helps engineering teams standardize secure VM access, enforce the dedicated subnet model, keep naming and tagging clean, and reuse the same administration-access pattern across development, test, and production environments. Microsoft’s quickstart and resource model make this repeatable approach a good fit for infrastructure as code. :contentReference[oaicite:7]{index=7}
Consistency
The same Bastion architecture can be deployed across multiple environments without rebuilding secure access decisions by hand.
Reviewability
Engineers can review subnet placement, public IP usage, and Bastion feature settings through pull requests before deployment.
Safer operations
Terraform reduces drift and makes it easier to keep administration access aligned with your broader Azure security design.
Azure Bastion Terraform explained with the 5 Ws + How
This keeps the page useful for beginners, working engineers, and interview learners who want practical Azure networking and operations understanding.
What
Terraform-based deployment of Azure Bastion using the AzureRM provider.
Why
To manage secure RDP and SSH access to private VMs in a repeatable and reviewable way.
When
Use it when Azure VMs should remain private but administrators still need secure remote access.
Where
Inside Azure resource groups and VNets, using the dedicated AzureBastionSubnet and a Bastion host resource. :contentReference[oaicite:8]{index=8}
Who
DevOps engineers, platform teams, cloud engineers, operations teams, and architects managing secure Azure VM access.
How
Terraform declares the Bastion host, required networking components, and optional feature settings, and Azure builds the secure VM access layer accordingly. :contentReference[oaicite:9]{index=9}
Prerequisites before writing the Terraform
Bastion design starts with administration-access architecture. A clean Terraform deployment needs more than just the Bastion resource. It needs the right virtual network layout, the correct Bastion subnet, and a clear decision that Bastion is the right operational access pattern for the environment.
Common prerequisites
- Azure subscription and Terraform AzureRM provider
- Resource group
- Virtual network
- Dedicated
AzureBastionSubnet - Public IP for the standard Bastion deployment model
- Clear target VM administration requirements
Production planning items
- Which Bastion SKU the environment needs
- Whether features like tunneling or copy/paste should be enabled
- Whether native client workflows matter for operations
- Whether private-only Bastion should be evaluated separately
- How Bastion fits into hub-and-spoke or peered VNet design
- How administrators will authenticate and operate through Bastion
Terraform resource model for Azure Bastion
Bastion Terraform is centered on the Bastion host resource, but the working deployment also depends on the VNet, required Bastion subnet, and public IP in the standard quickstart pattern. The current AzureRM resource model also supports optional feature flags such as copy/paste, file copy, shareable link, and tunneling. :contentReference[oaicite:10]{index=10}
| Terraform resource or block | Azure concept | Purpose |
|---|---|---|
azurerm_bastion_host |
Bastion host | Creates the managed Bastion service for secure VM administration |
azurerm_virtual_network |
Virtual network | Provides the network where Bastion is deployed |
azurerm_subnet |
AzureBastionSubnet |
Provides the dedicated subnet Bastion requires |
azurerm_public_ip |
Bastion public IP | Provides the Bastion endpoint for the standard deployment model |
ip_configuration |
Bastion IP configuration | Binds the Bastion host to the required subnet and public IP |
tunneling_enabled |
Native client tunneling support | Enables supported native client and tunneling workflows |
copy_paste_enabled |
Clipboard behavior | Controls clipboard-related feature behavior for sessions |
file_copy_enabled |
File transfer support | Controls file copy capability in supported scenarios |
Recommended code structure
For real projects, do not scatter Bastion logic randomly through files. Bastion affects security, operations, and remote access design, so even a relatively small deployment benefits from clean module structure.
terraform/
├── main.tf
├── variables.tf
├── outputs.tf
├── providers.tf
├── terraform.tfvars
└── modules/
└── bastion/
├── main.tf
├── variables.tf
└── outputs.tf
Root module
Connects shared network resources, environment naming, and the VNet or hub architecture that Bastion belongs to.
Reusable child module
Encapsulates the Bastion host, required subnet, public IP, and selected feature flags so multiple environments stay consistent.
Variables and outputs
Keep names, tags, SKU, feature settings, and network identifiers separated from the core resource logic.
Terraform example for Azure Bastion
This example follows the current Azure Bastion Terraform quickstart model: resource group, VNet, required AzureBastionSubnet, Standard public IP, and Bastion host. It also shows a few commonly used feature flags supported by the current resource model. :contentReference[oaicite:11]{index=11}
terraform {
required_version = ">= 1.5.0"
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = ">= 4.0.0"
}
random = {
source = "hashicorp/random"
version = "~> 3.0"
}
}
}
provider "azurerm" {
features {}
}
resource "random_pet" "name" {
length = 2
}
resource "azurerm_resource_group" "rg" {
name = "rg-bastion-${random_pet.name.id}"
location = "South Africa North"
}
resource "azurerm_virtual_network" "vnet" {
name = "vnet-bastion-${random_pet.name.id}"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
address_space = ["10.50.0.0/16"]
}
resource "azurerm_subnet" "bastion_subnet" {
name = "AzureBastionSubnet"
resource_group_name = azurerm_resource_group.rg.name
virtual_network_name = azurerm_virtual_network.vnet.name
address_prefixes = ["10.50.1.0/26"]
}
resource "azurerm_public_ip" "bastion_pip" {
name = "pip-bastion-${random_pet.name.id}"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
allocation_method = "Static"
sku = "Standard"
tags = {
environment = "prod"
service = "bastion"
owner = "platform-team"
}
}
resource "azurerm_bastion_host" "bastion" {
name = "bas-${random_pet.name.id}"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
sku = "Standard"
copy_paste_enabled = true
file_copy_enabled = true
tunneling_enabled = true
shareable_link_enabled = false
ip_configuration {
name = "bastion-ip-config"
subnet_id = azurerm_subnet.bastion_subnet.id
public_ip_address_id = azurerm_public_ip.bastion_pip.id
}
tags = {
environment = "prod"
service = "bastion"
owner = "platform-team"
}
}
output "bastion_host_id" {
value = azurerm_bastion_host.bastion.id
}
output "bastion_public_ip" {
value = azurerm_public_ip.bastion_pip.ip_address
}
Basic variation
If you want a simpler Bastion configuration, reduce the feature flags and change the SKU deliberately after validating which capabilities your environment actually needs. Azure’s current quickstart still defaults to Standard in the Terraform example. :contentReference[oaicite:12]{index=12}
How the Terraform code maps to the real Azure service
Many engineers can paste Terraform, but not everyone understands how each resource changes Azure behavior. This section makes the mapping clear.
Virtual network placement
azurerm_virtual_network defines where the Bastion service lives and where it will provide secure administration access to private VMs.
Dedicated Bastion subnet
azurerm_subnet named AzureBastionSubnet is a core requirement in the standard Bastion deployment model. Bastion is not placed into an arbitrary application subnet. :contentReference[oaicite:13]{index=13}
Bastion public endpoint
azurerm_public_ip provides the public endpoint for the Bastion host in the standard deployment design used by the current Terraform quickstart. :contentReference[oaicite:14]{index=14}
Bastion host resource
azurerm_bastion_host creates the managed Azure service that administrators use for secure RDP and SSH access to private VMs.
Feature flags
Resource settings such as tunneling_enabled, copy_paste_enabled, and file_copy_enabled control which supported Bastion features are enabled for the deployment. :contentReference[oaicite:15]{index=15}
Outputs
Outputs expose the Bastion host ID and Bastion public IP so other modules and operations workflows can consume the deployed resources cleanly.
Feature flags and options
One of the reasons Bastion Terraform is more than a one-line resource is that feature settings affect how operations teams actually use the service. The current Bastion resource model includes settings for copy/paste, file copy, tunneling, and shareable link support. :contentReference[oaicite:16]{index=16}
Tunneling
Tunneling is the key setting commonly associated with enabling native client workflows in Bastion. Microsoft’s support answer specifically points to tunneling_enabled = true for native client support in Terraform. :contentReference[oaicite:17]{index=17}
Copy and file options
Clipboard and file transfer related settings should be enabled deliberately based on operational needs and security expectations, not by habit.
AzureBastionSubnet model
This is one of the most important Bastion topics. Bastion is not deployed into your regular application subnet. It uses the dedicated AzureBastionSubnet in the standard architecture model described by Microsoft’s Terraform and Bastion configuration guidance. :contentReference[oaicite:18]{index=18}
Administrator
|
v
+-----------------------------------+
| Azure Bastion Host |
| Public endpoint + managed service |
+-----------------------------------+
|
v
+-----------------------------------+
| AzureBastionSubnet |
| Dedicated Bastion subnet |
+-----------------------------------+
|
v
+-----------------------------------+
| Private Azure VNet |
| Target VMs on private IP space |
+-----------------------------------+
Why the dedicated subnet matters
It keeps the Bastion architecture structured and separate from normal application workloads, which is important for both clarity and supportability.
Why engineers get this wrong
Some teams assume Bastion can just live in any subnet, but the standard Azure Bastion deployment model explicitly expects the dedicated Bastion subnet.
AzureBastionSubnet is a first-class design requirement, not an optional naming preference.
Real-world Azure Bastion Terraform use cases
Practical examples make this page useful and avoid generic Terraform content by grounding Bastion in real Azure administration scenarios.
Private production VM administration
A platform team uses Terraform to deploy Bastion so operations can securely reach production VMs without putting public IPs on those VMs.
Hub-and-spoke administration access
A central Bastion deployment in a shared operations VNet supports private administration across a broader Azure network architecture where peering is part of the design.
Replacing jump hosts
A security-conscious team standardizes Bastion in Terraform to eliminate self-managed jump boxes and keep administration access patterns consistent across environments.
Terraform vs manual Azure portal deployment
Both approaches can work, but Terraform becomes more valuable as secure administration architecture grows and must remain consistent across environments.
| Approach | Best for | Strength | Weakness |
|---|---|---|---|
| Terraform | Repeatable production deployments | Version control, consistency, reviewable changes | Requires structure and code discipline |
| Azure Portal | One-off testing or learning | Fast for initial exploration | Hard to reproduce accurately across environments |
Best practices
Practical guidance is what turns a Terraform page from a snippet page into a real engineering reference.
Keep target VMs private
Use Bastion when the goal is secure administration without direct public IP exposure on the target VMs.
Choose SKU deliberately
Pick the Bastion tier based on real operational needs, especially if native client workflows or broader production capabilities matter.
Treat AzureBastionSubnet as required architecture
Do not treat the Bastion subnet as a casual implementation detail. It is a core part of the design.
Enable feature flags intentionally
Only enable tunneling, file copy, or related features if they fit your operational and security model.
Tag resources clearly
Bastion affects security and operations, so ownership, environment, and purpose should always be obvious.
Keep Bastion separate from application ingress thinking
Bastion is for VM administration, not application delivery, WAF, or public frontend design.
Common mistakes
Platform-specific mistakes are what make this page practical instead of generic. These are the things teams commonly get wrong with Bastion Terraform.
Using the wrong subnet pattern
Some engineers try to place Bastion into a normal application subnet instead of the dedicated Bastion subnet.
Confusing Bastion with broader VPN connectivity
Bastion is focused on VM administration, not general user-to-network private access across all scenarios.
Enabling features blindly
Teams sometimes enable all feature flags without checking whether those workflows fit the organization’s security expectations.
Keeping public IPs on target VMs anyway
This can weaken the whole point of using Bastion as the secure administration access layer.
Weak naming and tagging
Bastion is security-sensitive infrastructure, so unclear names and missing tags make support and governance harder.
Treating Bastion like a one-off manual setup
In larger environments, Bastion design should be standardized and reusable, not recreated differently each time.
Frequently asked questions
FAQ sections help capture real search intent and make the page more complete for working engineers and learners.
What Terraform resource creates Azure Bastion?
The main Terraform resource is azurerm_bastion_host. :contentReference[oaicite:19]{index=19}
What subnet is required for Azure Bastion in Terraform?
The standard Bastion deployment model uses the dedicated AzureBastionSubnet. :contentReference[oaicite:20]{index=20}
Does the standard Terraform Bastion quickstart use Standard SKU?
Yes. Microsoft’s current Terraform quickstart for Bastion deploys Bastion with the Standard SKU. :contentReference[oaicite:21]{index=21}
How do I enable native client support in Terraform?
Microsoft’s support guidance points to tunneling_enabled = true for native client support in Terraform. :contentReference[oaicite:22]{index=22}
Do target VMs need public IPs when using Bastion?
No. Microsoft’s Bastion overview says Bastion supports secure access to VMs using private IP addresses, without requiring a public IP on the VM. :contentReference[oaicite:23]{index=23}
Can I use file copy and clipboard features with Bastion in Terraform?
The current Bastion resource model includes feature flags such as file_copy_enabled and copy_paste_enabled, subject to supported tier and workflow behavior. :contentReference[oaicite:24]{index=24}