feat(oracle): kit de instalare la client + corectarea lipsurilor din instalare
Blocul de instalare/migrare Oracle 21c XE, terminat si validat pe VM 302. Kit de instalare (nou) scripts/build-client-kit.ps1 exporta CONTAFIN_ORACLE si FIRMANOUA de pe LXC 108 (PDB ROA2, nu ROA - ROA e productia ROA_CENTRAL), le aduce local prin cele trei hopuri container -> LXC -> host -> statie, le redenumeste la numele pe care le asteapta scripturile si le impacheteaza cu o copie a directorului roa-windows-setup. Citeste logul expdp si raporteaza cate firme are NOM_FIRME, ca sa nu plece din greseala datele unui client. roa-windows-setup/INSTALEAZA.cmd ruleaza pasii 01..08 fara "set /p", deci merge si prin SSH - RunAll.cmd nu poate fi rulat neinteractiv. Trateaza corect codul 5 de la pasul 03 si se opreste la prima eroare reala. Corectii 01-setup-database.ps1 nu mai scrie SQLNET.RECV_TIMEOUT / SEND_TIMEOUT in sqlnet.ora. Le hardcoda la 30 s, iar fisierul e citit si de impdp: in timpul unui import serverul poate lucra minute fara sa trimita un pachet, clientul murea cu ORA-12609 iar scriptul raporta esec pentru un import care se terminase cu bine pe server. Reprodus si reparat pe VM 302. 01-setup-database.ps1: Step 4c optional (-ResetSystemPassword) care curata EXPIRED(GRACE) pe SYSTEM in CDB root; ALTER PROFILE opreste expirarile viitoare dar nu reseteaza un cont deja intrat in gratie. uninstall-roa.sql: retry la DROP USER dupa KILL SESSION, plus un bloc final de verdict care numara ce a ramas si iese cu ORA-20900 daca baza nu e curata. Pana acum toate sectiunile prindeau exceptiile in WHEN OTHERS si scriptul tiparea "UNINSTALL COMPLETE" chiar si cand un user supravietuise, iar instalarea urmatoare dadea ORA-31684 in lant. 99-uninstall-roa.ps1 propaga codul de iesire. 08-post-install-config.ps1: Step 7b seteaza SMTP_OUT_SERVER si ACL-ul de retea pentru CONTAFIN_ORACLE. UTL_MAIL se instala si primea EXECUTE, adica destul cat sa compileze, dar nu si cat sa trimita. Privilegiul resolve nu accepta interval de porturi (ORA-24244), deci se acorda separat de connect. 07-verify-installation.ps1: sectiune noua care verifica prezenta lui FIRMANOUA.dmp in DMPDIR si o raporteaza ca eroare daca lipseste. Fara el, adaugarea unei firme noi pica in DBMS_DATAPUMP.ADD_FILE peste luni de la instalare, cand nimeni nu mai leaga eroarea de instalare. configure-profile.sql: antetul spune ca e unealta de remediere manuala, nu parte din flux; pas nou la final pentru CDB root. Documentatie README-ul roa-windows-setup descrie acum explicit cele doua scenarii - instalare pe curat si migrare - de unde se iau DMP-urile sablon, si capcana ORA-12609. Handoff-urile de sesiune au fost sterse; ce era durabil in ele a intrat in README-uri si in docs/diagnostic-spatiu-clienti.md. Validare pe VM 302: ciclu complet din kit, instalare pe curat, verificarea finala "[OK] All checks passed!". Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01SzF1hf4aFS1tmJWpPMiwGp
This commit is contained in:
199
docs/acces-client-tailscale-ssh.md
Normal file
199
docs/acces-client-tailscale-ssh.md
Normal file
@@ -0,0 +1,199 @@
|
||||
# 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 `<host>\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 `<Objs Version=...>` —
|
||||
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.
|
||||
Reference in New Issue
Block a user