Zduplikowane rekordy SRV kontrolerów domeny
January 14, 2020 ‐ 7 minut(a) czytania
W Windows Server 2016 i nowszych usługa serwera nazw (DNS) wspiera rejestrację rekordów SRV uwzględniając wielkość liter w nazwie hosta (case-sensitive). O czym wiele osób przekonało się wkrótce po wprowadzeniu nowej wersji systemu operacyjnego do środowiska Active Directory.
Kontrolery domeny działające pod kontrolą systemu Windows Server 2016 lub nowszych, których nazwy zawierają jedną lub więcej wielkich liter w nazwie, mogą rejestrować rekordy SRV zawierające tylko małe litery, gdy usługa serwera nazw, z której korzystają jest uruchomiona w systemie Windows Server 2012 R2 lub starszym, a dodatkowo rekordy zawierające mieszane lub wyłącznie wielkie literami, gdy serwer nazw jest uruchomiony na Windows Server 2016 lub nowszym.
Powodowane jest to obsługą rozróżniania wielkości liter w przesłanym w żądaniu rejestracji informacjach RDATA do serwera DNS.
Czy zduplikowane rekordy mogą być szkodliwe?
W większości wypadków nie będzie to miało większego wpływu na dostępność usługi ani wydajność kontrolerów domeny. Niemniej te kontrolery domeny, które zarejestrują lokatory usług podwójnie będą występować dwukrotnie częściej na liście serwerów przy zapytania klientów (więcej o mechniźmie DC Locator). To z kolei może oznaczać nadmierną utylizację serwerów z powielonymi rekordami, nierównomierny rozkład klientów oraz generować opóźnia w obsłudze żądań klientów domeny.
Poniższy zrzut ekranu prezentuje zduplikowane rekordy SRV _kerberos zarejestrowane przez kontroler domeny o nazwie PFE-DC1 (zawiera wielkie litery).
Kolejny przykład zawiera rekordy SRV _ldap zarejestrowane przez ten sam kontroler domeny.
Przyznacie, że sprawa wygląda nieciekawie? Co w tej sytuacji zrobić?
Powyższe zachowanie serwera DNS, na którym rejestrowany lub odświeżany jest rekord jest poprawnym zachowaniem dla Windows Server 2016 i nowszych. Zatem jest to “problem”, a nie problem. Klienci dysponujący wsparciem mogą otworzyć zgłoszenie i otrzymają prywatną poprawkę (private fix).
Docelowo, w marcowym zbiorczym pakiecie poprawek oraz towarzyszącym mu wydaniu szablonów administracyjnych zasad grup znajdzie się nowe ustawienie, które pozwoli zablokować rejestrację zdublowanych rekordów.
Nowe ustawienie dostępne będzie w następującej ścieżce:
Computer Configuration\Policies\Administrative Templates\System\Net Logon\DC Locator DNS Records\Use lowercase DNS host names when registering domain controller SRV records
I będzie stosowane domyślnie (czyli nawet wówczas, gdy nie będzie skonfigurowane (Not configured)).
Do tego czasu zalecana jest zmiana nazwy kontrolerów domeny, na taką która zawierać będzie tylko małe litery (tak, wspieramy to, choć w niektórych wypadkach należy pamiętać o dodatkowych czynnościach). Przy okazji warto zaznajomić się z dokumentacją, w pierwszej kolejności polecam artykuł Computer Naming, a następnie Naming conventions in Active Directory.
A co z pozostałościami? Jeśli zgodnie z rekomendacjami stosujecie automatyczne czyszczenie stref z przestarzałych rekordów (scavenging), rekordy zostaną usunięte automatycznie.
Jeśli nie stosujecie scavenging lub nie chcecie czekać na wyniki jego działania, możecie usunąć pozostałości samodzielnie. W dalszej części opiszę jak skryptowo wylistować oraz usunąć rzeczone zduplikowane rekordy.
Jak sprawdzić jakie oraz ile rekordów SRV w mojej domenie zarejestrowano dla kontrolerów domeny z nazwami zawierającymi wielkie litery?
Na potrzeby tego ćwiczenia przygotowałem skrypt PowerShell, który pozwala zidentyfikować rekordy SRV w strefie funkcjonalnej Active Directory (_msdcs). Skrypt można pobrać z mojego repozytorium lub skopiować poniżej.
<# .SYNOPSIS Get-UppercaseDomainSrvRecords_v1.ps1 - Finds SRV records with upper-case letters in name registered under _msdcs. .DESCRIPTION This script will locate your Active Directory integrated DNS servers and find SRV records with upper-case letters in name registered under _msdcs. .OUTPUTS Object, allows sorting, filtering and pipe output date. .COPYRIGHT Grzegorz Glogowski - Microsoft Corporation .NOTES This script is provided "AS IS" with no warranties and confers no rights. Change Log V1.00, 20200112 - Initial version #> #Clear screen, useful when run in ISE cls <# #Set up domain specification, borrowed from PyroTek3 #https://github.com/PyroTek3/PowerShell-AD-Recon/blob/master/Find-PSServiceAccounts if(-not $Domain) { $ADDomainInfo = [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain() $Domain = $ADDomainInfo.Name } #> #Get Active Directory forest and domain information $forest = Get-ADForest $domain = Get-ADDomain #Find all DCs/DNS servers $dns = (Resolve-DnsName $($domain.DNSRoot) -type NS | ? {$_.type -eq "A"}).Name <#Alternative way to get DNS servers (LDAP query) - Windows Server 2008 R2 and older #Find DNS servers #https://social.technet.microsoft.com/wiki/contents/articles/18996.active-directory-powershell-script-to-list-all-spns-used.aspx $search = New-Object DirectoryServices.DirectorySearcher([ADSI]"") $search.filter = "(servicePrincipalName=DNS*)" $searchbase = "OU=Domain Controllers,"+$($domain.DistinguishedName) $results = $search.Findall() | ?{ $_.path -like $searchbase } $results = $search.Findall() $dns = $results.Properties.dnshostname #> #$dcs = $domain.ReplicaDirectoryServers $rootzone = $domain.DNSRoot $msdcszone = "_msdcs." + $rootzone #Get filtered set of SRV records from _msdcs $dnsrecords = Get-DnsServerResourceRecord -ZoneName $msdcszone | Where-Object {$_.RecordType -ne "NS" -and $_.RecordType -ne "SOA" -and $_.RecordType -ne "CNAME" -and $_.RecordType -ne "A" } #Get filtered set of SRV records from _msdcs with upper-case letters #$dnsrecords = Get-DnsServerResourceRecord -ZoneName $msdcszone | Where-Object {$_.RecordType -ne "NS" -and $_.RecordType -ne "SOA" -and $_.RecordType -ne "CNAME" -and $_.RecordType -ne "A" -and $_.RecordData.DomainName -cmatch '[A-Z]' } #Initialize the array $OutputObj = @() ForEach ($rr in $dnsrecords) { $name = $rr.HostName $type = $rr.RecordType $ttl = $rr.TimeToLive $created = $rr.Timestamp #$data = $rr.RecordData.DomainName #$data = $rr.RecordData | select DomainName -ExpandProperty DomainName | Out-String $data = $rr.RecordData | select DomainName -ExpandProperty DomainName $uppercase = $data -cmatch '[A-Z]' $OutputObj += New-Object -TypeName PSobject -Property @{ Name = $name Type = $type TTL = $ttl Created = $created Data = $data CaseSensitive = $uppercase } } #Get Active Directory sites $sites = ([System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest().Sites).Name #Divide output into generic and site-specific SRV records with upper-case letters foreach ($site in $sites) { $currentpath = "_tcp." + $($site) + "._sites.dc." + $($msdcszone) -replace " ","" #Write-Host "Records with UPPER-CASE in: " $currentpath.ToLower() "`r`n" -ForegroundColor DarkYellow Write-Host "Records with UPPER-CASE in" $site "site container `r`n" -ForegroundColor DarkYellow $OutputObj | where {$_.Name -match $site -and $_.Case -eq $true} | select Name,Data | Format-Table -AutoSize } Write-Host "Records with UPPER-CASE in generic containers `r`n" -ForegroundColor DarkYellow $OutputObj | where {$_.Name -notmatch "._Sites." -and $_.Case -eq $true}| select Name,Data | Format-Table -AutoSize #EOF
Powyższy skrypt automatycznie wyświetla wyniki z podziałem na kontenery, w których znajdują się wykryte rekordy z wielkimi literami w nazwie.
Jeśli na wynika potrzebujecie wykonać sortowanie, filtrowanie lub chcecie je przesłać na wejście kolejnego polecenia, należy użyć następującego kodu.
<# .SYNOPSIS Get-UppercaseDomainSrvRecords_v2.ps1 - Finds SRV records with upper-case letters in name registered under _msdcs. .DESCRIPTION This script will locate your Active Directory integrated DNS servers and find SRV records with upper-case letters in name registered under _msdcs. .OUTPUTS Object, allows sorting, filtering and pipe output date. .COPYRIGHT Grzegorz Glogowski - Microsoft Corporation .NOTES This script is provided "AS IS" with no warranties and confers no rights. Change Log V1.00, 20200112 - Initial version #> #Clear screen, useful when run in ISE #cls <# #Set up domain specification, borrowed from PyroTek3 #https://github.com/PyroTek3/PowerShell-AD-Recon/blob/master/Find-PSServiceAccounts if(-not $Domain) { $ADDomainInfo = [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain() $Domain = $ADDomainInfo.Name } #> #Get Active Directory forest and domain information $forest = Get-ADForest $domain = Get-ADDomain #Find all DCs/DNS servers $dns = (Resolve-DnsName $($domain.DNSRoot) -type NS | ? {$_.type -eq "A"}).Name <#Alternative way to get DNS servers (LDAP query) - Windows Server 2008 R2 and older #Find DNS servers #https://social.technet.microsoft.com/wiki/contents/articles/18996.active-directory-powershell-script-to-list-all-spns-used.aspx $search = New-Object DirectoryServices.DirectorySearcher([ADSI]"") $search.filter = "(servicePrincipalName=DNS*)" $searchbase = "OU=Domain Controllers,"+$($domain.DistinguishedName) $results = $search.Findall() | ?{ $_.path -like $searchbase } $results = $search.Findall() $dns = $results.Properties.dnshostname #> #$dcs = $domain.ReplicaDirectoryServers $rootzone = $domain.DNSRoot $msdcszone = "_msdcs." + $rootzone #Get filtered set of SRV records from _msdcs $dnsrecords = Get-DnsServerResourceRecord -ZoneName $msdcszone | Where-Object {$_.RecordType -ne "NS" -and $_.RecordType -ne "SOA" -and $_.RecordType -ne "CNAME" -and $_.RecordType -ne "A" } #Get filtered set of SRV records from _msdcs with upper-case letters #$dnsrecords = Get-DnsServerResourceRecord -ZoneName $msdcszone | Where-Object {$_.RecordType -ne "NS" -and $_.RecordType -ne "SOA" -and $_.RecordType -ne "CNAME" -and $_.RecordType -ne "A" -and $_.RecordData.DomainName -cmatch '[A-Z]' } #Initialize the array $OutputObj = @() ForEach ($rr in $dnsrecords) { $name = $rr.HostName $type = $rr.RecordType $ttl = $rr.TimeToLive $created = $rr.Timestamp #$data = $rr.RecordData.DomainName #$data = $rr.RecordData | select DomainName -ExpandProperty DomainName | Out-String $data = $rr.RecordData | select DomainName -ExpandProperty DomainName $uppercase = $data -cmatch '[A-Z]' $OutputObj += New-Object -TypeName PSobject -Property @{ Name = $name Type = $type TTL = $ttl Created = $created Data = $data CaseSensitive = $uppercase } } #Get Active Directory sites $sites = ([System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest().Sites).Name #Divide output into generic and site-specific SRV records with upper-case letters foreach ($site in $sites) { $currentpath = "_tcp." + $($site) + "._sites.dc." + $($msdcszone) -replace " ","" #Write-Host "Records with UPPER-CASE in: " $currentpath.ToLower() "`r`n" -ForegroundColor Yellow Write-Host "Records with UPPER-CASE in" $site "site container `r`n" -ForegroundColor Yellow $OutputObj | where {$_.Name -match $site -and $_.CaseSensitive -eq $true} | select Name,Data | Format-Table -AutoSize } Write-Host "Records with UPPER-CASE in generic containers `r`n" -ForegroundColor Yellow $OutputObj | where {$_.Name -notmatch "._Sites." -and $_.CaseSensitive -eq $true}| select Name,Data | Format-Table -AutoSize #EOF
Wówczas, sami zdecydujecie o tym, co dalej zrobić z wykrytymi rekordami.
Uwaga: Do poprawnego działania Active Directory niezbędne są odpowiednie strefy oraz rekordy DNS. Zalecam dużą dozę ostrożności i proszę nie róbcie niczego pochopnie, aby nie musieć naprawiać lub odzyskiwać środowiska!
Twoje okno na chmurę