ActiveDirectory/MixedDomainController

Материал из ALT Linux Wiki

Использование одновременно доменных контроллеров на ALT Domain 11 (Samba DC) и Windows Server 2022 DC.

ВСЕ ДЕЙСТВИЯ ВЫ ДЕЛАЕТЕ НА СВОЙ СТРАХ И РИСК. СДЕЛАЙТЕ БЕКАПЫ, ИМЕЙТЕ ПЛАН ВОССТАНОВЛЕНИЯ!!!

Исходные данные

Есть работающая AD на базе двух DC Windows Server 2022 с именами DC01 и DC02.

Читаем официальную документацию по включению ALT Server и ALT Domain как дополнительного DC к существующей AD: [[1]]

В случае уровней леса и домена 2016 итоговая команда включения ALTDC в домен как дополнительный DC следующая:

samba-tool domain join testdomain.local DC -UTESTDOMAIN\\Administrator --realm=testdomain.local --dns-backend=SAMBA_INTERNAL --option="dns forwarder=77.88.8.8" --option="ad dc functional level = 2016" -d 5

После включения в домен службу Samba запускаем, в AD DC на одном из Windows DC запускаем ADSS (Sites and Services), запускаем KCC (построение топологии репликации), убеждаемся, что появляется связи репликации между DC01/DC02 и ALTDC.

Далее с помощью команды: samba-tool drs showrepl проверяем работу и успешность репликации на ALT Linux:

==== INBOUND NEIGHBORS ====
DC=testdomain,DC=local
       Default-First-Site-Name\DC02 via RPC
               DSA object GUID: b211e5cd-d457-4210-ac87-6c25fa2859e2
               Last attempt @ Thu Sep 25 15:04:53 2025 +05 was successful
               0 consecutive failure(s).
               Last success @ Thu Sep 25 15:04:53 2025 +05

DC=testdomain,DC=local
       Default-First-Site-Name\DC01 via RPC
               DSA object GUID: 92e9a947-d2a9-4b89-b90f-16a2148310fe
               Last attempt @ Thu Sep 25 15:04:53 2025 +05 was successful
               0 consecutive failure(s).
               Last success @ Thu Sep 25 15:04:53 2025 +05

CN=Schema,CN=Configuration,DC=testdomain,DC=local
       Default-First-Site-Name\DC02 via RPC
               DSA object GUID: b211e5cd-d457-4210-ac87-6c25fa2859e2
               Last attempt @ Thu Sep 25 15:01:14 2025 +05 was successful
               0 consecutive failure(s).
               Last success @ Thu Sep 25 15:01:14 2025 +05

CN=Schema,CN=Configuration,DC=testdomain,DC=local
       Default-First-Site-Name\DC01 via RPC
               DSA object GUID: 92e9a947-d2a9-4b89-b90f-16a2148310fe
               Last attempt @ Thu Sep 25 15:01:14 2025 +05 was successful
               0 consecutive failure(s).
               Last success @ Thu Sep 25 15:01:14 2025 +05

CN=Configuration,DC=testdomain,DC=local
       Default-First-Site-Name\DC02 via RPC
               DSA object GUID: b211e5cd-d457-4210-ac87-6c25fa2859e2
               Last attempt @ Thu Sep 25 15:01:14 2025 +05 was successful
               0 consecutive failure(s).
               Last success @ Thu Sep 25 15:01:14 2025 +05

CN=Configuration,DC=testdomain,DC=local
       Default-First-Site-Name\DC01 via RPC
               DSA object GUID: 92e9a947-d2a9-4b89-b90f-16a2148310fe
               Last attempt @ Thu Sep 25 15:01:14 2025 +05 was successful
               0 consecutive failure(s).
               Last success @ Thu Sep 25 15:01:14 2025 +05

DC=ForestDnsZones,DC=testdomain,DC=local
       Default-First-Site-Name\DC02 via RPC
               DSA object GUID: b211e5cd-d457-4210-ac87-6c25fa2859e2
               Last attempt @ Thu Sep 25 15:01:14 2025 +05 was successful
               0 consecutive failure(s).
               Last success @ Thu Sep 25 15:01:14 2025 +05

DC=ForestDnsZones,DC=testdomain,DC=local
       Default-First-Site-Name\DC01 via RPC
               DSA object GUID: 92e9a947-d2a9-4b89-b90f-16a2148310fe
               Last attempt @ Thu Sep 25 15:01:14 2025 +05 was successful
               0 consecutive failure(s).
               Last success @ Thu Sep 25 15:01:14 2025 +05

DC=DomainDnsZones,DC=testdomain,DC=local
       Default-First-Site-Name\DC02 via RPC
               DSA object GUID: b211e5cd-d457-4210-ac87-6c25fa2859e2
               Last attempt @ Thu Sep 25 15:04:09 2025 +05 was successful
               0 consecutive failure(s).
               Last success @ Thu Sep 25 15:04:09 2025 +05

