Edit

Share via


Configure Bastion for Kerberos authentication using the Azure portal

This article shows you how to configure Azure Bastion to use Kerberos authentication. Kerberos authentication can be used with Basic SKU tier or higher for Azure Bastion. For more information about Kerberos authentication, see the Kerberos authentication overview. For more information about Azure Bastion, see What is Azure Bastion?

Considerations

  • The Kerberos setting for Azure Bastion can be configured in the Azure portal only and not with native client.
  • VMs migrated from on-premises to Azure aren't currently supported for Kerberos.
  • Cross-realm authentication isn't currently supported for Kerberos.
  • The Domain controller must be an Azure Hosted VM within the same virtual network that bastion is deployed.
  • Changes to DNS servers don't propagate to Bastion. Bastion redeployment is needed for DNS info to properly propagate. After making any changes to DNS server, you'll need to delete and re-create the Bastion resource.
  • If more DCs (___domain controllers) are added, Bastion will only recognize the first DC.
  • If more DCs are added for different domains, the added domains can't successfully authenticate with Kerberos.

Prerequisites

  • An Azure account with an active subscription. If you don't have one, create one for free. To be able to connect to a VM through your browser using Bastion, you must be able to sign in to the Azure portal.
  • Ensure that the Network Security Groups (NSGs) associated with both Azure Bastion and Kerberos-enabled systems (such as ___domain controllers) allow both inbound and outbound traffic on the following ports: 53, 88, 389, 464 and 636. These ports are required for proper DNS resolution, Kerberos authentication, and Active Directory communication. For further reference, see the Microsoft documentation on configuring firewalls for Active Directory domains and trusts: Configure Windows Firewall to allow Active Directory domains and trusts
  • An Azure virtual network. For steps to create a virtual network, see Quickstart: Create a virtual network.

Update VNet DNS servers

In this section, the following steps help you update your virtual network to specify custom DNS settings.

  1. Sign in to the Azure portal.
  2. Go to the virtual network for which you want to deploy the Bastion resources.
  3. Go to the DNS servers page for your virtual network and select Custom. Add the IP address of your Azure-hosted ___domain controller and Save.

Deploy Bastion

  1. Begin configuring your bastion deployment using the steps in Tutorial: Deploy Bastion using manual configuration settings. Configure the settings on the Basics tab. Then, at the top of the page, click Advanced to go to the Advanced tab.
  2. On the Advanced tab, select Kerberos.
  3. At the bottom of the page, select Review + create, then Create to deploy Bastion to your virtual network.
  4. Once the deployment completes, you can use it to sign in to any reachable Windows VMs joined to the custom DNS you specified in the earlier steps.

To modify an existing Bastion deployment

In this section, the following steps help you modify your virtual network and existing Bastion deployment for Kerberos authentication.

  1. Update the DNS settings for your virtual network.
  2. Go to the portal page for your Bastion deployment and select Configuration.
  3. On the Configuration page, select Kerberos authentication, then select Apply.
  4. Bastion updates with the new configuration settings.

To verify Bastion is using Kerberos

Note

You must use the User Principal Name (UPN) to sign in using Kerberos.

Once you have enabled Kerberos on your Bastion resource, you can verify that it's actually using Kerberos for authentication to the target ___domain-joined VM.

  1. Sign into the target VM (either via Bastion or not). Search for "Edit Group Policy" from the taskbar and open the Local Group Policy Editor.

  2. Select Computer Configuration > Windows Settings > Security Settings > Local Policies > Security Options.

  3. Find the policy Networking security: Restrict NTLM: Incoming NTLM Traffic and set it to Deny all ___domain accounts. Because Bastion uses NTLM for authentication when Kerberos is disabled, this setting ensures that NTLM-based authentication is unsuccessful for future sign-in attempts on the VM.

  4. End the VM session.

  5. Connect to the target VM again using Bastion. Sign-in should succeed, indicating that Bastion used Kerberos (and not NTLM) for authentication.

    Note

    To prevent failback to NTLM, make sure you follow the preceding steps. Enabling Kerberos (without following the procedure) won't prevent failback to NTLM.

Quickstart: Set up Bastion with Kerberos - Resource Manager template

