# Acces administrativ la un server de client prin Tailscale + SSH De ce: pentru instalări/migrări Oracle la client avem nevoie de **shell text** pe serverul lui. RustDesk nu ajută — e sesiune grafică, nu se poate automatiza. Iar la mulți clienți **nu se pot face forward-uri de porturi pe router**. Tailscale rezolvă exact asta: nodul face doar conexiuni de ieșire (UDP 41641 pentru NAT traversal, cu cădere pe releu DERP peste 443), deci merge și în spatele CGNAT, fără nicio regulă pe router. RustDesk rămâne util pentru **bootstrap-ul de o singură dată** — pașii de mai jos se execută manual, o dată, prin el. Primul caz aplicat: **VADECO** — `vadeco-server`, Windows Server 2019 Standard, Tailscale `100.93.100.75` (2026-08-25). Context conex: `acces-ssh-chei-angajati.md` (Bitvise pe chei, capcana LSA protection). --- ## 1. Tailscale pe serverul clientului 1. Instalezi Tailscale, te loghezi cu contul ROMFAST. 2. **Run unattended** — din tray → Preferences, sau `tailscale up --unattended`. Fără el, tailscaled pornește abia după ce cineva face login în Windows; pe un server la care nu se loghează nimeni, accesul e mort după fiecare reboot. 3. Cere acordul clientului înainte — e VPN pe serverul lui. ## 2. Izolarea nodului: tag + ACL Fără asta, serverul clientului intră în tailnet ca device obișnuit și **vede toată infrastructura ROMFAST**. Dacă e vreodată compromis, atacatorul sare mai departe. Modelul Tailscale, pe scurt: - ACL-ul e **default-deny**: ce nu e permis explicit, e blocat. Nu scrii interdicții. - Regulile au **direcție**: `src` = cine deschide conexiunea, `dst` = cine o primește. - Fiecare device are o **identitate**: fie contul care l-a logat (*user-owned*), fie **tag-ul**. Aplicarea unui tag **înlocuiește** proprietatea contului, nu se adaugă la ea. - `autogroup:member` = conturile umane din tailnet. Un device tagged **nu** e member. ### Politica Admin console → Access controls. UI-ul nou are editor vizual (Definitions / Grants); fișierul HuJSON brut e la `https://login.tailscale.com/admin/acls/file`. ```hujson { "tagOwners": { "tag:client": ["autogroup:admin"], }, "acls": [ // device-urile noastre (ne-tagged) ajung oriunde { "action": "accept", "src": ["autogroup:member"], "dst": ["*:*"] }, // NU exista nicio regula cu "src": ["tag:client"] // => serverul clientului nu poate initia nimic in tailnet ], } ``` > **Obligatoriu:** șterge regula implicită `src: ["*"]` → `dst: ["*:*"]`. Cât timp există, > `*` include și `tag:client` și toată izolarea e degeaba. > **Înainte de a șterge**, verifică în Machines că niciun nod ROMFAST nu e deja tagged — ar > rămâne fără acces. ### Aplicarea tag-ului Machines → nodul → `...` → **Edit ACL tags** → `tag:client`. Efecte: proprietatea trece la tag (dispare din „owned by you" — normal), iar **expirarea cheii se dezactivează automat** la device-urile tagged, deci nu mai trebuie dezactivată manual. Verificare rapidă în `tailscale status` — nodul apare cu owner `tagged-devices`: ``` 100.93.100.75 vadeco-server tagged-devices windows - ``` ### Testul de izolare Rulează **aceeași** comandă înainte și după aplicarea tag-ului, de pe serverul clientului: ```powershell Test-NetConnection 100.95.55.51 -Port 22 # 100.95.55.51 = LXC 171, are sshd pornit ``` - înainte de tag: `TcpTestSucceeded : True` (nodul e încă member) — confirmă că testul e valid - după tag: `TcpTestSucceeded : False` (~20s până expiră) — confirmă izolarea > **Nu folosi `tailscale ping` ca test de ACL.** Lucrează sub filtrul de pachete și poate > reuși chiar când ACL-ul blochează traficul real. Doar un test TCP pe un port concret spune > adevărul. Sensul invers (noi → client) se testează la punctul 4, cu serverul SSH pornit. > „Dacă nodul nu poate ajunge la noi, cum îmi răspunde SSH-ul?" — ACL-ul reglementează **cine > deschide** o conexiune, nu direcția octeților. Sesiunea deschisă dinspre noi funcționează > normal în ambele sensuri; clientul doar nu poate iniția el ceva spre tailnet. ## 3. Serverul SSH pe mașina clientului Două variante; ambele merg, alege după context. ### Bitvise SSH Server (consecvent cu restul clienților) Control Panel → **Easy settings**: - **Windows accounts** → `Administrator` (sau alt cont din grupul Administrators) → **Public keys** → Import cheia publică. Shell access: terminal + exec. - Conturile **virtuale** rămân pentru tuneluri (la VADECO: `romfast`, `vadeco`, s2c pe 1521/80). > **Capcana conturilor virtuale:** implicit sunt mapate pe contul Windows `bvssh_virtualusers`, > cu privilegii minime. Prin ele obții shell, dar `Get-Service`, `Get-CimInstance` și > `Get-PSDrive` întorc **gol** — nu erori, ci nimic — și nu se poate instala Oracle. Simptom: > `whoami` întoarce `\bvssh_virtualusers` și verificarea de admin dă `False`. > > Fie folosești un cont Windows real (mai simplu), fie mapezi contul virtual pe un cont admin > din Advanced settings → Access control → grup → **Windows account** + parolă, plus setarea > **Elevation** (fără ea, token filtrat de UAC și instalarea Oracle pică pe permisiuni obscure). > Dezavantaj: parola de admin ajunge stocată în configul Bitvise. > **Capcana LSA protection:** pe Windows recent (~2025+) cu Bitvise < 9.51, autentificarea cu > cheie pe **conturi Windows** eșuează (parola merge, cheia nu) — vezi > `acces-ssh-chei-angajati.md`. Pe Server 2019 nu se aplică. Conturile virtuale nu sunt afectate > niciodată. ### OpenSSH nativ Windows (alternativă, fără licențiere) ```powershell Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0 Set-Service -Name sshd -StartupType Automatic Start-Service sshd New-ItemProperty -Path "HKLM:\SOFTWARE\OpenSSH" -Name DefaultShell ` -Value "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe" ` -PropertyType String -Force $f = "$env:ProgramData\ssh\administrators_authorized_keys" Set-Content -Path $f -Encoding ascii -Value 'ssh-ed25519 AAAA... comentariu' icacls $f /inheritance:r /grant "*S-1-5-32-544:F" /grant "*S-1-5-18:F" Restart-Service sshd ``` - `administrators_authorized_keys` e fișierul corect pentru conturi **admin** (nu `~/.ssh`). - ACL-ul de la `icacls` e obligatoriu: cu moștenire de permisiuni, sshd ignoră fișierul **în tăcere** și vezi doar „Permission denied". SID-urile evită problema pe Windows localizat. - `-Encoding ascii` intenționat — `utf8` în PowerShell 5.1 scrie BOM, iar sshd nu digeră cheia. ### Firewall ```powershell Set-NetFirewallRule -Name 'OpenSSH-Server-In-TCP' -RemoteAddress 100.64.0.0/10 # Bitvise: Get-NetFirewallRule -DisplayName '*Bitvise*' | Set-NetFirewallRule -RemoteAddress 100.64.0.0/10 ``` Restricția se face **pe firewall**, nu prin bind pe adresa 100.x în configul serverului SSH: la boot, interfața Tailscale urcă adesea *după* serviciu, bind-ul eșuează și serverul rămâne mort. ## 4. Testul de acceptanță De pe orice device ROMFAST din tailnet: ```bash ssh Administrator@100.93.100.75 "powershell -c (Get-Item 'C:\').FullName" ``` Pentru comenzi mai complexe, ghilimelele se pierd prin lanțul ssh → Bitvise → PowerShell. Folosește `-EncodedCommand`: ```bash ENC=$(iconv -f UTF-8 -t UTF-16LE script.ps1 | base64 -w0) ssh Administrator@100.93.100.75 "powershell -NoProfile -EncodedCommand $ENC" ``` Output-ul PowerShell prin exec vine cu antet `#< CLIXML` și un bloc `` — se filtrează cu `grep -v`. ## 5. Verificare de mediu înainte de instalarea Oracle ```powershell "ADMIN = $(([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator))" "OS = $((Get-CimInstance Win32_OperatingSystem).Caption)" "RAM_GB = $([math]::Round((Get-CimInstance Win32_ComputerSystem).TotalPhysicalMemory/1GB,1))" Get-Service | Where-Object {$_.Name -like 'Oracle*'} | Select-Object Name,Status,StartType Get-PSDrive -PSProvider FileSystem | Select-Object Name,@{n='FreeGB';e={[math]::Round($_.Free/1GB,1)}} ``` `ADMIN = True` e condiția minimă — dacă e `False`, restul câmpurilor vin goale din lipsă de drepturi, nu pentru că lipsesc, și orice concluzie despre mașină e falsă. ## Revocarea accesului 1. Machines → nodul → **Remove** (îl scoate din tailnet complet); și/sau 2. ștergerea cheii publice din contul de pe serverul SSH. Pasul 1 e suficient și instantaneu — fără el, ștergerea cheii lasă nodul în rețea.