From 1b385cca7cbab9984a47b29ad023ec1b11770595 Mon Sep 17 00:00:00 2001 From: minguezsanzjuanjose Date: Sat, 3 Oct 2026 17:18:41 +0200 Subject: [PATCH] =?UTF-8?q?03-oct:=20superguardado=20autom=C3=A1tico?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG_INFRA.md | 9 ++ changelog_infra.json | 12 +++ docs/ACCESO_REMOTO_SOBREMESA.md | 74 +++++++++++++++ scripts/acceso_remoto/setup_ssh_server.ps1 | 104 +++++++++++++++++++++ scripts/acceso_remoto/setup_tailscale.ps1 | 60 ++++++++++++ 5 files changed, 259 insertions(+) create mode 100644 docs/ACCESO_REMOTO_SOBREMESA.md create mode 100644 scripts/acceso_remoto/setup_ssh_server.ps1 create mode 100644 scripts/acceso_remoto/setup_tailscale.ps1 diff --git a/CHANGELOG_INFRA.md b/CHANGELOG_INFRA.md index 474ce08..ccbe8e8 100644 --- a/CHANGELOG_INFRA.md +++ b/CHANGELOG_INFRA.md @@ -9,6 +9,7 @@ - **2026-10-02-superguardado-py-protocolo-guardado-total-automatico-portati** [scripts] superguardado.py: protocolo guardado total automatico portatil+sobremesa (aplicado en: portatil) - **2026-10-03-superwhisper-enter-ahk-f13-boton-auxiliar-logitech-tarea-pro** [scripts] SuperWhisper Enter: AHK F13 boton auxiliar Logitech + tarea programada (aplicado en: portatil) - **2026-10-03-monitor-de-estado-telegram-correo-jira-en-segundo-plano** [servicios] Monitor de estado (Telegram + correo + Jira) en segundo plano (aplicado en: portatil) +- **2026-10-03-acceso-remoto-al-sobremesa-openssh-server-tailscale-ssh-powe** [servicios] Acceso remoto al sobremesa: OpenSSH Server + Tailscale (ssh -> PowerShell) (aplicado en: portatil) ## Historial @@ -28,6 +29,14 @@ - **Aplicado en**: portatil - **Detalle**: Proceso Python (scripts/monitor_estado.py) que cada 30 min recoge Telegram (5 fuentes), correo jminguez@prolongo.es y Jira DS (nuevos + sin asignar), archiva por fuente, resume con IA (OmniRoute) y avisa por voz local. Arranque por tarea programada 'Monitor Estado' + plugin global monitor-estado-bootstrap.ts; watchdog idempotente; sesion Telegram dedicada (sessions/monitor, login por QR); tests pytest en tests/. Requiere en el otro equipo: pip install pytest qrcode, login Telegram QR y re-ejecutar instalar_global.ps1. +### 2026-10-03 · Acceso remoto al sobremesa: OpenSSH Server + Tailscale (ssh -> PowerShell) +- **id**: `2026-10-03-acceso-remoto-al-sobremesa-openssh-server-tailscale-ssh-powe` +- **Equipo**: portatil +- **Categoria**: servicios +- **Transferible**: si +- **Aplicado en**: portatil +- **Detalle**: Scripts en scripts/acceso_remoto/: setup_tailscale.ps1 (malla privada) y setup_ssh_server.ps1 (OpenSSH Server, shell PowerShell, firewall solo Tailscale+LAN, instala clave publica). Clave SSH del portatil: ~/.ssh/id_ed25519. Doc: docs/ACCESO_REMOTO_SOBREMESA.md. Permite ssh juanm@sobremesa desde cualquier red sin abrir puertos. Requiere en cada equipo: ejecutar setup_tailscale; en el sobremesa ademas setup_ssh_server (admin). + ### 2026-10-02 · superguardado.py: protocolo guardado total automatico portatil+sobremesa - **id**: `2026-10-02-superguardado-py-protocolo-guardado-total-automatico-portati` - **Equipo**: portatil diff --git a/changelog_infra.json b/changelog_infra.json index 53642c1..c48bcdd 100644 --- a/changelog_infra.json +++ b/changelog_infra.json @@ -237,6 +237,18 @@ "portatil" ], "detalle": "Proceso Python (scripts/monitor_estado.py) que cada 30 min recoge Telegram (5 fuentes), correo jminguez@prolongo.es y Jira DS (nuevos + sin asignar), archiva por fuente, resume con IA (OmniRoute) y avisa por voz local. Arranque por tarea programada 'Monitor Estado' + plugin global monitor-estado-bootstrap.ts; watchdog idempotente; sesion Telegram dedicada (sessions/monitor, login por QR); tests pytest en tests/. Requiere en el otro equipo: pip install pytest qrcode, login Telegram QR y re-ejecutar instalar_global.ps1." + }, + { + "id": "2026-10-03-acceso-remoto-al-sobremesa-openssh-server-tailscale-ssh-powe", + "fecha": "2026-10-03", + "equipo": "portatil", + "categoria": "servicios", + "titulo": "Acceso remoto al sobremesa: OpenSSH Server + Tailscale (ssh -> PowerShell)", + "transferible": true, + "aplicado_en": [ + "portatil" + ], + "detalle": "Scripts en scripts/acceso_remoto/: setup_tailscale.ps1 (malla privada) y setup_ssh_server.ps1 (OpenSSH Server, shell PowerShell, firewall solo Tailscale+LAN, instala clave publica). Clave SSH del portatil: ~/.ssh/id_ed25519. Doc: docs/ACCESO_REMOTO_SOBREMESA.md. Permite ssh juanm@sobremesa desde cualquier red sin abrir puertos. Requiere en cada equipo: ejecutar setup_tailscale; en el sobremesa ademas setup_ssh_server (admin)." } ] } diff --git a/docs/ACCESO_REMOTO_SOBREMESA.md b/docs/ACCESO_REMOTO_SOBREMESA.md new file mode 100644 index 0000000..e5a68a1 --- /dev/null +++ b/docs/ACCESO_REMOTO_SOBREMESA.md @@ -0,0 +1,74 @@ +# Acceso remoto al sobremesa (SSH → PowerShell) + Tailscale + +Fecha: 03-oct-2026. Complementa `SISTEMA_APAGADO_ENCENDIDO_REMOTO.md` (ese cubre *encender/apagar*; +esto cubre *entrar una vez encendido*). + +## Objetivo +Poder trabajar en el sobremesa desde el portátil (o el iPad) **esté donde esté el PC**, con acceso +directo a su **PowerShell** por SSH, sin abrir puertos en el router. + +## Arquitectura +``` +Portátil / iPad ──(Tailscale, red privada cifrada)──> SOBREMESA + └─ sshd (OpenSSH) → PowerShell +``` +- **Tailscale** pone ambos equipos en una malla privada (rango `100.64.0.0/10`), con nombres estables. +- **OpenSSH Server** en el sobremesa expone `sshd` (puerto 22), shell por defecto = PowerShell. +- El firewall del sobremesa solo acepta SSH desde Tailscale y LAN. + +El encendido sigue siendo por el flujo existente (Telegram → Home Assistant → regleta + Wake-on-LAN). +`sshd` arranca como **servicio** con Windows, así que en cuanto el PC tiene corriente y hace WoL, +SSH ya está disponible (no depende del autologon). + +## Puesta en marcha (una vez por equipo) + +### 1) Portátil (cliente) +- Instalar Tailscale y unirse: `scripts\acceso_remoto\setup_tailscale.ps1 -Hostname portatil` + (abre el navegador para autenticar; requiere admin para instalar). +- Clave SSH (ya creada en este portátil): `~/.ssh/id_ed25519`. + Pública: + ``` + ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIK7tk2+Vznv3zs+vjks64fwV+mznOQ7D+7Ct+vIBFJcz juanm@portatil + ``` + +### 2) Sobremesa (servidor) — ejecutar **como administrador** +```powershell +# 1. Tailscale +powershell -ExecutionPolicy Bypass -File scripts\acceso_remoto\setup_tailscale.ps1 -Hostname sobremesa + +# 2. OpenSSH Server + clave del portátil (auto-eleva) +powershell -ExecutionPolicy Bypass -File scripts\acceso_remoto\setup_ssh_server.ps1 ` + -PublicKey "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIK7tk2+Vznv3zs+vjks64fwV+mznOQ7D+7Ct+vIBFJcz juanm@portatil" +``` + +### 3) Probar desde el portátil +```powershell +ssh juanm@sobremesa # por nombre Tailscale +ssh juanm@100.x.y.z # o por IP Tailscale +``` + +## Uso diario +- `ssh juanm@sobremesa` → consola PowerShell remota. +- Comandos sueltos: `ssh juanm@sobremesa "Get-Process | Sort CPU -Desc | Select -First 5"`. +- Copiar ficheros: `scp fichero juanm@sobremesa:C:/Users/juanm/`. +- Desde el iPad: app **Tailscale** + cliente SSH (p. ej. Termius/Blink) con la misma clave. + +## Seguridad +- Contraseñas SSH deshabilitadas → **solo clave pública** (recomendado: `PasswordAuthentication no`). +- Firewall SSH restringido a `100.64.0.0/10` (Tailscale) y LAN; sin exposición a Internet. +- La tailnet se puede restringir por ACLs en el panel de Tailscale. +- La clave `id_ed25519` del portátil está **sin passphrase** por comodidad (los equipos ya tienen + autologon). Si se quiere endurecer: `ssh-keygen -p -f ~/.ssh/id_ed25519`. + +## Troubleshooting +- `ssh` no conecta: en el sobremesa `Get-Service sshd` (debe estar *Running*) y `Get-NetFirewallRule -DisplayName 'OpenSSH Server (sshd) - acceso remoto'`. +- No resuelve el nombre Tailscale: `tailscale status` en ambos; usar la IP `100.x.y.z`. +- ¿Autenticación rechazada? Revisar que la clave pública está en + `C:\ProgramData\ssh\administrators_authorized_keys` (si el usuario es admin) con ACLs correctas + (`SYSTEM` y `Administrators` a Full). +- Ver logs: `Get-Service sshd | Get-Content` o `C:\ProgramData\ssh\logs\sshd.log` (activando `LogLevel DEBUG3` si hace falta). + +## Relación con el arranque remoto +1. Telegram `/encender` → regleta + WoL → sobremesa arranca. +2. `sshd` y Tailscale arrancan solos con Windows. +3. Portátil: `ssh juanm@sobremesa` → PowerShell remoto. diff --git a/scripts/acceso_remoto/setup_ssh_server.ps1 b/scripts/acceso_remoto/setup_ssh_server.ps1 new file mode 100644 index 0000000..3464254 --- /dev/null +++ b/scripts/acceso_remoto/setup_ssh_server.ps1 @@ -0,0 +1,104 @@ +<# +.SYNOPSIS + Configura el acceso remoto por SSH (-> PowerShell) en un PC Windows. + +.DESCRIPTION + Idempotente. Deja listo el equipo para conectarse desde otro (p. ej. el portatil) + con `ssh usuario@equipo` y caer directamente en PowerShell. + + Hace: + 1. Instala la capacidad OpenSSH.Server (si falta). + 2. Pone y arranca los servicios sshd y ssh-agent (Automatico). + 3. Deja PowerShell como shell por defecto de SSH. + 4. Crea una regla de firewall para el puerto 22, restringida a Tailscale y LAN. + 5. Instala la clave publica recibida en authorized_keys (o administrators_authorized_keys). + + Requiere PowerShell ELEVADO (se auto-eleva si hace falta). + +.EXAMPLE + powershell -ExecutionPolicy Bypass -File setup_ssh_server.ps1 -PublicKey "ssh-ed25519 AAAA... juanm@portatil" +#> +[CmdletBinding()] +param( + [string]$PublicKey = '', + [string[]]$AllowedNetworks = @('100.64.0.0/10', '192.168.1.0/24', '192.168.50.0/24') +) + +$ErrorActionPreference = 'Stop' + +# --- Auto-elevacion ------------------------------------------------------- +$esAdmin = ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) +if (-not $esAdmin) { + Write-Host 'Requiere administrador. Reabriendo elevado...' -ForegroundColor Yellow + $argsList = @('-NoProfile', '-ExecutionPolicy', 'Bypass', '-File', "`"$PSCommandPath`"") + if ($PublicKey) { $argsList += @('-PublicKey', "`"$PublicKey`"") } + Start-Process powershell -Verb RunAs -ArgumentList $argsList + exit +} + +Write-Host '== Configurando OpenSSH Server (acceso remoto -> PowerShell) ==' -ForegroundColor Cyan + +# 1) Capacidad OpenSSH.Server ---------------------------------------------- +$cap = Get-WindowsCapability -Online -Name 'OpenSSH.Server*' | Select-Object -First 1 +if ($cap.State -ne 'Installed') { + Write-Host ' - Instalando OpenSSH.Server...' -ForegroundColor Yellow + Add-WindowsCapability -Online -Name $cap.Name | Out-Null +} +Write-Host ' - OpenSSH.Server instalado.' -ForegroundColor Green + +# 2) Servicios -------------------------------------------------------------- +foreach ($svc in @('sshd', 'ssh-agent')) { + if (Get-Service $svc -ErrorAction SilentlyContinue) { + Set-Service -Name $svc -StartupType Automatic + if ((Get-Service $svc).Status -ne 'Running') { Start-Service $svc } + Write-Host " - Servicio '$svc' -> Automatico y en marcha." -ForegroundColor Green + } +} + +# 3) Shell por defecto = PowerShell ---------------------------------------- +if (-not (Test-Path 'HKLM:\SOFTWARE\OpenSSH')) { New-Item -Path 'HKLM:\SOFTWARE\OpenSSH' -Force | Out-Null } +$pwsh = Join-Path $env:SystemRoot 'System32\WindowsPowerShell\v1.0\powershell.exe' +New-ItemProperty -Path 'HKLM:\SOFTWARE\OpenSSH' -Name 'DefaultShell' -Value $pwsh -PropertyType String -Force | Out-Null +Write-Host " - Shell por defecto: $pwsh" -ForegroundColor Green + +# 4) Firewall (solo Tailscale + LAN) --------------------------------------- +$ruleName = 'OpenSSH Server (sshd) - acceso remoto' +Get-NetFirewallRule -DisplayName $ruleName -ErrorAction SilentlyContinue | Remove-NetFirewallRule +New-NetFirewallRule -DisplayName $ruleName -Direction Inbound -Protocol TCP -Action Allow ` + -LocalPort 22 -RemoteAddress $AllowedNetworks -Profile Any | Out-Null +Write-Host " - Firewall: puerto 22 permitido desde $($AllowedNetworks -join ', ')." -ForegroundColor Green + +# 5) Clave publica ---------------------------------------------------------- +if ($PublicKey) { + $usuarioEsAdmin = $null -ne (Get-LocalGroupMember -Group (Get-LocalGroup -SID 'S-1-5-32-544').Name | + Where-Object { $_.Name -like "*\$env:USERNAME" }) + if ($usuarioEsAdmin) { + $keyFile = Join-Path $env:ProgramData 'ssh\administrators_authorized_keys' + $dir = Split-Path $keyFile + if (-not (Test-Path $dir)) { New-Item -ItemType Directory -Path $dir -Force | Out-Null } + } else { + $keyFile = Join-Path $env:USERPROFILE '.ssh\authorized_keys' + $dir = Split-Path $keyFile + if (-not (Test-Path $dir)) { New-Item -ItemType Directory -Path $dir -Force | Out-Null } + } + $contenido = if (Test-Path $keyFile) { Get-Content -LiteralPath $keyFile -ErrorAction SilentlyContinue } else { @() } + if ($contenido -notcontains $PublicKey.Trim()) { + Add-Content -LiteralPath $keyFile -Value $PublicKey.Trim() -Encoding ascii + Write-Host " - Clave publica anadida a $keyFile" -ForegroundColor Green + } else { + Write-Host " - La clave publica ya estaba en $keyFile" -ForegroundColor Green + } + if ($usuarioEsAdmin) { + icacls $keyFile /inheritance:r 2>$null | Out-Null + icacls $keyFile /grant 'SYSTEM:F' 'BUILTIN\Administradores:F' 'BUILTIN\Administrators:F' 2>$null | Out-Null + } + Restart-Service sshd + Write-Host ' - sshd reiniciado para aplicar la clave.' -ForegroundColor Green +} + +$ips = (Get-NetIPAddress -AddressFamily IPv4 | Where-Object { $_.IPAddress -notlike '127.*' }).IPAddress -join ', ' +Write-Host '' +Write-Host 'Listo. Datos de conexion:' -ForegroundColor Cyan +Write-Host " Usuario : $env:USERNAME" +Write-Host " IPs : $ips" +Write-Host " Prueba : ssh $env:USERNAME@" diff --git a/scripts/acceso_remoto/setup_tailscale.ps1 b/scripts/acceso_remoto/setup_tailscale.ps1 new file mode 100644 index 0000000..52b0d7b --- /dev/null +++ b/scripts/acceso_remoto/setup_tailscale.ps1 @@ -0,0 +1,60 @@ +<# +.SYNOPSIS + Instala y conecta Tailscale en un PC Windows (malla privada para acceso remoto). + +.DESCRIPTION + Idempotente. Tailscale une los equipos (sobremesa, portatil...) en una red privada + cifrada, sin abrir puertos en el router ni depender de la red local. + + Hace: + 1. Instala Tailscale via winget (si falta). + 2. Ejecuta `tailscale up --hostname ` (autenticacion en el navegador, una vez). + 3. Muestra estado y la IP de la tailnet. + + Ejecutar en CADA equipo que quiera usar la malla (sobremesa Y portatil). + +.EXAMPLE + powershell -ExecutionPolicy Bypass -File setup_tailscale.ps1 -Hostname sobremesa +#> +[CmdletBinding()] +param( + [string]$Hostname = $env:COMPUTERNAME.ToLower() +) + +$ErrorActionPreference = 'Continue' + +function Get-TailscaleExe { + $cmd = Get-Command tailscale -ErrorAction SilentlyContinue + if ($cmd) { return $cmd.Source } + foreach ($p in @("$env:ProgramFiles\Tailscale\tailscale.exe", "${env:ProgramFiles(x86)}\Tailscale\tailscale.exe")) { + if (Test-Path $p) { return $p } + } + return $null +} + +Write-Host '== Tailscale (malla privada para acceso remoto) ==' -ForegroundColor Cyan + +$ts = Get-TailscaleExe +if (-not $ts) { + Write-Host ' - Instalando Tailscale via winget...' -ForegroundColor Yellow + $wg = Get-Command winget -ErrorAction SilentlyContinue + if (-not $wg) { Write-Error 'winget no disponible. Instala Tailscale manualmente desde https://tailscale.com/download/windows'; exit 1 } + winget install --id Tailscale.Tailscale -e --accept-source-agreements --accept-package-agreements + Start-Sleep -Seconds 5 + $ts = Get-TailscaleExe + if (-not $ts) { Write-Error 'No se encuentra tailscale.exe tras la instalacion.'; exit 1 } +} +Write-Host " - tailscale: $ts" -ForegroundColor Green + +$svc = Get-Service -Name Tailscale -ErrorAction SilentlyContinue +if ($svc) { Set-Service -Name Tailscale -StartupType Automatic; if ($svc.Status -ne 'Running') { Start-Service Tailscale } } + +Write-Host " - Conectando a la tailnet como '$Hostname' (se abrira el navegador para autenticar)..." -ForegroundColor Yellow +& $ts up --hostname $Hostname + +Write-Host '' +Write-Host 'Estado:' -ForegroundColor Cyan +& $ts status +$ip = (& $ts ip -4 2>$null) -join ', ' +Write-Host "IP Tailscale : $ip" +Write-Host "Conexion : ssh $env:USERNAME@$Hostname (o a la IP Tailscale)"