Review the template

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "___location": {
      "defaultValue": "[resourceGroup().___location]",
      "type": "string"
    },
    "defaultNsgName": {
      "type": "string",
      "defaultValue": "Default-nsg"
    },
    "VnetName": {
      "type": "string",
      "defaultValue": "myVnet"
    },
    "ClientVMName": {
      "defaultValue": "Client-vm",
      "type": "string"
    },
    "ServerVMName": {
      "defaultValue": "Server-vm",
      "type": "string"
    },
    "vmsize": {
      "defaultValue": "Standard_DS1_v2",
      "type": "string",
      "metadata": {
        "description": "VM SKU to deploy"
      }
    },
    "ServerVMUsername": {
      "type": "string",
      "defaultValue": "serveruser",
      "metadata": {
        "description": "Admin username on all VMs."
      }
    },
    "ServerVMPassword": {
      "type": "securestring",
      "metadata": {
        "description": "Admin password on all VMs."
      }
    },
    "SafeModeAdministratorPassword": {
      "type": "securestring",
      "metadata": {
        "description": "See https://learn.microsoft.com/en-us/powershell/module/addsdeployment/install-addsdomaincontroller?view=windowsserver2022-ps#-safemodeadministratorpassword"
      }
    },
    "ClientVMUsername": {
      "type": "string",
      "defaultValue": "clientuser",
      "metadata": {
        "description": "username on ClientVM."
      }
    },
    "ClientVMPassword": {
      "type": "securestring",
      "metadata": {
        "description": "password on ClientVM."
      }
    },
    "ServerVmImage": {
      "type": "object",
      "defaultValue": {
        "offer": "WindowsServer",
        "publisher": "MicrosoftWindowsServer",
        "sku": "2019-Datacenter",
        "version": "latest"
      }
    },
    "ClientVmImage": {
      "type": "object",
      "defaultValue": {
        "offer": "Windows",
        "publisher": "microsoftvisualstudio",
        "sku": "Windows-10-N-x64",
        "version": "latest"
      }
    },
    "publicIPAllocationMethod": {
      "type": "string",
      "defaultValue": "Static"
    },
    "BastionName": {
      "defaultValue": "Bastion",
      "type": "string"
    },
    "BastionPublicIPName": {
        "defaultValue": "Bastion-ip",
        "type": "string"
    }
  },
  "variables": {
    "DefaultSubnetId": "[concat(resourceId('Microsoft.Network/virtualNetworks', parameters('VnetName')), '/subnets/default')]",
    "ClientVMSubnetId": "[concat(resourceId('Microsoft.Network/virtualNetworks', parameters('VnetName')), '/subnets/clientvm-subnet')]",
    "DNSServerIpAddress": "10.16.0.4",
    "ClientVMPrivateIpAddress": "10.16.1.4"
  },
  "resources": [
    {
      "apiVersion": "2020-03-01",
      "name": "[parameters('VnetName')]",
      "type": "Microsoft.Network/virtualNetworks",
      "___location": "[parameters('___location')]",
      "properties": {
        "dhcpOptions": {
          "dnsServers": [ "[variables('DNSServerIpAddress')]" ]
        },
        "subnets": [
          {
            "name": "default",
            "properties": {
              "addressPrefix": "10.16.0.0/24"
            }
          },
          {
            "name": "clientvm-subnet",
            "properties": {
              "addressPrefix": "10.16.1.0/24"
            }
          },
          {
            "name": "AzureBastionSubnet",
            "properties": {
              "addressPrefix": "10.16.2.0/24"
            }
          }
        ],
        "addressSpace": {
          "addressPrefixes": [
            "10.16.0.0/16"
          ]
        }
      }
    },
    {
      "type": "Microsoft.Network/networkInterfaces",
      "apiVersion": "2018-10-01",
      "name": "[concat(parameters('ServerVMName'), 'Nic')]",
      "___location": "[parameters('___location')]",
      "dependsOn": [
        "[concat('Microsoft.Network/virtualNetworks/', parameters('VnetName'))]"
      ],
      "properties": {
        "ipConfigurations": [
          {
            "name": "[concat(parameters('ServerVMName'), 'NicIpConfig')]",
            "properties": {
              "privateIPAllocationMethod": "Static",
              "privateIPAddress": "[variables('DNSServerIpAddress')]",
              "subnet": {
                "id": "[variables('DefaultSubnetId')]"
              }
            }
          }
        ]
      }
    },
    {
      "type": "Microsoft.Compute/virtualMachines",
      "apiVersion": "2020-06-01",
      "name": "[parameters('ServerVMName')]",
      "___location": "[parameters('___location')]",
      "dependsOn": [
        "[concat('Microsoft.Network/networkInterfaces/', parameters('ServerVMName'), 'Nic')]"
      ],
      "properties": {
        "hardwareProfile": {
          "vmSize": "[parameters('vmSize')]"
        },
        "osProfile": {
          "AdminUsername": "[parameters('ServerVMUsername')]",
          "AdminPassword": "[parameters('ServerVMPassword')]",
          "computerName": "[parameters('ServerVMName')]"
        },
        "storageProfile": {
          "imageReference": "[parameters('ServerVmImage')]",
          "osDisk": {
            "createOption": "FromImage",
            "managedDisk": {
              "storageAccountType": "Standard_LRS"
            }
          }
        },
        "networkProfile": {
          "networkInterfaces": [
            {
              "id": "[ResourceId('Microsoft.Network/networkInterfaces/', concat(parameters('ServerVMName'), 'Nic'))]"
            }
          ]
        }
      }
    },
    {
      "type": "Microsoft.Compute/virtualMachines/extensions",
      "apiVersion": "2021-04-01",
      "name": "[concat(parameters('ServerVMName'),'/', 'PromoteToDomainController')]",
      "___location": "[parameters('___location')]",
      "dependsOn": [
        "[concat('Microsoft.Compute/virtualMachines/',parameters('ServerVMName'))]"
      ],
      "properties": {
        "publisher": "Microsoft.Compute",
        "type": "CustomScriptExtension",
        "typeHandlerVersion": "1.7",
        "autoUpgradeMinorVersion": true,
        "settings": {
          "commandToExecute": "[concat('powershell.exe -Command \"Install-windowsfeature AD-___domain-services; Import-Module ADDSDeployment;$Secure_String_Pwd = ConvertTo-SecureString ',parameters('SafeModeAdministratorPassword'),' -AsPlainText -Force; Install-ADDSForest -DomainName \"bastionkrb.test\" -SafeModeAdministratorPassword $Secure_String_Pwd -Force:$true')]"
          }
      }
    },
    {
      "type": "Microsoft.Network/networkInterfaces",
      "apiVersion": "2018-10-01",
      "name": "[concat(parameters('ClientVMName'), 'Nic')]",
      "___location": "[parameters('___location')]",
      "dependsOn": [
        "[concat('Microsoft.Network/virtualNetworks/', parameters('VnetName'))]",
        "[concat('Microsoft.Compute/virtualMachines/', parameters('ServerVMName'))]"
      ],
      "properties": {
        "ipConfigurations": [
          {
            "name": "[concat(parameters('ClientVMName'), 'NicIpConfig')]",
            "properties": {
              "privateIPAllocationMethod": "Static",
              "privateIPAddress": "[variables('ClientVMPrivateIpAddress')]",
              "subnet": {
                "id": "[variables('ClientVMSubnetId')]"
              }
            }
          }
        ]
      }
    },
    {
      "type": "Microsoft.Compute/virtualMachines",
      "apiVersion": "2020-06-01",
      "name": "[parameters('ClientVMName')]",
      "___location": "[parameters('___location')]",
      "dependsOn": [
        "[concat('Microsoft.Network/networkInterfaces/', parameters('ClientVMName'), 'Nic')]"
      ],
      "properties": {
        "hardwareProfile": {
          "vmSize": "[parameters('vmSize')]"
        },
        "osProfile": {
          "AdminUsername": "[parameters('ClientVMUsername')]",
          "AdminPassword": "[parameters('ClientVMPassword')]",
          "computerName": "[parameters('ClientVMName')]"
        },
        "storageProfile": {
          "imageReference": "[parameters('ClientVmImage')]",
          "osDisk": {
            "createOption": "FromImage",
            "managedDisk": {
              "storageAccountType": "Standard_LRS"
            }
          }
        },
        "networkProfile": {
          "networkInterfaces": [
            {
              "id": "[ResourceId('Microsoft.Network/networkInterfaces/', concat(parameters('ClientVMName'), 'Nic'))]"
            }
          ]
        }
      }
    },
    {
      "type": "Microsoft.Compute/virtualMachines/extensions",
      "apiVersion": "2021-04-01",
      "name": "[concat(parameters('ClientVMName'),'/', 'DomainJoin')]",
      "___location": "[parameters('___location')]",
      "dependsOn": [
        "[concat('Microsoft.Compute/virtualMachines/',parameters('ClientVMName'))]",
        "[concat('Microsoft.Compute/virtualMachines/', parameters('ServerVMName'),'/extensions/', 'PromoteToDomainController')]",
        "[concat('Microsoft.Network/bastionHosts/', parameters('BastionName'))]"
      ],
      "properties": {
        "publisher": "Microsoft.Compute",
        "type": "CustomScriptExtension",
        "typeHandlerVersion": "1.7",
        "autoUpgradeMinorVersion": true,
        "settings": {
          "commandToExecute": "[concat('powershell.exe -Command Set-ItemProperty -Path HKLM:\\SYSTEM\\CurrentControlSet\\Control\\Lsa\\MSV1_0\\ -Name RestrictReceivingNTLMTraffic -Value 1; $Pass= ConvertTo-SecureString -String ',parameters('ServerVMPassword'),' -AsPlainText -Force; $Credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList \"AD\\serveruser\", $Pass; do { try { $joined = add-computer -computername Client-vm -domainname bastionkrb.test –credential $Credential -passthru -restart –force; } catch {}} while ($joined.HasSucceeded -ne $true)')]"
          }
      }
    },
    {
      "apiVersion": "2020-11-01",
      "type": "Microsoft.Network/publicIPAddresses",
      "name": "[parameters('BastionPublicIPName')]",
      "___location": "[resourceGroup().___location]",
      "sku": {
        "name": "Standard"
      },
      "properties": {
        "publicIPAllocationMethod": "Static"
      },
      "tags": {}
    },
    {
        "type": "Microsoft.Network/bastionHosts",
        "apiVersion": "2020-11-01",
        "name": "[parameters('BastionName')]",
        "___location": "[resourceGroup().___location]",
        "dependsOn": [
            "[concat('Microsoft.Network/virtualNetworks/', parameters('VnetName'))]",
            "[concat('Microsoft.Network/publicIpAddresses/', parameters('BastionPublicIPName'))]"
        ],
        "sku": {
            "name": "Standard"
        },
        "properties": {
            "enableKerberos": "true",
            "ipConfigurations": [
                {
                    "name": "IpConf",
                    "properties": {
                        "privateIPAllocationMethod": "Dynamic",
                        "publicIPAddress": {
                            "id": "[resourceId('Microsoft.Network/publicIpAddresses', parameters('BastionPublicIPName'))]"
                        },
                        "subnet": {
                            "id": "[concat(resourceId('Microsoft.Network/virtualNetworks', parameters('VnetName')), '/subnets/AzureBastionSubnet')]"
                        }
                    }
                }
            ]
        }
    }
  ]
}

The following resources have been defined in the template:

  • Deploys the following Azure resources:

  • Have the DNS Server of the virtual network point to the private IP address of the ServerVM (___domain controller).

  • Runs a Custom Script Extension on the ServerVM to promote it to a ___domain controller with ___domain name: bastionkrb.test.

  • Runs a Custom Script Extension on the ClientVM to have it:

    • Restrict NTLM: Incoming NTLM traffic = Deny all ___domain accounts (this is to ensure Kerberos is used for authentication).
    • Domain-join the bastionkrb.test ___domain.

Deploy the template

To set up Kerberos, deploy the preceding ARM template by running the following PowerShell cmd:

New-AzResourceGroupDeployment -ResourceGroupName <your-rg-name> -TemplateFile "<path-to-template>\KerberosDeployment.json"`

Review deployed resources

Now, sign in to ClientVM using Bastion with Kerberos authentication:

  • credentials: username = serveruser@bastionkrb.test and password = <password-entered-during-deployment>.

Next steps

For more information about Azure Bastion, see What is Azure Bastion?