Ensure only desired endpoints are open in Azure

Ensure only desired endpoints are open in Azure

Q. I want to ensure only certain endpoints are open to the Internet for my Azure VMs, is there an easy way to check and correct if extra endpoints are configured?

A. The Azure Service Manager (classic) utilizes cloud services that have a Virtual IP (VIP) that is an Internet routable IP address. Endpoints are created for specific ports via this VIP that point to local ports on specific VMs within the cloud service. These endpoints are accessible via the Internet and once connectivity from a virtual network in Azure to your on-premises network is established via site-to-site VPN or ExpressRoute you should limit endpoints exposed to the Internet ensuring the only endpoints are services you specifically want to publish to the Internet such as HTTP or HTTPS and not RDP or WS-Management.

A good way to ensure traffic from the Internet cannot communicate with your VMs is to create a Network Security Group (NSG) and apply it to your virtual subnets. In the NSG you can specify rules so that only specific ports would be allowed from the Internet to the IP range within the subnet/virtual network address space. For example below I create a NSG then apply it to my subnet. This would only allow HTTP and HTTPS which means even if RDP was enabled via an endpoint it would not be accessible as the NSG would block that traffic to the VM if it originated from the Internet. You should take care before implementing this type of rule as if other endpoints are required that will now be blocked and will not work!

