ActiveDirectory/MixedDomainController
Использование одновременно доменных контроллеров на 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