DC=DomainDnsZones,DC=testdomain,DC=local
       Default-First-Site-Name\DC01 via RPC
               DSA object GUID: 92e9a947-d2a9-4b89-b90f-16a2148310fe
               Last attempt @ Thu Sep 25 15:04:29 2025 +05 was successful
               0 consecutive failure(s).
               Last success @ Thu Sep 25 15:04:29 2025 +05

==== OUTBOUND NEIGHBORS ====

DC=testdomain,DC=local
       Default-First-Site-Name\DC02 via RPC
               DSA object GUID: b211e5cd-d457-4210-ac87-6c25fa2859e2
               Last attempt @ Thu Sep 25 14:58:48 2025 +05 was successful
               0 consecutive failure(s).
               Last success @ Thu Sep 25 14:58:48 2025 +05

DC=testdomain,DC=local
       Default-First-Site-Name\DC01 via RPC
               DSA object GUID: 92e9a947-d2a9-4b89-b90f-16a2148310fe
               Last attempt @ Thu Sep 25 14:55:27 2025 +05 was successful
               0 consecutive failure(s).
               Last success @ Thu Sep 25 14:55:27 2025 +05

CN=Schema,CN=Configuration,DC=testdomain,DC=local
       Default-First-Site-Name\DC02 via RPC
               DSA object GUID: b211e5cd-d457-4210-ac87-6c25fa2859e2
               Last attempt @ Thu Sep 25 14:06:04 2025 +05 was successful
               0 consecutive failure(s).
               Last success @ Thu Sep 25 14:06:04 2025 +05

CN=Schema,CN=Configuration,DC=testdomain,DC=local
       Default-First-Site-Name\DC01 via RPC
               DSA object GUID: 92e9a947-d2a9-4b89-b90f-16a2148310fe
               Last attempt @ Thu Sep 25 14:06:04 2025 +05 was successful
               0 consecutive failure(s).
               Last success @ Thu Sep 25 14:06:04 2025 +05

CN=Configuration,DC=testdomain,DC=local
       Default-First-Site-Name\DC02 via RPC
               DSA object GUID: b211e5cd-d457-4210-ac87-6c25fa2859e2
               Last attempt @ Thu Sep 25 14:06:04 2025 +05 was successful
               0 consecutive failure(s).
               Last success @ Thu Sep 25 14:06:04 2025 +05

CN=Configuration,DC=testdomain,DC=local
       Default-First-Site-Name\DC01 via RPC
               DSA object GUID: 92e9a947-d2a9-4b89-b90f-16a2148310fe
               Last attempt @ Thu Sep 25 14:06:04 2025 +05 was successful
               0 consecutive failure(s).
               Last success @ Thu Sep 25 14:06:04 2025 +05

DC=ForestDnsZones,DC=testdomain,DC=local
       Default-First-Site-Name\DC02 via RPC
               DSA object GUID: b211e5cd-d457-4210-ac87-6c25fa2859e2
               Last attempt @ Thu Sep 25 14:24:05 2025 +05 was successful
               0 consecutive failure(s).
               Last success @ Thu Sep 25 14:24:05 2025 +05

DC=ForestDnsZones,DC=testdomain,DC=local
       Default-First-Site-Name\DC01 via RPC
               DSA object GUID: 92e9a947-d2a9-4b89-b90f-16a2148310fe
               Last attempt @ Thu Sep 25 14:24:05 2025 +05 was successful
               0 consecutive failure(s).
               Last success @ Thu Sep 25 14:24:05 2025 +05

DC=DomainDnsZones,DC=testdomain,DC=local
       Default-First-Site-Name\DC01 via RPC
               DSA object GUID: 92e9a947-d2a9-4b89-b90f-16a2148310fe
               Last attempt @ Thu Sep 25 15:04:13 2025 +05 was successful
               0 consecutive failure(s).
               Last success @ Thu Sep 25 15:04:13 2025 +05

DC=DomainDnsZones,DC=testdomain,DC=local
       Default-First-Site-Name\DC02 via RPC
               DSA object GUID: b211e5cd-d457-4210-ac87-6c25fa2859e2
               Last attempt @ Thu Sep 25 15:02:03 2025 +05 was successful
               0 consecutive failure(s).
               Last success @ Thu Sep 25 15:02:03 2025 +05

==== KCC CONNECTION OBJECTS ====

Connection --
       Connection name: e75c9a11-50c8-4318-8379-fcd72cf34cb6
       Enabled        : TRUE
       Server DNS name : DC01.testdomain.local
       Server DN name  : CN=NTDS Settings,CN=DC01,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,DC=testdomain,DC=local
               TransportType: RPC
               options: 0x00000001