#Network Security Groups (NSG)
New-AzureNetworkSecurityGroup -Name "BlockInternet" -Location "East US" `
    -Label "NSG to block traffic from Internet except 80 and 443"

Get-AzureNetworkSecurityGroup -Name "BlockInternet" | 
    Set-AzureNetworkSecurityRule -Name HTTP -Type Inbound -Priority 100 `
    -Action Allow -SourceAddressPrefix 'INTERNET' -SourcePortRange '*' `
    -DestinationAddressPrefix 'VIRTUAL_NETWORK' -DestinationPortRange '80' -Protocol TCP

Get-AzureNetworkSecurityGroup -Name "BlockInternet" | 
    Set-AzureNetworkSecurityRule -Name HTTPS -Type Inbound -Priority 101 `
    -Action Allow -SourceAddressPrefix 'INTERNET' -SourcePortRange '*' `
    -DestinationAddressPrefix 'VIRTUAL_NETWORK' -DestinationPortRange '443' -Protocol TCP

Get-AzureNetworkSecurityGroup -Name "BlockInternet" -Detailed

#Associate a NSG to a subnet
Get-AzureNetworkSecurityGroup -Name "BlockInternet" | 
    Set-AzureNetworkSecurityGroupToSubnet -VirtualNetworkName 'VirtNet115' -SubnetName 'Static-Net'

#View
Get-AzureNetworkSecurityGroupForSubnet -SubnetName 'Static-Net' -VirtualNetworkName 'VirtNet115' 

The code above would be applied to all of the subnets in the virtual network. To enable RDP from the Internet you could use the following however this would not be recommended.

Get-AzureNetworkSecurityGroup -Name "BlockInternet" | 
    Set-AzureNetworkSecurityRule -Name RDP -Type Inbound -Priority 102 `
    -Action Allow -SourceAddressPrefix 'INTERNET' -SourcePortRange '*' `
    -DestinationAddressPrefix 'VIRTUAL_NETWORK' -DestinationPortRange '3389' -Protocol TCP

#To remove from the NSG
#Get-AzureNetworkSecurityGroup -Name "BlockInternet" | 
#Remove-AzureNetworkSecurityRule -Name RDP

If you change the rules in the NSG there is no need to reapply the NSG, the change should take affect in about 30 seconds.

If you do now want to use this whitelist approach another way is to run a script to detect endpoints that exist outside of the allowed. I wrote the script below which will list all endpoints outside of a range you specify. Additionally it will detect if a VM has an instance-level IP which enables direct access from the Internet. Below is the script. This script prompts the user for the action to take which can be to delete the endpoint, shutdown the VM or ignore. If you were going to run this as some type of automated process you would remove the user interaction and simply specify the desired action and change from Write-Host to Write-Output. Change the $allowedports variable to the ports you wish to be allowed. Note this script works for Azure Service Manager, I will create a different version in the future for Azure Resource Manager and the load balancer object and NAT rules.

$allowedports = 80,443
$vms = get-azurevm
foreach($vm in $vms)
{
    #Check if it has an instance level IP address which would allow any port
    if(Get-AzurePublicIP -VM $vm)
    {
    $outputstr = "*** Found instance level public IP address for VM " + $vm.Name + " which would allow all ports ***"
    Write-Host -ForegroundColor White -BackgroundColor DarkRed $outputstr
    }
      $endpoints = Get-AzureEndpoint -VM $vm
    foreach($endpoint in $endpoints)
    {
    #Check if the local port is allowed
    $allowed = $allowedports.Contains($endpoint.LocalPort)

    $outputstr = "Found endpoint for VM " + $vm.Name + " for private port " + $endpoint.LocalPort + " (" + $endpoint.name + ")"

    if ($allowed)
    {
        Write-Host -ForegroundColor Green $outputstr
    }
    else
    {
        Write-Host -ForegroundColor Red $outputstr
	    #REMOVE ALL THE CODE BELOW AND REPLACE WITH THE REQUIRED CODE FROM THE SWITCH IF YOU WISH TO AUTOMATE
        $caption = "Illegal Endpoint";
        $message = "What do you want to do?";
        $deleteendpoint = new-Object System.Management.Automation.Host.ChoiceDescription "&Delete","Delete the endpoint";
        $shutdownvm = new-Object System.Management.Automation.Host.ChoiceDescription "&Shutdown","Shutdown the VM";
        $ignore = new-Object System.Management.Automation.Host.ChoiceDescription "&Ignore","Ignore";
        $choices = [System.Management.Automation.Host.ChoiceDescription[]]($deleteendpoint,$shutdownvm,$ignore);
        $answer = $host.ui.PromptForChoice($caption,$message,$choices,2)

    switch ($answer){
        0 {get-azurevm -ServiceName $vm.ServiceName -Name $vm.Name | Remove-AzureEndpoint -Name $endpoint.Name | Update-AzureVM; break}
        1 {get-azurevm -ServiceName $vm.ServiceName -Name $vm.Name | Stop-AzureVM -Force ; break}
        2 {"Ignoring"; break}
        }
    }
    }
}

A version that just disables any non-legal endpoints would be the following BUT BE VERY CAREFUL before using something like this as it will remove all endpoints and you need to be very certain that the endpoints are not required!

$allowedports = 80,443
$vms = get-azurevm
foreach($vm in $vms)
{
    #Check if it has an instance level IP address which would allow any port
    if(Get-AzurePublicIP -VM $vm)
    {
    $outputstr = "*** Found instance level public IP address for VM " + $vm.Name + " which would allow all ports ***"
    Write-Output $outputstr
    }
      $endpoints = Get-AzureEndpoint -VM $vm
    foreach($endpoint in $endpoints)
    {
    #Check if the local port is allowed
    $allowed = $allowedports.Contains($endpoint.LocalPort)

    $outputstr = "Found endpoint for VM " + $vm.Name + " for private port " + $endpoint.LocalPort + " (" + $endpoint.name + ")"

    if ($allowed)
    {
        Write-Output $outputstr
    }
    else
    {
        Write-Output $outputstr
        Write-Output "Removing endpoint"
        get-azurevm -ServiceName $vm.ServiceName -Name $vm.Name | Remove-AzureEndpoint -Name $endpoint.Name | Update-AzureVM
    }
    }
}

Below is an example execution where I modified the script to check for any endpoints that were not RDP or WS-Management.

Hide comments

Comments

  • Allowed HTML tags: <em> <strong> <blockquote> <br> <p>

Plain text

  • No HTML tags allowed.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.
Publish