fix domain auth at login: DNS persistence via scheduled task
Nebula recreates the nebula1 TUN adapter on every start, wiping DNS settings. This caused domain authentication to fail at the Windows login screen because Netlogon could not reach the DC. Changes: - install-nebula.ps1 now takes -DnsServer and -Domain parameters - Changed service start type from delayed-auto to auto - Creates set-dns-on-start.ps1 startup script and NebulaDNS scheduled task - Sets ExpectedDialupDelay=60 in Netlogon registry - Idempotency check verifies scheduled task and startup script exist
This commit is contained in:
parent
08be15e31b
commit
57a53e1fde
10
CHANGELOG.md
10
CHANGELOG.md
@ -1,5 +1,15 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 1.1.0
|
||||||
|
|
||||||
|
DNS persistence and domain authentication at the login screen.
|
||||||
|
|
||||||
|
- `install-nebula.ps1` now requires `-DnsServer` and `-Domain` parameters
|
||||||
|
- Nebula service changed from `delayed-auto` to `auto` start — NlaSvc dependency already ensures the physical network is up
|
||||||
|
- Creates a `NebulaDNS` scheduled task that runs at startup to re-apply DNS on the `nebula1` adapter after Nebula recreates it, wait for the DC to become reachable, and force Netlogon DC rediscovery via `nltest`
|
||||||
|
- Sets `ExpectedDialupDelay` (60 seconds) in the Netlogon registry to give the tunnel time to establish before Netlogon gives up
|
||||||
|
- Idempotency check now also verifies the scheduled task and startup script exist
|
||||||
|
|
||||||
## 1.0.0
|
## 1.0.0
|
||||||
|
|
||||||
Initial release.
|
Initial release.
|
||||||
|
|||||||
25
README.md
25
README.md
@ -55,9 +55,9 @@ If you need to run steps individually:
|
|||||||
|
|
||||||
```powershell
|
```powershell
|
||||||
# 1. Install Nebula
|
# 1. Install Nebula
|
||||||
& "C:\path\to\nebula\install-nebula.ps1"
|
& "C:\path\to\nebula\install-nebula.ps1" -DnsServer 10.10.10.13 -Domain "arvandor.internal"
|
||||||
|
|
||||||
# 2. Point DNS at the domain controller
|
# 2. Point DNS at the domain controller (for the current session)
|
||||||
& "C:\path\to\nebula\set-dns.ps1" -DnsServer 10.10.10.13
|
& "C:\path\to\nebula\set-dns.ps1" -DnsServer 10.10.10.13
|
||||||
|
|
||||||
# 3. Join domain
|
# 3. Join domain
|
||||||
@ -66,6 +66,10 @@ If you need to run steps individually:
|
|||||||
|
|
||||||
### Parameters
|
### Parameters
|
||||||
|
|
||||||
|
**install-nebula.ps1**
|
||||||
|
- `-DnsServer` (required) — IP address of the domain controller. Used to configure DNS persistence across reboots.
|
||||||
|
- `-Domain` (required) — FQDN of the Active Directory domain. Used to configure Netlogon DC rediscovery at startup.
|
||||||
|
|
||||||
**set-dns.ps1**
|
**set-dns.ps1**
|
||||||
- `-DnsServer` (required) — IP address of the domain controller
|
- `-DnsServer` (required) — IP address of the domain controller
|
||||||
- `-InterfaceAlias` (optional) — Target a specific adapter. Defaults to `nebula1`
|
- `-InterfaceAlias` (optional) — Target a specific adapter. Defaults to `nebula1`
|
||||||
@ -90,14 +94,16 @@ If you need to run steps individually:
|
|||||||
|
|
||||||
All scripts are safe to re-run:
|
All scripts are safe to re-run:
|
||||||
|
|
||||||
- `install-nebula.ps1` — Skips reinstall if the service is already running with the correct version and matching files. Tears down and rebuilds if the version or files have changed.
|
- `install-nebula.ps1` — Skips reinstall if the service is already running with the correct version, matching files, and the `NebulaDNS` scheduled task exists. Tears down and rebuilds if the version or files have changed.
|
||||||
- `set-dns.ps1` — Overwrites the existing DNS setting on the Nebula adapter.
|
- `set-dns.ps1` — Overwrites the existing DNS setting on the Nebula adapter.
|
||||||
- `join-domain.ps1` — Skips the join if already on the domain.
|
- `join-domain.ps1` — Skips the join if already on the domain.
|
||||||
|
|
||||||
## Architecture
|
## Architecture
|
||||||
|
|
||||||
- **Nebula** provides the encrypted mesh network. It runs as a `LocalSystem` service with `delayed-auto` start, depending on `Tcpip` and `NlaSvc` (Network Location Awareness). This ensures the physical network is connected before Nebula attempts handshakes.
|
- **Nebula** provides the encrypted mesh network. It runs as a `LocalSystem` service with `auto` start, depending on `Tcpip` and `NlaSvc` (Network Location Awareness). This ensures the physical network is connected before Nebula attempts handshakes.
|
||||||
- **DNS** is configured only on the `nebula1` adapter. Physical adapters (Wi-Fi, Ethernet) keep their DHCP-assigned DNS so they can reach the internet and Nebula lighthouses independently.
|
- **DNS** is configured only on the `nebula1` adapter. Physical adapters (Wi-Fi, Ethernet) keep their DHCP-assigned DNS so they can reach the internet and Nebula lighthouses independently.
|
||||||
|
- **DNS persistence** — Nebula recreates the `nebula1` TUN adapter on every start, which wipes DNS settings. A `NebulaDNS` scheduled task runs at startup to re-apply DNS on the adapter, wait for the domain controller to become reachable, then force Netlogon to rediscover the DC via `nltest`. This ensures domain authentication works at the Windows login screen before any user logs in.
|
||||||
|
- **Netlogon tuning** — `ExpectedDialupDelay` (60 seconds) is set in the registry to give Netlogon additional time to locate the DC over the Nebula tunnel, which may involve relay handshakes.
|
||||||
- **Domain trust** flows through the Nebula tunnel. The domain controller is reachable at its Nebula IP, so machines do not need a VPN or physical proximity to the DC.
|
- **Domain trust** flows through the Nebula tunnel. The domain controller is reachable at its Nebula IP, so machines do not need a VPN or physical proximity to the DC.
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
@ -119,11 +125,11 @@ Common causes:
|
|||||||
- **"no config files found"** — The service was installed without `-config`. Reinstall using `install-nebula.ps1`.
|
- **"no config files found"** — The service was installed without `-config`. Reinstall using `install-nebula.ps1`.
|
||||||
|
|
||||||
### Handshake timeouts after reboot
|
### Handshake timeouts after reboot
|
||||||
Nebula started before the physical network was ready. Verify the service is configured with delayed start and NLA dependency:
|
Nebula started before the physical network was ready. Verify the service is configured with auto start and NLA dependency:
|
||||||
```powershell
|
```powershell
|
||||||
sc qc nebula
|
sc qc nebula
|
||||||
```
|
```
|
||||||
Expected: `START_TYPE: AUTO_START (DELAYED)` with `DEPENDENCIES: Tcpip, NlaSvc`. Re-run `install-nebula.ps1` to fix.
|
Expected: `START_TYPE: AUTO_START` with `DEPENDENCIES: Tcpip, NlaSvc`. Re-run `install-nebula.ps1` to fix.
|
||||||
|
|
||||||
### DNS resolution fails
|
### DNS resolution fails
|
||||||
Verify DNS is set on the Nebula adapter only:
|
Verify DNS is set on the Nebula adapter only:
|
||||||
@ -147,6 +153,13 @@ The Nebula tunnel must be established before Windows attempts domain authenticat
|
|||||||
1. Nebula service is running: `sc query nebula`
|
1. Nebula service is running: `sc query nebula`
|
||||||
2. Tunnel is active: `ping 10.10.10.13`
|
2. Tunnel is active: `ping 10.10.10.13`
|
||||||
3. DNS resolves: `nslookup arvandor.internal`
|
3. DNS resolves: `nslookup arvandor.internal`
|
||||||
|
4. NebulaDNS scheduled task exists: `Get-ScheduledTask -TaskName "NebulaDNS"`
|
||||||
|
5. Startup script exists: `Test-Path "C:\Program Files\Nebula\set-dns-on-start.ps1"`
|
||||||
|
|
||||||
|
If DNS is not set on `nebula1` after a reboot, the scheduled task may have failed. Check its last run result:
|
||||||
|
```powershell
|
||||||
|
Get-ScheduledTaskInfo -TaskName "NebulaDNS" | Select-Object LastRunTime, LastTaskResult
|
||||||
|
```
|
||||||
|
|
||||||
If the service is running but handshakes fail, check that the machine's Nebula certificate group has firewall access to the `ad` group.
|
If the service is running but handshakes fail, check that the machine's Nebula certificate group has firewall access to the `ad` group.
|
||||||
|
|
||||||
|
|||||||
@ -27,7 +27,7 @@ $ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Definition
|
|||||||
|
|
||||||
Write-Host ""
|
Write-Host ""
|
||||||
Write-Host "=== Step 1/3: Installing Nebula ==="
|
Write-Host "=== Step 1/3: Installing Nebula ==="
|
||||||
& "$ScriptDir\install-nebula.ps1"
|
& "$ScriptDir\install-nebula.ps1" -DnsServer $DnsServer -Domain $Domain
|
||||||
if ($LASTEXITCODE -ne 0) { exit 1 }
|
if ($LASTEXITCODE -ne 0) { exit 1 }
|
||||||
|
|
||||||
# --- Step 2: Set DNS ---
|
# --- Step 2: Set DNS ---
|
||||||
|
|||||||
@ -1,5 +1,13 @@
|
|||||||
#Requires -RunAsAdministrator
|
#Requires -RunAsAdministrator
|
||||||
|
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
[string]$DnsServer,
|
||||||
|
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
[string]$Domain
|
||||||
|
)
|
||||||
|
|
||||||
$ErrorActionPreference = "Stop"
|
$ErrorActionPreference = "Stop"
|
||||||
|
|
||||||
# --- Configuration ---
|
# --- Configuration ---
|
||||||
@ -18,10 +26,14 @@ if (-not $principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administra
|
|||||||
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Definition
|
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Definition
|
||||||
$InstallDir = "C:\Program Files\Nebula"
|
$InstallDir = "C:\Program Files\Nebula"
|
||||||
$ConfigPath = "$InstallDir\config.yml"
|
$ConfigPath = "$InstallDir\config.yml"
|
||||||
|
$StartupScript = "$InstallDir\set-dns-on-start.ps1"
|
||||||
$ExpectedBinPath = "`"$InstallDir\nebula.exe`" -service run -config `"$ConfigPath`""
|
$ExpectedBinPath = "`"$InstallDir\nebula.exe`" -service run -config `"$ConfigPath`""
|
||||||
$TempZip = Join-Path $env:TEMP "nebula-windows-amd64.zip"
|
$TempZip = Join-Path $env:TEMP "nebula-windows-amd64.zip"
|
||||||
$TempExtract = Join-Path $env:TEMP "nebula-extract"
|
$TempExtract = Join-Path $env:TEMP "nebula-extract"
|
||||||
|
|
||||||
|
# Derive the NetBIOS domain name from the FQDN (first label, uppercased)
|
||||||
|
$NetBIOSDomain = ($Domain -split '\.')[0].ToUpper()
|
||||||
|
|
||||||
# --- Validate per-host files before making any changes ---
|
# --- Validate per-host files before making any changes ---
|
||||||
|
|
||||||
$missing = @()
|
$missing = @()
|
||||||
@ -69,7 +81,11 @@ if ($existing) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($allMatch) {
|
# Also verify the scheduled task and startup script exist
|
||||||
|
$taskExists = Get-ScheduledTask -TaskName "NebulaDNS" -ErrorAction SilentlyContinue
|
||||||
|
$scriptExists = Test-Path $StartupScript
|
||||||
|
|
||||||
|
if ($allMatch -and $taskExists -and $scriptExists) {
|
||||||
Write-Host "Nebula $NebulaVersion is already installed and running with matching files. No changes needed."
|
Write-Host "Nebula $NebulaVersion is already installed and running with matching files. No changes needed."
|
||||||
exit 0
|
exit 0
|
||||||
}
|
}
|
||||||
@ -195,10 +211,10 @@ if ($LASTEXITCODE -ne 0) {
|
|||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
# Delayed start gives Wi-Fi/Ethernet time to fully associate and get an IP
|
# Auto start — the NlaSvc dependency ensures the physical network is up first
|
||||||
sc.exe config nebula start= delayed-auto | Out-Null
|
sc.exe config nebula start= auto | Out-Null
|
||||||
if ($LASTEXITCODE -ne 0) {
|
if ($LASTEXITCODE -ne 0) {
|
||||||
Write-Error "Failed to set delayed-auto start."
|
Write-Error "Failed to set auto start."
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -220,3 +236,62 @@ if ($svc.Status -eq "Running") {
|
|||||||
Write-Error "Nebula service failed to start. Check Event Viewer (Application log, source 'nebula')."
|
Write-Error "Nebula service failed to start. Check Event Viewer (Application log, source 'nebula')."
|
||||||
exit 1
|
exit 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# --- Configure DNS persistence across reboots ---
|
||||||
|
#
|
||||||
|
# Nebula recreates the nebula1 TUN adapter on every start, which wipes any
|
||||||
|
# DNS settings. This scheduled task runs at startup to re-apply DNS, wait
|
||||||
|
# for the domain controller to be reachable, then force Netlogon to
|
||||||
|
# rediscover the DC — ensuring domain authentication works at the login screen.
|
||||||
|
|
||||||
|
Write-Host "Creating startup DNS script..."
|
||||||
|
$startupScriptContent = @"
|
||||||
|
# Wait up to 120 seconds for the nebula1 adapter to appear
|
||||||
|
`$timeout = 120
|
||||||
|
while (`$timeout -gt 0) {
|
||||||
|
`$adapter = Get-NetAdapter -Name "nebula1" -ErrorAction SilentlyContinue
|
||||||
|
if (`$adapter -and `$adapter.Status -eq "Up") { break }
|
||||||
|
Start-Sleep -Seconds 2
|
||||||
|
`$timeout -= 2
|
||||||
|
}
|
||||||
|
if (`$timeout -le 0) { exit 1 }
|
||||||
|
Set-DnsClientServerAddress -InterfaceAlias "nebula1" -ServerAddresses "$DnsServer"
|
||||||
|
|
||||||
|
# Wait for DC to become reachable, then force Netlogon to rediscover
|
||||||
|
`$timeout = 180
|
||||||
|
while (`$timeout -gt 0) {
|
||||||
|
`$result = Resolve-DnsName "$Domain" -Server "$DnsServer" -ErrorAction SilentlyContinue
|
||||||
|
if (`$result) { break }
|
||||||
|
Start-Sleep -Seconds 5
|
||||||
|
`$timeout -= 5
|
||||||
|
}
|
||||||
|
if (`$timeout -gt 0) {
|
||||||
|
Clear-DnsClientCache
|
||||||
|
nltest /dsgetdc:$NetBIOSDomain /force 2>&1 | Out-Null
|
||||||
|
}
|
||||||
|
"@
|
||||||
|
Set-Content -Path $StartupScript -Value $startupScriptContent -Force
|
||||||
|
|
||||||
|
Write-Host "Registering NebulaDNS scheduled task..."
|
||||||
|
$existingTask = Get-ScheduledTask -TaskName "NebulaDNS" -ErrorAction SilentlyContinue
|
||||||
|
if ($existingTask) {
|
||||||
|
Unregister-ScheduledTask -TaskName "NebulaDNS" -Confirm:$false
|
||||||
|
}
|
||||||
|
|
||||||
|
$action = New-ScheduledTaskAction -Execute "powershell.exe" -Argument "-ExecutionPolicy Bypass -File `"$StartupScript`""
|
||||||
|
$trigger = New-ScheduledTaskTrigger -AtStartup
|
||||||
|
$principal = New-ScheduledTaskPrincipal -UserId "SYSTEM" -RunLevel Highest
|
||||||
|
$settings = New-ScheduledTaskSettingsSet -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries
|
||||||
|
Register-ScheduledTask -TaskName "NebulaDNS" -Action $action -Trigger $trigger -Principal $principal -Settings $settings -Description "Sets DNS on the Nebula adapter and forces Netlogon DC rediscovery" | Out-Null
|
||||||
|
|
||||||
|
Write-Host "NebulaDNS scheduled task registered."
|
||||||
|
|
||||||
|
# --- Configure Netlogon to wait for slow network links ---
|
||||||
|
#
|
||||||
|
# ExpectedDialupDelay tells Netlogon to keep retrying DC discovery for the
|
||||||
|
# specified number of seconds. This covers the window between Windows boot
|
||||||
|
# and the Nebula tunnel becoming fully operational.
|
||||||
|
|
||||||
|
$netlogonKey = "HKLM:\SYSTEM\CurrentControlSet\Services\Netlogon\Parameters"
|
||||||
|
Set-ItemProperty -Path $netlogonKey -Name "ExpectedDialupDelay" -Value 60 -Type DWord
|
||||||
|
Write-Host "Netlogon ExpectedDialupDelay set to 60 seconds."
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user