Warning: No NC replicated for Connection!
Connection --
       Connection name: a264bbee-e454-4ab7-ab68-c1592eca228b
       Enabled        : TRUE
       Server DNS name : DC02.testdomain.local
       Server DN name  : CN=NTDS Settings,CN=DC02,CN=Servers,CN=Default-First-Site-Name,CN=Sites,CN=Configuration,DC=testdomain,DC=local
               TransportType: RPC
               options: 0x00000001
Warning: No NC replicated for Connection!

На Windows DC аналогично успешность репликации проверяем в CMD с помощью команды: repadmin /showrepl

Настройка репликации SYSVOL из Windows DC в сторону ALT Linux Samba DC

Создаем каталог для монтирования SYSVOL из любого DC01/DC02:

mkdir /mnt/sysvol

Настраиваем автоматическое монтирование по CIFS протоколу:

mkdir /etc/sysvol.fstab

# Наполняем сам файл:
cat /etc/sysvol.fstab
username=altlinux_sysvol
password=XXXXXXXXXXXXXXX

Прописываем монтирование в /etc/fstab:

//192.168.0.1/sysvol      /mnt/sysvol    cifs    credentials=/etc/sysvol.fstab,mfsymlinks,nounix     0        0

# монтируем:
systemctl daemon-reload
mount -a
df

Теперь создаем и тестируем скрипт, который будет реплицировать каталог /mnt/sysvol в /var/lib/samba/sysvol/ при этом восстанавливая ACL/ACE права на файлах.

[root@altdc ~]# cat /root/Scripts/sync-sysvol.sh
#!/bin/bash

# Настройка переменных
SRC_DIR="/mnt/sysvol/testdomain.local"
DEST_DIR="/var/lib/samba/sysvol/testdomain.local"

# 1) Проверка, что каталог смонтирован и не пустой
if [ ! -d "$SRC_DIR" ]; then
    echo "Ошибка: каталог $SRC_DIR не существует."
    exit 1
fi

# Проверка, что каталог содержит файлы/папки
if [ -z "$(ls -A "$SRC_DIR")" ]; then
    echo "Ошибка: каталог $SRC_DIR пустой. Проверьте монтирование."
    exit 1
fi

echo "Каталог $SRC_DIR доступен и не пустой. Продолжаем синхронизацию..."

# 2) Синхронизация с полной перезаписью
# Опция --delete удаляет файлы в DEST, которых нет в SRC
rsync -av --delete --copy-links --chmod=Du=rwx,Dg=rx,Do=rx,Fu=rw,Fg=r,Fo=r --exclude 'DfsrPrivate/' "$SRC_DIR/" "$DEST_DIR/"

if [ $? -ne 0 ]; then
    echo "Ошибка: синхронизация не удалась."
    exit 1
fi

echo "Синхронизация завершена успешно."

# 3) Исправление ACL для Samba SYSVOL
samba-tool ntacl sysvolreset -d 0

if [ $? -ne 0 ]; then
    echo "Ошибка: ntacl sysvolreset не выполнен."
    exit 1
fi

echo "ACL для SYSVOL успешно исправлены."

exit 0

Данный скрипт помещаем в /etc/crontab, например, 1 раз в час.

Полезные команды для проверки работы репликации

Ряд полезных команд для проверки и починки:

export KRB5CCNAME=FILE:/tmp/krb5cc_0
 
kdestroy
 
kinit Administrator@TESTDOMAIN.LOCAL

klist
 
samba-tool drs showrepl --use-kerberos=required
 
samba-tool drs showrepl DC01 --use-kerberos=required

samba-tool drs showrepl
 
samba-tool dbcheck --cross-ncs --fix --yes
 
samba-tool drs replicate ALTDC DC02 DC=testdomain,DC=local --full-sync -U synsol -d 5
 
samba-tool dbcheck --reset-well-known-acls --fix --yes
 
samba-tool ntacl sysvolcheck
 
samba-tool ntacl sysvolreset

PowerShell скрипт для детального и полного сравнения ACL/ACE на всех файлах в каталогах SYSVOL

Скрипт, если хочется детально проверить, нормально ли идет репликация прав ACL/ACE между SYSVOL каталогами из Windows DC в сторону ALT Linux Samba DC:

# Compare-GPO-ACL.ps1
# Сравнение ACL в SYSVOL между двумя контроллерами домена
# Совместим с Windows PowerShell 5.1
 
$Path1 = "\\altdc.testdomain.local\sysvol\testdomain.local\Policies"
$Path2 = "\\dc02.testdomain.local\SYSVOL\testdomain.local\Policies"
$ExportPath = "C:\Scripts\GPO_ACL_Differences_$(Get-Date -Format 'yyyyMMdd_HHmmss').csv"
 
