What if I told you that you could access your Azure Cloud Resources and tick the following boxes:
- More secure than a VPN
- More secure than a Bastion Host and Jumpbox
- No need for patching and SOC2 compliance reports
If your cloud environment is serverless, why settle for less when it comes to remote access?
As soon as you introduce a jump box, you are required to patch the damn thing and this eats into the Opex budget in a big way.
So what is the solution?
What if you had a docker image with all the tools you need for support that you can spin up into an Azure Container Instance and access on demand, with the filesystem running off Azure Blob Storage?
Well, this is possible, and the good news is that you do not need to build it yourself. Microsoft already offers it.
Welcome to Azure Cloud Shell with VNET Integration!

The only limitation is that the Storage Account only supports Primary Regions, however Microsoft notified me today that Australia East is now supported.
Microsoft is currently working on more secondary region support, just something to be aware of from a security/data sovereignty perspective.
So the experience is like this.
- Log into the Azure Portal
- Choose Cloud Shell with advanced options – Select VNET Integration and select the subnet / storage account that we will terraform
- Boom – You are in the Azure network and Cloud Shell will have all your common support tools that your require.
Terraform
We will need:
- Dedicated subnet for CloudShell ACI instances to spin up in.
"csh" = "10.1.12.0/26"
- Dedicated support subnet for storage account
"sup" = "10.1.13.0/26"
- A dedicate subnet for the Azure Relay
relay_subnet = "10.1.14.0/26"
# Container instance built in OID for permissions / delegation
# Manually grant in Azure AD
container_instance_oid = "4c1b7058-e8ea-4854-abd2-bbb0abb6cd24"
- Storage Account for OS filesystem – network rules for Cloudshell
# See https://github.com/Azure/azure-quickstart-templates/blob/master/demos/cloud-shell-vnet-storage/azuredeploy.json
resource "azurerm_storage_account" "cloud_shell" {
name = "st${var.client}${var.env}${var.location_shortname}sup"
resource_group_name = azurerm_resource_group.rg.name
location = azurerm_resource_group.rg.location
allow_blob_public_access = false
account_tier = "Standard"
access_tier = "Cool"
account_replication_type = "LRS"
tags = local.tags
enable_https_traffic_only = true
network_rules {
bypass = ["None"]
default_action = "Deny"
ip_rules = [ "101.112.8.233" ]
virtual_network_subnet_ids = [
azurerm_subnet.cloud_shell_subnet.id,
azurerm_subnet.subnet["sup"].id
]
}
}
resource "azurerm_storage_share" "cloud_shell" {
name = "cshsupport"
storage_account_name = azurerm_storage_account.cloud_shell.name
quota = 50
}
- Then a Cloudshell Subnet leveraging subnet delegation so ACI can control network devices
resource "azurerm_subnet" "cloud_shell_subnet" {
name = "snet-${local.resource_id}-${var.client}-csh"
resource_group_name = azurerm_resource_group.rg.name
virtual_network_name = azurerm_virtual_network.network.name
address_prefixes = [var.cloud_shell_subnet]
delegation {
name = "delegation"
service_delegation {
name = "Microsoft.ContainerInstance/containerGroups"
}
}
service_endpoints = [
"Microsoft.Storage"
]
}
- Azure Relay Subnet and setup
resource "azurerm_subnet" "relay_subnet" {
name = "snet-${local.resource_id}-${var.client}-rel"
resource_group_name = azurerm_resource_group.rg.name
virtual_network_name = azurerm_virtual_network.network.name
address_prefixes = [var.relay_subnet]
enforce_private_link_endpoint_network_policies = true
enforce_private_link_service_network_policies = false
}
resource "azurerm_relay_namespace" "relay_namespace" {
name = "rel-${local.resource_id}-${var.client}-csh"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
sku_name = "Standard"
tags = local.tags
}
resource "azurerm_network_profile" "cloud_shell_containers" {
name = "netpr-${local.resource_id}-${var.client}-csh"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
tags = local.tags
container_network_interface {
name = "eth-${azurerm_subnet.cloud_shell_subnet.name}"
ip_configuration {
name = "ipconfig-${azurerm_subnet.cloud_shell_subnet.name}"
subnet_id = azurerm_subnet.cloud_shell_subnet.id
}
}
}
resource "azurerm_private_endpoint" "relay_csh" {
name = "prve-${local.resource_id}-${var.client}-csh"
location = azurerm_resource_group.rg.location
resource_group_name = azurerm_resource_group.rg.name
tags = local.tags
subnet_id = azurerm_subnet.relay_subnet.id
private_service_connection {
name = "prvsc-${local.resource_id}-${var.client}-csh"
private_connection_resource_id = azurerm_relay_namespace.relay_namespace.id
subresource_names = ["namespace"]
is_manual_connection = false
}
}
resource "azurerm_private_dns_zone" "private_dns_relay" {
name = "privatelink.servicebus.windows.net"
resource_group_name = azurerm_resource_group.rg.name
tags = local.tags
}
resource "azurerm_private_dns_a_record" "relay_dns_a_record" {
name = "csh"
zone_name = azurerm_private_dns_zone.private_dns_relay.name
resource_group_name = azurerm_resource_group.rg.name
ttl = 3600
records = [azurerm_private_endpoint.relay_csh.private_service_connection[0].private_ip_address]
}
resource "azurerm_private_dns_zone_virtual_network_link" "relay_vnet_link" {
name = "dnsvl-${local.resource_id}-${var.client}-csh"
resource_group_name = azurerm_resource_group.rg.name
private_dns_zone_name = azurerm_private_dns_zone.private_dns_relay.name
virtual_network_id = azurerm_virtual_network.network.id
registration_enabled = false
}
Now connect to CloudShell
So the above should get you on the right track for the most secure and painless free maintenance Remote Access solution for Azure Cloud!
Goodbye VPN!
Goodbye Bastion Host!
Goodbye Jumpboxes!

Source: https://docs.microsoft.com/en-us/azure/cloud-shell/private-vnet
You must be logged in to post a comment.