Constrained Delegation with Hyper-V

Version 2

    What in the world is constrained delegation and why is it important in a Hyper-V environment?  Well, have you ever tried to configure an ISO file from a network share to a virtual machine and end up with an error when you tried to run that VM?  Most people answer “yes” to that question, and they frustratingly make a local copy of the ISO file and curse Microsoft for not supporting network ISO files.

     

    Actually, Microsoft fully supports network ISO file.  You just have to follow the rules of Kerberos.  In this case, the rule is known as Kerberos Constrained Delegation.

     

    In a multiple server environment, it is quite common to set up library servers to store commonly used resources.  A very common resource is an ISO file containing distribution media, such as the Microsoft Windows Server installation media.  Most of you know that with the later Microsoft operating system, you simply double-click on an ISO file and it is mounted as a DVD and is now available for your use.

     

    This works just fine when you are trying to use an ISO file for your own use.  You are using your identity and your privileges to access that.  But, what happens when you go into an environment such as Hyper-V?  When you are running Hyper-V, and you configure a virtual machine to use an ISO file that is stored on a library server, it is Hyper-V and not you, that is requesting to use that ISO.  By default, Windows security is set up to prevent a service (in this case Hyper-V) to act on the behalf of another user (you).  This protects against all sorts of malware that might try to break into a system across the network by using your credentials.

     

    What actually happens when you define the settings of a virtual machine to use an ISO file from a library share?  You are asking the Hyper-V service to access the ISO file.  But the Hyper-V service is local on the machine you are working on. It has no privilege to access the ISO on the library share.  As a result, even if you have full privileges on that ISO file, when you try to start the virtual machine, you will get an access violation error because the request to read the ISO file is coming from the Hyper-V service and not you.

     

    Earlier I mentioned a common resolution to this issue was to make a local copy of the ISO file for your use on the Hyper-V host.  In fact, if you use Microsoft System Center Virtual Machine Manager, this is a default behavior.  When you specify to create a VM and you specify an ISO to be assigned to that VM’s DVD drive, SCVMM will make a copy of the ISO file and store it with the VM.  The end result of this is that multiple copies of the ISO end up all over the organization.  If the contents of that ISO contain information that is updated on a regular basis, you now have to find all the occurrences of the old ISO and replace it with the new ISO.  Nobody wants to manage that sort of an environment.

     

    The simple way around this is configure Constrained Delegation.  As with anything like this, it is possible to configure this manually (http://technet.microsoft.com/en-us/library/cc720385(v=WS.10).aspx), but in cloud environments, it is a better practice to build some automation for this.  The script in this article will automatically configure constrained delegation.

     

    It is a recommended practice to enable constrained delegation for each of your Hyper-V hosts. It makes life a lot easier.

     

    As a sample script, it configures constrained delegation and live migration.  I added the live migration capability because is another aspect of Hyper-V that you will likely be configuring on every host.  This capability is works with Hyper-V 2012 and later.  Though constrained delegation has been around since Windows Server 2003, this script does not work with Hyper-V 2008 or 2008 R2; new capabilities were added to PowerShell in 2012.

     

    This script has some requirements.  First, you need to define your Active Directory domain path.  Additionally, it assumes that you have created an organizational unit in Active Directory to contain your Hyper-V hosts.  The script is designed to handle two different tables of servers.  The first table, $hvServers,  contains the Hyper-V servers to set up for live migration and which need constrained delegation.  The second table, $smbServers, contains the names of the library servers.  These values should be tailored to your environment.

     

    Since this script is accessing Active Directory, you need the Active Directory PowerShell module installed on the system from which you run this.  Therefore, it can be run from an Active Directory domain controller, or a system that has had the RSAT Active Directory 2012 PowerShell module installed on it.

     

     

    $adPath = 'DC=VSPEX,DC=com'

    $hvServersGroup = "HyperV-Hosts"

     

    $hvServers = @()

    $hvServers +=, 'HyperV-01'

     

    $smbServers = @()

    $smbServers +=, 'Library-01'

    $smbServers +=, 'Library-02'

     

    $enableLiveMigration =
    $true

     

    $errTag = $false

     

    #Validate that all servers are in Active Directory

    Foreach ($server in $hvServers)

    {

        $error.Clear()

        $trash = Get-ADComputer $server

       If ($error.length -ge 1)

       {

           Write-Host "Server $server is not found in Active Directory"

          $errTag = $true

       }

    }

     

    Foreach ($server in $smbServers)

    {

        $error.Clear()

       $trash = Get-ADComputer $server

       If ($error.length -ge 1)

       {

           Write-Host "Server $server is not found in Active Directory"

           $errTag = $true

       }

    }

     

    If ($errTag) {Write-Host -ForegroundColor Red "Errors detected. Run aborted."; Exit}

     

    # Find if HyperV Server group exists in AD.  If not, add it.

    $tmp1 = Get-AdGroup -Filter {Name -eq $hvServersGroup}

    If ($tmp1 -eq $null)

    {

        $error.Clear()

       New-ADGroup -Name $hvServersGroup -DisplayName $hvServersGroup `

         -GroupScope Global -GroupCategory Security -Path "CN=Users,$adPath" `

         -Description "Hyper-V Servers"

       Write-Host "$hvServersGroup did not exist in Active Directory; it was added"

       If ($error.length -ge 0)

       {

           Write-Host -ForegroundColor Red "Error adding AD group $hvServersGroup -
    aborting"

           Exit

       }

    }

     

    # Add Hyper-V servers to group if not already in Hyper-V Server group

    $errTag = $false

    Foreach ($server in $hvServers)

    {

        $hvServersAD = @(Get-ADGroupMember -Identity $hvServersGroup)

       If ($hvServersAD.count -lt 1)

       {

           Add-ADGroupMember -Identity $hvServersGroup -Members (Get-ADComputer -Identity
    $server)

       }

       Else

       {

           For ($hvCnt = 0; $hvCnt -lt $hvServersAD.count; $hvCnt++)

           {

               $error.Clear()

               If ($server -eq $hvServersAD[$hvCnt])

               {

                   Break

               }

               Else

               {

                   Add-ADGroupMember -Identity $hvServersGroup -Members (Get-ADComputer
    -Identity $server)

               }

               If ($error.length -ge 1)

               {

                   Write-Host -ForegroundColor Red "Error adding $server to AD Group $hvServersGroup"

                   $errTag = $true

               }

            }

        }

    }

     

    If ($errTag -eq $true)

    {

        Write-Host -ForegroundColor Red "Errors detected adding members to group $hvServersGroup -
    aborting"

        Exit

    }

     

    Foreach ($smbServer in $smbServers)

    {

        $smbServerAD = Get-ADComputer $smbServer

        $AllowedToDelegateToSMB = @(

            ("cifs/"+$smbServerAD.Name),

            ("cifs/"+$smbServerAD.DNSHostName))

     

        $hvServersAD = Get-ADGroupMember -Identity $hvServersGroup

        For ($srvCnt = 0; $srvCnt -lt $hvServersAD.count; $srvCnt++)

        {

            $AllowedToDelegateTo = $AllowedToDelegateToSMB

            If ($EnableLiveMigration)

            {

                For ($delCNT = 0; $delCNT -lt $hvServersAD.count; $delCNT++)

                {

                    If ($delCNT -ne $srvCnt)

                    {

                        $delegationServer = $HvServersAD[$delCNT] | Get-ADComputer

                        $AllowedToDelegateTo += @(

                            ("Microsoft Virtual System Migration Service/"+$delegationServer.Name),

                            ("Microsoft Virtual System Migration Service/"+$delegationServer.DNSHostName))      

                    }

                }

            }

            ($hvServersAD[$srvCnt] | Get-ADComputer) | Set-ADObject -Add @{"msDS-AllowedToDelegateTo"=$AllowedToDelegateTo}

          }

    }