# Функция: получение ACL с разрешением SID в читаемые имена
function Get-ResolvedAcl {
    param([string]$Path)
 
    $aclList = @()
    $items = Get-ChildItem -Path $Path -Recurse -Force -ErrorAction SilentlyContinue
 
    foreach ($item in $items) {
        try {
            $acl = Get-Acl -Path $item.FullName -ErrorAction Stop
            foreach ($ace in $acl.Access) {
                $identity = $ace.IdentityReference
                if ($identity -is [System.Security.Principal.SecurityIdentifier]) {
                    try {
                        $ntAccount = $identity.Translate([System.Security.Principal.NTAccount])
                        $resolvedName = $ntAccount.Value
                    } catch {
                        $resolvedName = $identity.Value
                    }
                } else {
                    $resolvedName = $identity.Value
                }
 
                $aclList += [PSCustomObject]@{
                    RelativePath         = $item.FullName.Substring($Path.Length).TrimStart('\')
                    Identity             = $resolvedName
                    FileSystemRights     = $ace.FileSystemRights
                    AccessControlType    = $ace.AccessControlType
                    InheritanceFlags     = $ace.InheritanceFlags
                    PropagationFlags     = $ace.PropagationFlags
                }
            }
        } catch {
            Write-Warning "Не удалось получить ACL для: $($item.FullName)"
        }
    }
    return $aclList
}
 
Write-Host "Сбор ACL с $Path1..." -ForegroundColor Cyan
$acl1 = Get-ResolvedAcl -Path $Path1
 
Write-Host "Сбор ACL с $Path2..." -ForegroundColor Cyan
$acl2 = Get-ResolvedAcl -Path $Path2
 
# Группировка по относительному пути
$hash1 = @{}
$hash2 = @{}

$acl1 | ForEach-Object {
    $key = $_.RelativePath
    if (-not $hash1.ContainsKey($key)) { $hash1[$key] = @() }
    $hash1[$key] += $_
}

$acl2 | ForEach-Object {
    $key = $_.RelativePath
    if (-not $hash2.ContainsKey($key)) { $hash2[$key] = @() }
    $hash2[$key] += $_
}
 
# Сравнение
$differences = @()
$allPaths = ($hash1.Keys + $hash2.Keys) | Sort-Object -Unique
 
foreach ($path in $allPaths) {
    $entries1 = if ($hash1.ContainsKey($path)) { $hash1[$path] } else { @() }
    $entries2 = if ($hash2.ContainsKey($path)) { $hash2[$path] } else { @() }
 
    # Преобразуем в строки для сравнения
    $str1 = $entries1 | ForEach-Object {
        "$($_.Identity)|$($_.FileSystemRights)|$($_.AccessControlType)|$($_.InheritanceFlags)|$($_.PropagationFlags)"
    } | Sort-Object
 
    $str2 = $entries2 | ForEach-Object {
        "$($_.Identity)|$($_.FileSystemRights)|$($_.AccessControlType)|$($_.InheritanceFlags)|$($_.PropagationFlags)"
    } | Sort-Object

    # Защита от $null
    $ref = if ($str1) { $str1 } else { @() }
    $diffObj = if ($str2) { $str2 } else { @() }
 
    $compareResult = Compare-Object -ReferenceObject $ref -DifferenceObject $diffObj
    if ($compareResult) {
        foreach ($item in $compareResult) {
            $side = if ($item.SideIndicator -eq "<=") { "OnlyOn_altdc" } else { "OnlyOn_dc02" }
            $parts = $item.InputObject -split '\|', 5
            $differences += [PSCustomObject]@{
                Path                 = $path
                Server               = $side
                Identity             = $parts[0]
                FileSystemRights     = $parts[1]
                AccessControlType    = $parts[2]
                InheritanceFlags     = $parts[3]
                PropagationFlags     = $parts[4]
            }
        }
    }
}
 
# Вывод в консоль
if ($differences.Count -eq 0) {
    Write-Host "✅ ACL идентичны на обоих серверах." -ForegroundColor Green
} else {
    Write-Host "⚠️  Найдено $($differences.Count) различий в ACL:" -ForegroundColor Red
    $differences | Format-Table -AutoSize
}
 
# Экспорт в CSV
if ($differences.Count -gt 0) {
    $differences | Export-Csv -Path $ExportPath -Encoding UTF8 -NoTypeInformation
    Write-Host "📄 Результат экспортирован в: $ExportPath" -ForegroundColor Yellow
} else {
    # Создаём пустой файл с пометкой "no differences"
    Set-Content -Path $ExportPath -Value "No ACL differences found between $Path1 and $Path2." -Encoding UTF8
    Write-Host "📄 Создан файл подтверждения: $ExportPath" -ForegroundColor Green
}
 
Write-Host "Завершено." -ForegroundColor Cyan