Hello and happy 2019! I figured I'd start the year fresh with a cloud related topic and provide a tutorial on setting up an Azure lab environment. I have decided to tackle the AZ-300 and AZ-301 to obtain the Azure Solutions Architect Expert certification.

Today I'll be laying down the foundation of my Azure lab environment and set up a jump host also known as a bastion host for those who are familiar with AWS. Why would I want to setup a jump host? Security - with a jump host, you don't have ssh opened to the public. Ssh to individual servers are only allowed through the jump host with this you can consolidate your logging and heavy security measures on the jump host. However this does not mean removing all of your security measures on your individual servers, this just lowers the attack surface. The overall purpose of the jump host is to provide a single point of entry to my environment in a region.

The Layout:

For this demonstration, I will be using two virtual machines running, Centos 7.5 and Ubuntu 18.04. Centos will be acting as my jump host and Ubuntu 18.04 will be my application server. Only authorized users will be allowed to ssh to the jump host and the only port open on to the public on the app host are port 80 and 443.

Resource Group Setup:

To start off, I'll create a resource group for the jump host. This will group all of the components needed for the jump host together. I will be naming my jump host's resource group: ue2-bastion and application resource group: ue2-app01. Feel free to name yours as you see fit, I chose this naming scheme to represent the region (US East 2) and function (app or bastion).

Server Setup:

I'll begin with the jump host resource group, create a new virtual machine using the CentOS-based 7.5 image. I will be using password for the administrator account for simplicity sake of this tutorial, but feel free to use SSH public keys. If however you want to use password for a production environment, please setup a proper VPN tunnel. The VPN tunnel will add another layer of security and lower the jump host's attack surface. Make sure to allow ssh through the inbound ports. In the disk section I will only be using  the premium SSD. No actual application specific data will ever be on the jump host.

Let's move to the network configuration since this will be quite involved. First thing, the virtual network will need to be edited. Click on "Create new", in the new window that appears, I'll be switching the address range and subnet name. I know for a fact that host count on my bastion vnet will never go beyond ten hosts, so having an address range of which allows for 256 addresses is a waste! I'll use which will give me 8 addresses if I ever need anything else on the same virtual network (vnet) as my jump host.

In the management section, I like to enable auto-shutdown on my lab environment. Obviously, don't configure this if you're on a production environment that requires 24/7 uptime.

Now we'll bring up another server for the application. Go into application resource group (ue2-app01) and create a new server. For this server, I'll be using Ubuntu 18.04 as the operating system. Same setup as as the jump host but with a different image, Ubuntu instead of CentOS, different vnet and subnet, and finally allow HTTP and HTTPS public inbound ports. I set the address space to for the app vnet. This gives me sixteen addresses to play with, more than enough IP's for any addition in the future. For the subnet name, I named it ue2-app01-vnet-sub, once again this name is arbitrary. You can use whatever naming convention makes sense to you.

Once the app host is up, go into the app resource group and select the your app's virtual machine, mine is ue2-app01-vm01.

After you have selected the app virtual machine go into the networking tab on the left and click on "Add inbound port rule". In here, I'll show you how to allow ssh access to the app virtual machine.

In here, change the source to IP Addresses and change the source IP addresses/CIDR ranges to the jump host's network segment ( Source port ranges can be left with a ' * ', change destination to IP Addresses and change destination IP addresses/CIDR ranges to the specific private IP of app virtual machine ( Set the destination port ranges to 22 and the protocol to tcp, for action set it to allow, set the priority to 1000. Lastly I like to easily and quickly glance at what the inbound port rule does so I gave it the name ssh-from-ue1-bastion.


Alright, now comes the fun part! So we have our jump host and app server configured, but we can only ssh to the jump host's public IP and when we try to ssh to the app server's public IP nothing happens, as expected. Now if you have gone ahead and tried to ssh from the jump host to the app server using the app server's private IP, you may have noticed that you couldn't ssh into it. This is because the jump host's vnet is not aware of the app server's vnet, it does not have a route to that network.

This is where the magic of peering will help us out! Go to the app host resource group and select the virtual network for the app host. Mine is named ue2-app01-vnet.

Select 'Peerings' and hit 'Add'

In the window that appears give it a name. I named mine ue2-app01-vnet-to-bastion. For 'Peer details' select 'Resource manager' and check off the box for 'I know my resource ID' and supply the resource ID of your jump host's vnet. It will be located under your jump host's vnet properties section.

Peering on ue2-app01-vnet. Ignore the red exclamation points

Once the app host's vnet is squared away, let's hop to the jump host and configure it's peering. However before you do, make sure you have the resource ID of your app host's vnet. As soon as you have it repeat the steps outlined previously for setting up peering for the app server's vnet. The only difference this time around is that we're putting in the resource ID of the app server's vnet instead of the jump host's vnet.

As soon as you have it configured click the new peerings and you should see in the "Peering status" that it is "Connected" if it says 'initiated' or anything else the peering may not have been established.

SSH test:

Time for the true test, let's see if you can actually ssh all the way into the app server. I haven't configured DNS on my environment so I'll be relying on private IP as soon as I get into my jump host.

Last login: Tue Jan  8 18:42:01 2019 from exampleisp.com
[scleft@ue2-bastion-vm01 ~]$

My app server's private IP is

[scleft@ue2-bastion-vm01 ~]$ ssh
scleft@'s password:
Welcome to Ubuntu 18.04.1 LTS (GNU/Linux 4.15.0-1035-azure x86_64)
Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage
System information as of Tue Jan  8 22:56:25 UTC 2019
System load:  0.0               Processes:           113
  Usage of /:   4.0% of 28.90GB   Users logged in:     0
  Memory usage: 4%                IP address for eth0:
  Swap usage:   0%
packages can be updated.
updates are security updates.
Last login: Tue Jan  8 19:19:17 2019 from

Success, it's working!!! Now you're able to connect to the app server without having to expose port 22 to the public. Before we part ways, if anyone wants to earn extra security points, it's a good idea to setup a VPN network and only allow any IP's from the VPN to ssh to the jump host. Extremely good idea if you're setting up a production environment, but for my lab use, this is sufficient - I'll most likely delete this environment and recreate it ten more times. 🤣