Compare commits

..
1 Commits
Author SHA1 Message Date
alexrg c737bd3192 Add Linux Active Directory enrollment bootstrap 2026-09-07 09:42:24 -06:00
6 changed files with 365 additions and 4 deletions
+8
View File
@@ -50,6 +50,7 @@ Operational documentation:
- [Broker location, health, timeout, and recovery](docs/broker-operations.md) - [Broker location, health, timeout, and recovery](docs/broker-operations.md)
- [Windows domain join and remote-access onboarding](docs/windows-client-onboarding.md) - [Windows domain join and remote-access onboarding](docs/windows-client-onboarding.md)
- [Required Credential Provider client enrollment](docs/client-enrollment.md) - [Required Credential Provider client enrollment](docs/client-enrollment.md)
- [Linux client enrollment with realmd and SSSD](docs/linux-client-enrollment.md)
- [Domain monitoring, usage reports, and six-month retention](docs/monitoring.md) - [Domain monitoring, usage reports, and six-month retention](docs/monitoring.md)
- [Decision: do not persist password verifiers in Redis](docs/decisions/0001-no-password-cache.md) - [Decision: do not persist password verifiers in Redis](docs/decisions/0001-no-password-cache.md)
@@ -106,6 +107,13 @@ Start-SguServerBootstrap.cmd 192.168.50.10
Start-SguClientEnrollment.cmd 192.168.50.10 Start-SguClientEnrollment.cmd 192.168.50.10
``` ```
Linux clients are enrolled through their native PAM/SSSD stack instead of the
Windows Credential Provider:
```bash
sudo bash ./Enroll-SguLinuxDomainClient.sh --domain-controller 192.168.50.10
```
The server command creates a new forest and resumes by itself after its required The server command creates a new forest and resumes by itself after its required
restart. The client command registers a unique non-exportable mTLS certificate, restart. The client command registers a unique non-exportable mTLS certificate,
installs and validates SGU before domain join, then enables the managed remote installs and validates SGU before domain join, then enables the managed remote
+26 -2
View File
@@ -1,6 +1,6 @@
# Recuperación desde cero y alta en una sola ejecución # Recuperación desde cero y alta en una sola ejecución
Los releases entregan dos ZIP independientes. Cada uno contiene sus binarios, Los releases entregan tres ZIP independientes. Cada uno contiene sus binarios,
scripts, instalador offline requerido y un manifiesto SHA-256 interno. No contienen scripts, instalador offline requerido y un manifiesto SHA-256 interno. No contienen
contraseñas, claves privadas ni certificados reutilizables. contraseñas, claves privadas ni certificados reutilizables.
@@ -131,6 +131,30 @@ bosque modificar el dominio. Para la operación soportada, el script aplica una
transacción proveedor-primero y se niega a unir un equipo que no haya pasado las transacción proveedor-primero y se niega a unir un equipo que no haya pasado las
validaciones. validaciones.
## Cliente Linux nuevo
El ZIP `sgu-linux-client-bootstrap-VERSION.zip` usa el mecanismo nativo de
Linux: `realmd`, Kerberos, SSSD, NSS y PAM. No distribuye ni instala el
Credential Provider de Windows.
En una VM con Internet por `Default Switch` y una NIC privada conectada a
`Laboratorio AD`, ejecutar como administrador:
```bash
sudo bash ./Enroll-SguLinuxDomainClient.sh \
--domain-controller 192.168.50.10 \
--domain-interface eth0 \
--domain-address 192.168.50.12/24 \
--enable-ssh
```
La contraseña de la cuenta autorizada para la unión se solicita de forma
interactiva por `realmd`; no se incluye en la línea de comandos. El script
configura DNS de AD en la NIC privada, preserva la ruta de Internet, crea la
cuenta de equipo en `OU=Laboratorio`, habilita creación de directorio personal
mediante PAM y valida la cuenta de equipo con `adcli testjoin`. La documentación
de operación completa está en [linux-client-enrollment.md](linux-client-enrollment.md).
## Crear y publicar un release ## Crear y publicar un release
Desde el repositorio y con el SDK fijado en `global.json`: Desde el repositorio y con el SDK fijado en `global.json`:
@@ -150,4 +174,4 @@ la línea de comandos. Para empaquetar recursos institucionales adicionales:
-ServerContentPath C:\Preparacion\Packages -ServerContentPath C:\Preparacion\Packages
``` ```
`SHA256SUMS-VERSION.txt` permite comprobar ambos ZIP antes de usarlos. `SHA256SUMS-VERSION.txt` permite comprobar los tres ZIP antes de usarlos.
+78
View File
@@ -0,0 +1,78 @@
# Enrolamiento de clientes Linux
El enrolador Linux incorpora una estación Debian/Ubuntu o RHEL/Fedora/Rocky/AlmaLinux a `lci.lasalle.mx` mediante `realmd`, `adcli`, Kerberos y SSSD. No instala el Credential Provider de Windows: Linux conserva su propio inicio de sesión PAM/SSSD.
La contraseña de la cuenta autorizada para unir equipos se solicita directamente por `realmd`. Nunca se acepta como argumento, ni se escribe en archivos, registros o la línea de comandos.
## Requisitos de red
El equipo debe alcanzar por una interfaz privada al controlador de dominio, DNS y Kerberos. En el laboratorio:
| Servicio | Destino |
| --- | --- |
| Controlador y DNS | `192.168.50.10` |
| Dominio | `lci.lasalle.mx` |
| OU de equipos | `OU=Laboratorio,DC=lci,DC=lasalle,DC=mx` |
Para una VM Hyper-V con dos NIC, mantén el Internet en `Default Switch` y conecta una segunda NIC a `Laboratorio AD`. El enrolador puede configurar la segunda NIC sin modificar la ruta predeterminada:
```bash
sudo bash ./Enroll-SguLinuxDomainClient.sh \
--domain-controller 192.168.50.10 \
--domain-interface eth0 \
--domain-address 192.168.50.12/24 \
--enable-ssh
```
`--domain-interface` y `--domain-address` son opcionales como pareja. Si ya se aprovisionó la red privada mediante cloud-init, DHCP o gestión de configuración, omítelos y conserva únicamente `--domain-controller`.
El script se niega a reconfigurar una interfaz que posea la ruta predeterminada; así no deja a la máquina sin salida a Internet al agregar AD.
## Qué instala y configura
1. Instala `realmd`, `adcli`, SSSD, Kerberos y los módulos NSS/PAM adecuados para la familia de distribución.
2. Comprueba el registro DNS SRV de Active Directory y sincronización de hora ya existente.
3. Establece el nombre de host `NOMBRE.lci.lasalle.mx` antes de crear la cuenta de equipo.
4. Une el equipo con `adcli` en `OU=Laboratorio`.
5. Activa SSSD, creación de directorio personal mediante PAM y valida la contraseña de la cuenta de equipo con `adcli testjoin`.
6. Cuando se proporcionó la NIC privada, activa actualizaciones DNS dinámicas de SSSD en esa interfaz.
7. Con `--enable-ssh`, instala y habilita OpenSSH y abre únicamente el servicio SSH cuando el firewall local ya está activo.
El objeto de equipo aparece como `NOMBRE` en `OU=Laboratorio`. SSSD registra su registro A cuando la actualización DNS dinámica está activada.
## Inicio de sesión de dominio
Después de la unión, el formato explícito es:
```text
usuario@lci.lasalle.mx
```
La primera sesión crea `/home/usuario@lci.lasalle.mx`. El valor predeterminado de SSSD conserva credenciales para desconexiones breves de la red; las contraseñas no son administradas ni almacenadas por el Auth Broker.
Para limitar quién puede iniciar sesión, incluye un grupo de AD:
```bash
sudo bash ./Enroll-SguLinuxDomainClient.sh \
--domain-controller 192.168.50.10 \
--allow-group 'SG-Laboratorio-Linux-Users'
```
Ese modo ejecuta `realm deny --all` seguido de `realm permit --groups`; crea y administra el grupo antes de usarlo.
## Verificación y salida controlada
```bash
realm list
sudo adcli testjoin --domain=lci.lasalle.mx
getent passwd 'usuario@lci.lasalle.mx'
sudo sssctl domain-status lci.lasalle.mx
```
Para sacar un equipo del dominio de forma explícita:
```bash
sudo realm leave lci.lasalle.mx
```
Esta última acción elimina la relación de confianza local; debe ejecutarse sólo durante baja o reconstrucción del equipo.
+233
View File
@@ -0,0 +1,233 @@
#!/usr/bin/env bash
# Enroll-SguLinuxDomainClient.sh
#
# Idempotently joins a Debian/Ubuntu or RHEL-family Linux workstation to the
# SGU Active Directory laboratory. The join password is always requested by
# realmd; this script never accepts, logs, or stores it.
set -Eeuo pipefail
IFS=$'\n\t'
DOMAIN_NAME='lci.lasalle.mx'
DOMAIN_CONTROLLER=''
DOMAIN_DNS=''
COMPUTER_OU='OU=Laboratorio,DC=lci,DC=lasalle,DC=mx'
JOIN_USER='Administrator'
DOMAIN_INTERFACE=''
DOMAIN_ADDRESS=''
COMPUTER_NAME=''
ALLOW_GROUP=''
ENABLE_SSH=false
usage() {
cat <<'EOF'
Usage:
sudo ./Enroll-SguLinuxDomainClient.sh --domain-controller <IPv4-or-FQDN> [options]
Required:
--domain-controller VALUE Fixed IPv4 address or DNS name of the AD controller.
Options:
--domain-name VALUE AD DNS domain (default: lci.lasalle.mx).
--domain-dns VALUE DNS server for the AD network (default: domain controller).
--computer-ou DN Destination computer OU.
--join-user USER AD account permitted to join computers (default: Administrator).
--computer-name NAME NetBIOS host name; its FQDN becomes NAME.DOMAIN.
--domain-interface IFACE Private NIC connected to the AD network.
--domain-address CIDR Static IPv4 address for --domain-interface, e.g. 192.168.50.12/24.
--allow-group GROUP Restrict Linux sign-in to this AD group after joining.
--enable-ssh Install, enable, and (when active) permit OpenSSH in the local firewall.
--help Show this help.
Network safety:
--domain-interface and --domain-address must be supplied together. The selected
interface must not own the default route, so the command cannot replace the
Internet route while attaching a private AD NIC.
The AD password is requested interactively by realmd. It is never accepted as an
argument or written to a file, log, or command line.
EOF
}
fail() {
printf 'ERROR: %s\n' "$*" >&2
exit 1
}
need_command() {
command -v "$1" >/dev/null 2>&1 || fail "Required command is unavailable: $1"
}
while (($#)); do
case "$1" in
--domain-controller) DOMAIN_CONTROLLER=${2:?Missing value for --domain-controller}; shift 2 ;;
--domain-name) DOMAIN_NAME=${2:?Missing value for --domain-name}; shift 2 ;;
--domain-dns) DOMAIN_DNS=${2:?Missing value for --domain-dns}; shift 2 ;;
--computer-ou) COMPUTER_OU=${2:?Missing value for --computer-ou}; shift 2 ;;
--join-user) JOIN_USER=${2:?Missing value for --join-user}; shift 2 ;;
--computer-name) COMPUTER_NAME=${2:?Missing value for --computer-name}; shift 2 ;;
--domain-interface) DOMAIN_INTERFACE=${2:?Missing value for --domain-interface}; shift 2 ;;
--domain-address) DOMAIN_ADDRESS=${2:?Missing value for --domain-address}; shift 2 ;;
--allow-group) ALLOW_GROUP=${2:?Missing value for --allow-group}; shift 2 ;;
--enable-ssh) ENABLE_SSH=true; shift ;;
--help|-h) usage; exit 0 ;;
*) fail "Unknown argument: $1. Use --help for usage." ;;
esac
done
[[ ${EUID} -eq 0 ]] || fail 'Run this command with sudo or as root.'
[[ -n $DOMAIN_CONTROLLER ]] || fail '--domain-controller is required.'
if [[ -z $DOMAIN_DNS ]]; then
DOMAIN_DNS=$DOMAIN_CONTROLLER
fi
if [[ -n $DOMAIN_INTERFACE || -n $DOMAIN_ADDRESS ]]; then
[[ -n $DOMAIN_INTERFACE && -n $DOMAIN_ADDRESS ]] || \
fail '--domain-interface and --domain-address must be supplied together.'
fi
if [[ -z $COMPUTER_NAME ]]; then
COMPUTER_NAME=$(hostname -s)
fi
COMPUTER_NAME=${COMPUTER_NAME^^}
HOST_FQDN="${COMPUTER_NAME,,}.${DOMAIN_NAME,,}"
install_prerequisites() {
local -a packages=()
if command -v apt-get >/dev/null 2>&1; then
packages=(realmd sssd sssd-tools adcli libnss-sss libpam-sss krb5-user packagekit samba-common-bin)
if [[ $ENABLE_SSH == true ]]; then
packages+=(openssh-server)
fi
export DEBIAN_FRONTEND=noninteractive
apt-get update
apt-get install -y "${packages[@]}"
pam-auth-update --enable mkhomedir --force
return
fi
if command -v dnf >/dev/null 2>&1; then
packages=(realmd sssd sssd-tools adcli oddjob oddjob-mkhomedir samba-common-tools krb5-workstation)
if [[ $ENABLE_SSH == true ]]; then
packages+=(openssh-server)
fi
dnf install -y "${packages[@]}"
authselect select sssd with-mkhomedir --force
return
fi
fail 'Supported package managers are apt-get (Debian/Ubuntu) and dnf (RHEL/Fedora/Rocky/AlmaLinux).'
}
configure_private_ad_interface() {
[[ -n $DOMAIN_INTERFACE ]] || return
need_command nmcli
ip link show "$DOMAIN_INTERFACE" >/dev/null 2>&1 || \
fail "Network interface does not exist: $DOMAIN_INTERFACE"
local default_interface
default_interface=$(ip route show default | awk 'NR == 1 { print $5 }')
if [[ $default_interface == "$DOMAIN_INTERFACE" ]]; then
fail "Refusing to reconfigure $DOMAIN_INTERFACE because it owns the default route. Use the private AD NIC."
fi
local connection_name="SGU-Lab-AD-${DOMAIN_INTERFACE}"
if ! nmcli -t -f NAME connection show | grep -Fxq "$connection_name"; then
nmcli connection add type ethernet ifname "$DOMAIN_INTERFACE" con-name "$connection_name"
fi
nmcli connection modify "$connection_name" \
connection.autoconnect yes \
ipv4.method manual \
ipv4.addresses "$DOMAIN_ADDRESS" \
ipv4.dns "$DOMAIN_DNS" \
ipv4.dns-search "$DOMAIN_NAME" \
ipv4.never-default yes \
ipv6.method ignore
nmcli connection up "$connection_name"
}
enable_sssd_dyndns() {
[[ -n $DOMAIN_INTERFACE ]] || return
local configuration_directory='/etc/sssd/conf.d'
local configuration_path="${configuration_directory}/90-sgu-dyndns.conf"
local temporary_path
temporary_path=$(mktemp)
printf '%s\n' \
"[domain/${DOMAIN_NAME,,}]" \
"ad_hostname = ${HOST_FQDN}" \
'dyndns_update = True' \
'dyndns_update_ptr = True' \
"dyndns_iface = ${DOMAIN_INTERFACE}" \
'dyndns_refresh_interval = 43200' >"$temporary_path"
install -d -o root -g root -m 700 "$configuration_directory"
install -o root -g root -m 600 "$temporary_path" "$configuration_path"
rm -f "$temporary_path"
}
enable_ssh() {
[[ $ENABLE_SSH == true ]] || return
local service_name='sshd'
if systemctl list-unit-files ssh.service >/dev/null 2>&1; then
service_name='ssh'
fi
systemctl enable --now "$service_name"
if command -v ufw >/dev/null 2>&1 && ufw status | grep -q '^Status: active'; then
ufw allow OpenSSH
elif command -v firewall-cmd >/dev/null 2>&1 && systemctl is-active --quiet firewalld; then
firewall-cmd --permanent --add-service=ssh
firewall-cmd --reload
fi
}
verify_domain_connectivity() {
need_command getent
getent ahostsv4 "$DOMAIN_CONTROLLER" >/dev/null || \
fail "Could not resolve the domain controller: $DOMAIN_CONTROLLER"
if command -v resolvectl >/dev/null 2>&1; then
resolvectl query --type=SRV "_ldap._tcp.dc._msdcs.${DOMAIN_NAME}" >/dev/null || \
fail "AD DNS does not provide _ldap._tcp.dc._msdcs.${DOMAIN_NAME}."
fi
}
configure_private_ad_interface
install_prerequisites
verify_domain_connectivity
# Establish a canonical host name before adcli creates or refreshes the
# computer object, SPNs, and keytab entries.
hostnamectl set-hostname "$HOST_FQDN"
if realm list --name-only 2>/dev/null | grep -Fxqi "$DOMAIN_NAME"; then
printf 'Computer is already joined to %s; validating and refreshing configuration.\n' "$DOMAIN_NAME"
else
realm discover "$DOMAIN_NAME" >/dev/null
printf 'Joining %s. realmd will request the password for %s interactively.\n' "$DOMAIN_NAME" "$JOIN_USER"
realm join \
--membership-software=adcli \
--client-software=sssd \
--computer-ou="$COMPUTER_OU" \
--user="$JOIN_USER" \
"$DOMAIN_NAME"
fi
enable_sssd_dyndns
systemctl enable --now sssd
sssctl config-check
systemctl restart sssd
adcli update --domain="$DOMAIN_NAME" --host-fqdn="$HOST_FQDN" --computer-name="$COMPUTER_NAME"
adcli testjoin --domain="$DOMAIN_NAME"
if [[ -n $ALLOW_GROUP ]]; then
realm deny --all
realm permit --groups "$ALLOW_GROUP"
fi
enable_ssh
printf '\nLinux enrollment completed.\n'
printf ' Host: %s\n' "$HOST_FQDN"
printf ' Domain: %s\n' "$DOMAIN_NAME"
printf ' OU: %s\n' "$COMPUTER_OU"
printf ' Login format: %%U@%s\n' "$DOMAIN_NAME"
realm list
+18 -2
View File
@@ -80,15 +80,17 @@ if (-not $runtimeInstaller) {
New-Item -ItemType Directory -Path $resolvedOutputRoot -Force | Out-Null New-Item -ItemType Directory -Path $resolvedOutputRoot -Force | Out-Null
$clientRoot = Join-Path $resolvedOutputRoot "sgu-client-bootstrap-$Version" $clientRoot = Join-Path $resolvedOutputRoot "sgu-client-bootstrap-$Version"
$serverRoot = Join-Path $resolvedOutputRoot "sgu-server-bootstrap-$Version" $serverRoot = Join-Path $resolvedOutputRoot "sgu-server-bootstrap-$Version"
$linuxClientRoot = Join-Path $resolvedOutputRoot "sgu-linux-client-bootstrap-$Version"
$clientZip = "$clientRoot.zip" $clientZip = "$clientRoot.zip"
$serverZip = "$serverRoot.zip" $serverZip = "$serverRoot.zip"
foreach ($target in @($clientRoot,$serverRoot,$clientZip,$serverZip)) { $linuxClientZip = "$linuxClientRoot.zip"
foreach ($target in @($clientRoot,$serverRoot,$linuxClientRoot,$clientZip,$serverZip,$linuxClientZip)) {
if (Test-Path -LiteralPath $target) { if (Test-Path -LiteralPath $target) {
throw "Release target already exists: $target" throw "Release target already exists: $target"
} }
} }
New-Item -ItemType Directory -Path $clientRoot,$serverRoot -Force | Out-Null New-Item -ItemType Directory -Path $clientRoot,$serverRoot,$linuxClientRoot -Force | Out-Null
Copy-RequiredFile -Source (Join-Path $PSScriptRoot 'Invoke-SguClientBootstrap.ps1') ` Copy-RequiredFile -Source (Join-Path $PSScriptRoot 'Invoke-SguClientBootstrap.ps1') `
-Destination (Join-Path $clientRoot 'Invoke-SguClientBootstrap.ps1') -Destination (Join-Path $clientRoot 'Invoke-SguClientBootstrap.ps1')
@@ -120,6 +122,17 @@ Write-PackageManifest -PackageRoot $clientRoot -PackageVersion $Version -Package
Compress-Archive -Path (Join-Path $clientRoot '*') -DestinationPath $clientZip ` Compress-Archive -Path (Join-Path $clientRoot '*') -DestinationPath $clientZip `
-CompressionLevel Optimal -CompressionLevel Optimal
# Linux clients use their native PAM/SSSD sign-in stack rather than the Windows
# Credential Provider. Keep their self-contained bootstrap independent so a
# Linux administrator never receives Windows binaries or certificate material.
Copy-RequiredFile -Source (Join-Path $PSScriptRoot 'Enroll-SguLinuxDomainClient.sh') `
-Destination (Join-Path $linuxClientRoot 'Enroll-SguLinuxDomainClient.sh')
Copy-RequiredFile -Source (Join-Path $repositoryRoot 'docs\linux-client-enrollment.md') `
-Destination (Join-Path $linuxClientRoot 'README.md')
Write-PackageManifest -PackageRoot $linuxClientRoot -PackageVersion $Version -PackageKind LinuxClient
Compress-Archive -Path (Join-Path $linuxClientRoot '*') -DestinationPath $linuxClientZip `
-CompressionLevel Optimal
Copy-RequiredFile -Source (Join-Path $PSScriptRoot 'Initialize-SguDomainController.ps1') ` Copy-RequiredFile -Source (Join-Path $PSScriptRoot 'Initialize-SguDomainController.ps1') `
-Destination (Join-Path $serverRoot 'Initialize-SguDomainController.ps1') -Destination (Join-Path $serverRoot 'Initialize-SguDomainController.ps1')
Copy-RequiredFile -Source (Join-Path $PSScriptRoot 'Start-SguServerBootstrap.cmd') ` Copy-RequiredFile -Source (Join-Path $PSScriptRoot 'Start-SguServerBootstrap.cmd') `
@@ -161,6 +174,7 @@ Compress-Archive -Path (Join-Path $serverRoot '*') -DestinationPath $serverZip `
$checksums = @( $checksums = @(
("{0} {1}" -f (Get-FileHash -LiteralPath $clientZip -Algorithm SHA256).Hash, (Split-Path $clientZip -Leaf)) ("{0} {1}" -f (Get-FileHash -LiteralPath $clientZip -Algorithm SHA256).Hash, (Split-Path $clientZip -Leaf))
("{0} {1}" -f (Get-FileHash -LiteralPath $serverZip -Algorithm SHA256).Hash, (Split-Path $serverZip -Leaf)) ("{0} {1}" -f (Get-FileHash -LiteralPath $serverZip -Algorithm SHA256).Hash, (Split-Path $serverZip -Leaf))
("{0} {1}" -f (Get-FileHash -LiteralPath $linuxClientZip -Algorithm SHA256).Hash, (Split-Path $linuxClientZip -Leaf))
) )
$checksumsPath = Join-Path $resolvedOutputRoot "SHA256SUMS-$Version.txt" $checksumsPath = Join-Path $resolvedOutputRoot "SHA256SUMS-$Version.txt"
[IO.File]::WriteAllLines($checksumsPath, $checksums, [Text.UTF8Encoding]::new($false)) [IO.File]::WriteAllLines($checksumsPath, $checksums, [Text.UTF8Encoding]::new($false))
@@ -169,6 +183,8 @@ $checksumsPath = Join-Path $resolvedOutputRoot "SHA256SUMS-$Version.txt"
Version = $Version Version = $Version
ClientPackage = $clientZip ClientPackage = $clientZip
ClientSha256 = (Get-FileHash -LiteralPath $clientZip -Algorithm SHA256).Hash ClientSha256 = (Get-FileHash -LiteralPath $clientZip -Algorithm SHA256).Hash
LinuxClientPackage = $linuxClientZip
LinuxClientSha256 = (Get-FileHash -LiteralPath $linuxClientZip -Algorithm SHA256).Hash
ServerPackage = $serverZip ServerPackage = $serverZip
ServerSha256 = (Get-FileHash -LiteralPath $serverZip -Algorithm SHA256).Hash ServerSha256 = (Get-FileHash -LiteralPath $serverZip -Algorithm SHA256).Hash
Checksums = $checksumsPath Checksums = $checksumsPath
+2
View File
@@ -17,6 +17,7 @@ $tagName = "v$Version"
$assetPaths = @( $assetPaths = @(
(Join-Path $ReleaseDirectory "sgu-client-bootstrap-$Version.zip"), (Join-Path $ReleaseDirectory "sgu-client-bootstrap-$Version.zip"),
(Join-Path $ReleaseDirectory "sgu-server-bootstrap-$Version.zip"), (Join-Path $ReleaseDirectory "sgu-server-bootstrap-$Version.zip"),
(Join-Path $ReleaseDirectory "sgu-linux-client-bootstrap-$Version.zip"),
(Join-Path $ReleaseDirectory "SHA256SUMS-$Version.txt") (Join-Path $ReleaseDirectory "SHA256SUMS-$Version.txt")
) )
foreach ($assetPath in $assetPaths) { foreach ($assetPath in $assetPaths) {
@@ -100,6 +101,7 @@ Bootstrap reproducible para el laboratorio SGU.
- **Advertencia:** el bootstrap de servidor crea un bosque nuevo. No restaura los SID, contraseñas ni relaciones de confianza del bosque anterior; para conservarlos se requiere una recuperación de bosque desde una copia de estado del sistema. - **Advertencia:** el bootstrap de servidor crea un bosque nuevo. No restaura los SID, contraseñas ni relaciones de confianza del bosque anterior; para conservarlos se requiere una recuperación de bosque desde una copia de estado del sistema.
- `sgu-server-bootstrap-$Version.zip`: crea el bosque AD/DNS, OUs, grupo RDP, GPO, recurso `Packages`, broker mTLS y administración remota; se reanuda solo después del reinicio. - `sgu-server-bootstrap-$Version.zip`: crea el bosque AD/DNS, OUs, grupo RDP, GPO, recurso `Packages`, broker mTLS y administración remota; se reanuda solo después del reinicio.
- `sgu-client-bootstrap-$Version.zip`: registra un certificado mTLS único, instala y valida el Credential Provider antes de unir el equipo al dominio, habilita RDP/WinRM y se repara al arranque. - `sgu-client-bootstrap-$Version.zip`: registra un certificado mTLS único, instala y valida el Credential Provider antes de unir el equipo al dominio, habilita RDP/WinRM y se repara al arranque.
- `sgu-linux-client-bootstrap-$Version.zip`: une clientes Debian/Ubuntu o RHEL/Fedora/Rocky/AlmaLinux con realmd, Kerberos y SSSD. Solicita interactivamente la contraseña de unión y no instala el Credential Provider de Windows.
- El servidor configura WEF/WEC para registrar sesiones y fallos, inventariar el estado alcanzable de las máquinas cada cinco minutos y conservar durante 183 días tanto esos eventos como el diagnóstico estructurado del Auth Broker. - El servidor configura WEF/WEC para registrar sesiones y fallos, inventariar el estado alcanzable de las máquinas cada cinco minutos y conservar durante 183 días tanto esos eventos como el diagnóstico estructurado del Auth Broker.
- Windows Home se detecta y se rechaza con una explicación, ya que no admite unión a Active Directory ni RDP host. - Windows Home se detecta y se rechaza con una explicación, ya que no admite unión a Active Directory ni RDP host.